ZKProva Integration Guide¶
API reference for credit union partners integrating ZKP-powered identity verification.
Base URL: https://api.zkprova.com/api/v1
Authentication¶
ZKProva uses two auth methods:
| Method | Header | Used by |
|---|---|---|
| JWT Bearer | Authorization: Bearer <token> |
Members (register/login flow) |
| API Key | X-API-Key: <key> |
Lenders (programmatic access) |
Register as a Lender¶
curl -X POST https://api.zkprova.com/api/v1/auth/lender/register \
-H "Content-Type: application/json" \
-d '{
"email": "integrations@lender.com",
"password": "securePassword123!",
"organization_name": "Acme Lending",
"verifier_type": "lender"
}'
Response includes a JWT token and an API key:
{
"access_token": "eyJhbGciOiJIUzI1NiIs...",
"token_type": "bearer",
"api_key": "zkp_live_abc123..."
}
Obtain a JWT (Login)¶
curl -X POST https://api.zkprova.com/api/v1/auth/lender/login \
-H "Content-Type: application/json" \
-d '{"email": "integrations@lender.com", "password": "securePassword123!"}'
Rotate API Key¶
curl -X POST https://api.zkprova.com/api/v1/auth/lender/rotate-key \
-H "Authorization: Bearer <jwt>"
Returns a new api_key. The previous key is immediately invalidated.
Lender Verification Flow¶
This is the primary integration path. A member presents a QR code; your system verifies it.
Step 1: Resolve QR Token¶
Extract the member's DID and bundled claims from a QR token.
curl:
curl -X POST https://api.zkprova.com/api/v1/verify/token \
-H "X-API-Key: zkp_live_abc123" \
-H "Content-Type: application/json" \
-d '{"token": "qr_abc123def456"}'
SDK:
const result = await client.resolveToken('qr_abc123def456');
console.log(result.member_did); // "did:key:z6Mk..."
console.log(result.claims); // [{claim_type: "income_range", threshold: 50000, ...}]
Response:
{
"member_did": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK",
"claims": [
{
"claim_type": "income_range",
"threshold": 50000,
"public_signals": ["1", "0"]
}
],
"token_valid": true
}
Step 2: Verify ZKP Proofs¶
Run full cryptographic verification — ZKP proof check, issuer auth, revocation status, holder binding.
curl:
curl -X POST https://api.zkprova.com/api/v1/verify/proof \
-H "X-API-Key: zkp_live_abc123" \
-H "Content-Type: application/json" \
-d '{"token": "qr_abc123def456"}'
SDK:
const proof = await client.verifyProof('qr_abc123def456');
if (proof.all_verified) {
console.log('All proofs valid');
console.log(proof.auto_fill); // Pre-fill your loan application
} else {
console.log(`Failed at step: ${proof.failed_step}`);
}
Response (success):
{
"member_did": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK",
"claims_verified": {"income_range": true, "membership_status": true},
"all_verified": true,
"verification_id": "550e8400-e29b-41d4-a716-446655440000",
"steps": [
{"step": "DECODE", "label": "Decode credential", "passed": true, "detail": "W3C VC decoded"},
{"step": "FRESHNESS", "label": "Check expiry", "passed": true, "detail": "Credential valid"},
{"step": "ISSUER_AUTH", "label": "Verify issuer", "passed": true, "detail": "Issuer signature valid"},
{"step": "ZKP_VERIFY", "label": "ZKP proof", "passed": true, "detail": "Groth16 proof verified"},
{"step": "REVOCATION", "label": "Revocation check", "passed": true, "detail": "Not revoked"},
{"step": "HOLDER_BINDING", "label": "Holder binding", "passed": true, "detail": "DID matches"}
],
"issuer_info": {
"did": "did:key:z6MkIssuer...",
"name": "Sample Credit Union",
"ncua_charter": "12345",
"trusted": true
},
"auto_fill": [
{"field": "income_range", "value": "Above $50,000", "claim_type": "income_range"},
{"field": "membership_status", "value": "Active member", "claim_type": "membership_status"}
]
}
Step 3: Check Trust Registry¶
Verify the issuing credit union is in the trust registry.
curl:
SDK:
const registry = await client.getTrustRegistry();
const issuer = registry.find(r => r.did === proof.issuer_info?.did);
console.log(issuer?.status); // "active"
Response:
[
{
"id": "550e8400-...",
"did": "did:key:z6MkIssuer...",
"name": "Sample Credit Union",
"ncua_charter": "12345",
"public_key_hex": "04abcdef...",
"status": "active",
"created_at": "2026-01-15T12:00:00"
}
]
Step 4: View Verification History¶
Retrieve past verifications for audit/compliance.
curl:
curl "https://api.zkprova.com/api/v1/verify/history?limit=20&offset=0" \
-H "X-API-Key: zkp_live_abc123"
SDK:
const history = await client.getVerificationHistory({ limit: 20, offset: 0 });
console.log(`Total verifications: ${history.items.length}`);
Response:
{
"items": [
{
"id": "550e8400-...",
"member_did": "did:key:z6Mk...",
"claims_verified": {"income_range": true},
"all_verified": true,
"issuer_info": {"did": "did:key:z6MkIssuer...", "name": "Sample CU", "ncua_charter": "12345", "trusted": true},
"verified_at": "2026-02-28T14:30:00"
}
],
"total": 142,
"limit": 20,
"offset": 0
}
Member Credential Flow¶
For credit union apps issuing credentials to their members.
1. Register¶
curl -X POST https://api.zkprova.com/api/v1/auth/member/register \
-H "Content-Type: application/json" \
-d '{
"email": "member@example.com",
"password": "securePassword123!",
"full_name": "Jane Doe"
}'
2. Verify Email¶
curl -X POST https://api.zkprova.com/api/v1/auth/email/verify \
-H "Content-Type: application/json" \
-d '{"code": "123456"}'
3. Issue Credential¶
curl -X POST https://api.zkprova.com/api/v1/credentials/issue \
-H "Authorization: Bearer <member_jwt>" \
-H "Content-Type: application/json" \
-d '{"claim_type": "income_range", "threshold": 50000}'
Supported claim_type values: income_range, credit_tier, account_age, membership_status, employment_verification, dti_ratio.
For async issuance (recommended for production), add ?async=true:
curl -X POST "https://api.zkprova.com/api/v1/credentials/issue?async=true" \
-H "Authorization: Bearer <member_jwt>" \
-H "Content-Type: application/json" \
-d '{"claim_type": "income_range", "threshold": 50000}'
Returns 202 Accepted with a job_id to poll:
curl https://api.zkprova.com/api/v1/credentials/issue/<job_id> \
-H "Authorization: Bearer <member_jwt>"
4. Generate QR Code¶
curl -X POST https://api.zkprova.com/api/v1/qr/generate \
-H "Authorization: Bearer <member_jwt>" \
-H "Content-Type: application/json" \
-d '{"credential_ids": ["<credential_id>"]}'
Returns a token that the member presents to a lender.
Two-Factor Authentication¶
Enable TOTP¶
Returns a totp_uri for authenticator apps and recovery_codes.
Verify Login with TOTP¶
If 2FA is enabled, login returns requires_2fa: true. Complete with:
curl -X POST https://api.zkprova.com/api/v1/auth/2fa/verify-login \
-H "Content-Type: application/json" \
-d '{"email": "user@example.com", "totp_code": "123456"}'
Webhook Setup¶
Receive real-time notifications for verification events. See Webhook Event Reference for full details.
Register a Webhook¶
curl -X POST https://api.zkprova.com/api/v1/webhooks \
-H "X-API-Key: zkp_live_abc123" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-app.com/webhooks/zkprova",
"events": ["verification.completed", "verification.failed", "credential.revoked"]
}'
Response includes a secret for signature verification.
Error Handling¶
HTTP Status Codes¶
| Code | Meaning |
|---|---|
| 200 | Success |
| 202 | Accepted (async job queued) |
| 400 | Bad request — invalid input or proof failure |
| 401 | Unauthorized — missing or invalid credentials |
| 404 | Resource not found |
| 429 | Rate limit or quota exceeded |
| 500 | Server error |
Error Response Format¶
Rate Limit Headers¶
Every response includes:
| Header | Description |
|---|---|
X-RateLimit-Limit |
Requests allowed in window |
X-RateLimit-Remaining |
Requests remaining |
X-RateLimit-Reset |
Seconds until window resets |
Retry-After |
Seconds to wait (on 429 only) |
See Rate Limits & Quotas for per-endpoint limits and plan tiers.
Retry Strategy¶
- 429 responses: Wait for
Retry-Afterseconds, then retry. - 5xx responses: Exponential backoff (1s, 2s, 4s), max 3 retries.
- The SDK handles retries automatically — configure with
retriesoption.