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.
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
| Field | Type | Required | Description |
|---|---|---|---|
externalRef | string | No | Your internal reference ID (user ID, order ID, etc.) |
checks | string[] | No | Override checks to run. If omitted, uses the API key's enabled features. |
redirectUrl | string | No | URL to redirect user after verification completes. |
callbackUrl | string | No | Webhook URL for this specific session (overrides key-level webhook). |
metadata | object | No | Arbitrary 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"]
}
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
| Status | Description |
|---|---|
PENDING | Session created, user hasn't started |
IN_PROGRESS | User has started the verification flow |
COMPLETED | All checks finished |
EXPIRED | Session timed out (default: 30 minutes) |
CANCELLED | Cancelled via API |
Overall Results
| Result | Description |
|---|---|
APPROVED | All checks passed |
REJECTED | One or more checks failed |
REVIEW | Borderline 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.
| Setting | Default | Description |
|---|---|---|
| Liveness threshold | 0.85 | Minimum 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.
| Setting | Default | Description |
|---|---|---|
| Minimum age | 18 | Required 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.
| Setting | Default | Description |
|---|---|---|
| Face match threshold | 0.57 | Minimum 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 });
});
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>
allow="camera" attribute is required for liveness checks to access the user's camera from within the iframe.Error Codes
| Status | Meaning |
|---|---|
400 | Bad request — missing required fields or invalid data |
401 | Invalid or missing API key |
403 | Feature not enabled for this API key |
404 | Session not found |
429 | Rate limit exceeded |
500 | Internal 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.