API Reference
Base URL: https://api.idova.id — resolves to the environment you're reading on. The production URL is issued when you go live.
All endpoints:
- Authenticate with
Authorization: Bearer idv_{test|live}_… - Accept both the internal ULID and the short public ID (e.g.
kyc_A5X7Q2P4NJ) in path parameters - Return JSON
- Support
Idempotency-Keyon POSTs
Applicants
Create an applicant
POST /v1/applicants
Body
{
"firstName": "Jane",
"lastName": "Smith",
"email": "jane@example.com",
"phone": "+14165551234",
"dob": "1990-06-15",
"country": "CA",
"externalRef": "customer-1234",
"metadata": { "source": "mobile-signup" }
}
Response 201
{
"id": "app_01KP47W4G6RBS3B5M8CHKE0EAM",
"publicId": "app_B8K2R9T4NM",
"firstName": "Jane",
"lastName": "Smith",
"email": "jane@example.com",
"phone": "+14165551234",
"dob": "1990-06-15",
"country": "CA",
"externalRef": "customer-1234",
"metadata": { "source": "mobile-signup" },
"status": "active",
"createdAt": "2026-04-15T12:00:00Z",
"updatedAt": "2026-04-15T12:00:00Z"
}
List applicants
GET /v1/applicants?page=0&size=20&includeArchived=false
Get an applicant
GET /v1/applicants/{id}
Update an applicant
PATCH /v1/applicants/{id}
Body (all fields optional — null = no change)
{ "email": "newemail@example.com", "phone": "+14165559999" }
KYC requests
Create a KYC request
POST /v1/kyc-requests
Provide exactly one of applicantId (for an existing applicant) or applicant (inline create).
Body
{
"applicant": {
"firstName": "Jane",
"lastName": "Smith",
"email": "jane@example.com",
"dob": "1990-06-15",
"country": "CA"
},
"environment": "sandbox",
"workflowType": "standard",
"callbackUrl": "https://yourapp.example.com/kyc-callback",
"redirectUrl": "https://yourapp.example.com/kyc-complete",
"externalRef": "onboarding-1234",
"metadata": { "channel": "mobile" }
}
Or with an existing applicant:
{ "applicantId": "app_B8K2R9T4NM", "environment": "sandbox" }
Response 201
{
"id": "kyc_01KP4FAA2YZ9Q4HCWRJK2FV7HG",
"publicId": "kyc_A5X7Q2P4NJ",
"applicantId": "app_01KP47W4G6RBS3B5M8CHKE0EAM",
"applicantPublicId": "app_B8K2R9T4NM",
"status": "link_generated",
"decision": "pending",
"environment": "sandbox",
"portalUrl": "https://idova.id/portal/abc123…",
"portalExpiresAt": "2026-04-17T12:00:00Z",
"createdAt": "2026-04-15T12:00:00Z"
}
List KYC requests
GET /v1/kyc-requests?page=0&size=20&status=awaiting_review
Get a KYC request
GET /v1/kyc-requests/{id}
Returns the full request DTO including automationDecision, automationConfidence, processingResult with signal breakdown + reasons.
Get events timeline
GET /v1/kyc-requests/{id}/events
Every lifecycle transition, append-only.
Get captured documents
GET /v1/kyc-requests/{id}/documents
Each document includes a pre-signed downloadUrl valid for 10 minutes.
Get captured selfies
GET /v1/kyc-requests/{id}/selfies
Get screening results
GET /v1/kyc-requests/{id}/screenings
AML screening outcomes (sanctions, PEP, adverse media) for the request.
Download report PDF
GET /v1/kyc-requests/{id}/report.pdf
Returns a complete A4 compliance report: applicant details, captured images with thumbnails embedded, screening results, signal breakdown, events timeline, reviewer notes.
Download report JSON
GET /v1/kyc-requests/{id}/report.json
Same content as the PDF, structured for programmatic consumption.
AML screening
Screen a person against sanctions, PEP, and adverse-media lists on its own — no document or
biometric verification. Use this when you need an AML check without a full identity flow. Each
check can optionally be enrolled in ongoing monitoring (re-screened daily; a new hit raises an
aml_check.monitoring_alert webhook).
Create an AML check
POST /v1/aml-checks
Synchronous — the response carries the verdict and the per-list results. Supports Idempotency-Key.
Body
{
"firstName": "Jane",
"lastName": "Smith",
"dob": "1990-06-15",
"country": "CA",
"monitoring": false,
"environment": "sandbox"
}
Only firstName and lastName are required; dob and country sharpen matching and reduce false
positives.
Response 201
{
"id": "aml_01KSGBGEA0YKNP8898XNDJEXMF",
"publicId": "aml_40AFMCDB33",
"environment": "sandbox",
"firstName": "Jane",
"lastName": "Smith",
"dob": "1990-06-15",
"country": "CA",
"status": "no_match",
"riskLevel": null,
"matchCount": 0,
"monitoringEnabled": false,
"lastScreenedAt": "2026-05-25T12:00:00Z",
"createdAt": "2026-05-25T12:00:00Z",
"results": [
{ "checkType": "sanctions", "provider": "opensanctions", "status": "clear", "riskLevel": "low", "matchCount": 0, "matches": [] },
{ "checkType": "pep", "provider": "opensanctions", "status": "clear", "riskLevel": "low", "matchCount": 0, "matches": [] },
{ "checkType": "adverse_media", "provider": "brave-llm", "status": "clear", "riskLevel": "low", "matchCount": 0, "matches": [] }
]
}
Job status (rolled up from the three checks):
| Status | Meaning |
|---|---|
no_match | every list came back clear |
potential_match | at least one list returned a hit — review the results[].matches |
failed | a provider errored (fail-closed — not a clean pass); retry |
Get an AML check
GET /v1/aml-checks/{id}
Returns the check including the per-list results and their matches.
List AML checks
GET /v1/aml-checks?page=0&size=10&status=potential_match
status filter is optional.
Download AML report PDF
GET /v1/aml-checks/{id}/report.pdf
A compliance PDF of the check — subject, verdict, per-list results + match records, and monitoring
history. The JSON equivalent is just GET /v1/aml-checks/{id}.
Rate limits
See Authentication → Rate limits.
OpenAPI
Auto-generated OpenAPI specification:
GET /v3/api-docs
Interactive Swagger UI (dev only):
/swagger-ui/index.html
