API Documentation

Everything you need to integrate Provefy identity verification into your platform.

Overview

Provefy provides identity verification through a simple REST API. The typical flow is:

1. Your backend creates a verification session via the API, specifying which checks to run.
2. You redirect your user to the hosted verification page (or embed it in an iframe).
3. The user completes the checks (selfie, ID upload, etc.).
4. Provefy sends the results to your webhook URL and you can also poll the API.

Authentication

All API requests require an API key in the Authorization header.

Authorization: Bearer kyc_live_aBcDeFgHiJkLmNoPqRsTuVwXyZ...

API keys are created in the admin dashboard. Each key has its own feature toggles, thresholds, rate limits, and branding. Keys are shown once at creation — store them securely.

Important: Keep your API key on your server only. Never expose it in client-side code, mobile apps, or browser requests.

Base URL

https://api.provefy.xyz/api/v1

Create Verification Session

POST /verify

Creates a new verification session and returns a URL where your user can complete the verification.

Request Body

FieldTypeRequiredDescription
externalRefstringNoYour internal reference ID (user ID, order ID, etc.)
checksstring[]NoOverride checks to run. If omitted, uses the API key's enabled features.
redirectUrlstringNoURL to redirect user after verification completes.
callbackUrlstringNoWebhook URL for this specific session (overrides key-level webhook).
metadataobjectNoArbitrary JSON stored with the session, returned in webhooks.

Available check types: liveness, age_estimation, doc_verify, face_match

Example

curl -X POST https://api.provefy.xyz/api/v1/verify \
  -H "Authorization: Bearer kyc_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "externalRef": "user_12345",
    "checks": ["liveness", "doc_verify", "face_match"],
    "redirectUrl": "https://yourapp.com/verification-done",
    "metadata": { "plan": "premium" }
  }'

Response

{
  "sessionId": "f4a9644f-0c9f-4aab-a879-...",
  "verificationUrl": "https://verify.provefy.xyz/verify/aBcDeFgHi...",
  "expiresAt": "2025-03-07T12:30:00.000Z",
  "requestedChecks": ["liveness", "doc_verify", "face_match"]
}
Redirect your user to verificationUrl. They'll see a branded verification flow and complete all checks. Sessions expire in 30 minutes by default.

Get Session Status

GET /verify/:sessionId

Returns the current status and results of a verification session.

curl https://api.provefy.xyz/api/v1/verify/f4a9644f-... \
  -H "Authorization: Bearer kyc_live_..."

Response

{
  "id": "f4a9644f-...",
  "externalRef": "user_12345",
  "status": "COMPLETED",
  "overallResult": "APPROVED",
  "checks": {
    "liveness": { "status": "COMPLETED", "result": "PASS", "livenessScore": 0.97 },
    "documentVerification": { "status": "COMPLETED", "result": "PASS", "documentType": "DRIVERS_LICENSE" },
    "faceMatch": { "status": "COMPLETED", "result": "PASS", "similarityScore": 0.82, "isMatch": true }
  },
  "metadata": { "plan": "premium" }
}

Session Statuses

StatusDescription
PENDINGSession created, user hasn't started
IN_PROGRESSUser has started the verification flow
COMPLETEDAll checks finished
EXPIREDSession timed out (default: 30 minutes)
CANCELLEDCancelled via API

Overall Results

ResultDescription
APPROVEDAll checks passed
REJECTEDOne or more checks failed
REVIEWBorderline results — needs manual review in the admin dashboard

List Sessions

GET /verify?status=COMPLETED&page=1&limit=20

Returns a paginated list of your sessions. Filter by status, externalRef.

Cancel Session

POST /verify/:sessionId/cancel

Cancels an active session. Only works on PENDING or IN_PROGRESS sessions.

Liveness Detection

Verifies the user is a real person (not a photo, video, or mask). Uses the MiniFASNet anti-spoofing model.

SettingDefaultDescription
Liveness threshold0.85Minimum score to pass (0-1). Lower = more permissive.

The user is guided through challenges: look straight, blink, turn head. Frames are captured automatically and analyzed server-side.

Age Estimation

Estimates the user's age from a selfie using the InsightFace GenderAge model. Accuracy is typically ±3 years.

SettingDefaultDescription
Minimum age18Required age. Users estimated 3+ years above pass; 2+ below fail; borderline → REVIEW.

Document OCR

Extracts text from ID documents using Tesseract OCR with MRZ (Machine Readable Zone) parsing for passports.

Supported documents: Passports, driver's licenses, national ID cards, residence permits.
Extracted fields: First name, last name, date of birth, document number, expiry date, gender, nationality.
Supported countries: US, BR, GB, AR, CO, MX, PT, and any document with MRZ.

Face Matching

Compares a selfie to a document photo using ArcFace embeddings (InsightFace W600K R50). Returns a cosine similarity score.

SettingDefaultDescription
Face match threshold0.57Minimum similarity to pass (0-1). Default is tuned for selfie-vs-document comparison where lighting, angle, and age differences are expected.

Hosted Verification Flow

The simplest integration: redirect your user to the verificationUrl returned when you create a session.

// In your backend, after creating a session:
res.redirect(session.verificationUrl);

// Or in your frontend:
window.location.href = session.verificationUrl;

The verification page is fully responsive, works on mobile, and automatically detects the user's language (English or Portuguese).

After completion, the user is redirected to your redirectUrl with query params:

https://yourapp.com/done?session_id=f4a9644f-...&result=APPROVED

Webhooks

When a verification session completes, Provefy sends a POST request to your webhook URL.

Setup

Set the webhook URL when creating an API key in the admin dashboard. You'll receive a webhook secret — use it to verify signatures.

Payload

{
  "event": "verification.completed",
  "sessionId": "f4a9644f-...",
  "externalRef": "user_12345",
  "overallResult": "APPROVED",
  "completedAt": "2025-03-07T12:35:00.000Z",
  "checks": {
    "liveness": { "result": "PASS", "livenessScore": 0.97 },
    "ageEstimation": { "result": "PASS", "estimatedAge": 28, "meetsMinAge": true },
    "documentVerification": { "result": "PASS", "documentType": "DRIVERS_LICENSE", "ocrConfidence": 0.85 },
    "faceMatch": { "result": "PASS", "similarityScore": 0.82, "isMatch": true }
  },
  "metadata": { "plan": "premium" }
}

Signature Verification

Webhook requests include an X-KYC-Signature header containing an HMAC-SHA256 signature of the request body using your webhook secret.

// Node.js example
const crypto = require('crypto');

function verifyWebhook(body, signature, secret) {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(body)
    .digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expected)
  );
}

// In your webhook handler:
app.post('/webhook/kyc', (req, res) => {
  const sig = req.headers['x-kyc-signature'];
  if (!verifyWebhook(JSON.stringify(req.body), sig, WEBHOOK_SECRET)) {
    return res.status(401).json({ error: 'Invalid signature' });
  }

  const { sessionId, overallResult, externalRef } = req.body;

  if (overallResult === 'APPROVED') {
    // Mark user as verified in your database
  } else if (overallResult === 'REVIEW') {
    // Flag for manual review
  } else {
    // Handle rejection
  }

  res.status(200).json({ received: true });
});
Retry policy: If your webhook endpoint returns a non-2xx status, Provefy retries once after 60 seconds. Maximum 3 attempts.

iFrame Embedding

You can embed the verification flow directly in your page instead of redirecting.

<!-- Embed the verification flow -->
<iframe
  src="https://verify.provefy.xyz/verify/SESSION_TOKEN"
  allow="camera; microphone"
  style="width: 100%; height: 700px; border: none;"
></iframe>

<!-- Listen for completion -->
<script>
window.addEventListener('message', (event) => {
  if (event.data?.type === 'provefy:complete') {
    console.log('Result:', event.data.data.overallResult);
    // 'APPROVED', 'REJECTED', or 'REVIEW'
  }
});
</script>
Important: The allow="camera" attribute is required for liveness checks to access the user's camera from within the iframe.

Error Codes

StatusMeaning
400Bad request — missing required fields or invalid data
401Invalid or missing API key
403Feature not enabled for this API key
404Session not found
429Rate limit exceeded
500Internal server error

All errors return JSON: { "error": "Human-readable message" }

Rate Limits

Each API key has a configurable rate limit (default: 100 requests/minute). The limit applies to all endpoints combined. Headers are included in responses:

X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1709812800

Security

Encryption at rest: All PII fields (names, document numbers) are encrypted with AES-256-GCM before storage.

Encryption in transit: All API traffic is over HTTPS with TLS 1.2+ and HSTS.

Secure processing: All biometric processing (face detection, liveness, age estimation, OCR, face matching) is handled securely. No biometric data is shared with third parties.

Session expiry: Verification sessions expire after 30 minutes. Completed session data is retained per your configuration.