Skip to content

API

Hosted flow

The verification UI the person completes: how to send them there, embed it, brand it and get them back.

The hosted flow lives at https://kycverify.me/verify/{token}. It runs in any modern phone or laptop browser and needs nothing installed. It shows your app's name, logo and primary colour, and walks the person through the steps the session's workflow enables.

Sending people to it

  • Recommended

    Full-page redirect

    Send the person to url; they return to callback_url with ?session_id&status.

  • Asynchronous

    Link by email or SMS

    Deliver url through your own channel; set contact.email to pre-fill the email step.

  • Built in

    Desktop to phone

    On a laptop the flow offers a QR code so the person continues on their phone camera.

  • Possible

    iframe

    Works with allow="camera", but the final redirect stays inside the frame. Rely on the webhook.

Four ways to put the hosted flow in front of a person.

Redirect and return

Redirect to url. When the session is final, the flow shows the result and, if the session has a callback_url (or the workflow a redirect_url), sends the person there after 5 seconds with two query parameters added:

text
https://app.example.com/kyc/done?session_id=ses_0k3v9x2m4a7qhd8f1rtb&status=approved

Desktop to phone

Opened on a laptop, the flow offers a QR code that opens the same session on a phone, where the camera is usually better. The person can also choose to continue on the current device.

In an iframe

html
<iframe
  src="https://kycverify.me/verify/q3Xf…"
  allow="camera; fullscreen"
  style="width: 100%; height: 720px; border: 0"
></iframe>

Camera access needs allow="camera". The final redirect navigates inside the frame, and the flow does not post messages to the parent, so drive your page from the webhook. The flow itself sets no frame-ancestors policy.

Branding

Each app has a primary_color (hex) and an optional logo_url, set in the console's app settings. The flow uses them for buttons, focus and the header. The app's name is shown in the consent text.

Step order

The order is fixed: consent → email → document → aadhaar → pan → liveness → review (submit). Disabled steps are skipped. Face match, AML, age and duplicate checks run in the background at submit.

Flow endpoints

The flow page calls a token-scoped API. You do not call it yourself, but it documents what is enforced:

MethodPathBody
GET/flow/{token}FlowState: steps, attempts, allowed documents, branding, redirect
POST/flow/{token}/consent{ accepted: true }
POST/flow/{token}/email/send{ email }: sends a 6-digit code
POST/flow/{token}/email/verify{ code }
POST/flow/{token}/documentmultipart document_type, country, front, back?
POST/flow/{token}/aadhaar/secure-qr{ qr_text } or multipart image
POST/flow/{token}/aadhaar/offline-xmlmultipart file (.zip), share_code
POST/flow/{token}/panmultipart pan, name?, image?
POST/flow/{token}/liveness/startissues challenge_id and challenges
POST/flow/{token}/livenessmultipart challenge_id, frames meta, frame_0..n
POST/flow/{token}/submitmoves the session to processing

Rules the server enforces

  • Every mutating call is refused with 409 conflict before consent, and once the session is processing, final or expired.
  • 60 requests per minute per token.
  • Uploads up to 10 MB each, identified by content (JPEG, PNG, WebP, ZIP) and encrypted with AES-256-GCM before they touch disk. Images over 8,192 pixels a side or 24 megapixels are refused before they are decoded.
  • Each step allows max_attempts tries (3 by default). A capture rejected for quality returns retry: true with the issues, so the person can retake it.
  • Email codes: 6 digits, valid 10 minutes, 5 tries per code, 5 sends per session.
  • Liveness challenges are single-use, expire after 5 minutes, and accept up to 16 frames.

Liveness challenges

  1. frame 0 · center

    baseline pose, size, embedding

  2. frame 1 · turn_left

    yaw left of the baseline

  3. frame 2 · smile

    mouth wider relative to eyes

  4. frame 3 · move_closer

    face larger than baseline

  • Issued order, single-use challenge id, 5 minutes
  • Same face in every frame (embedding vs centre)
  • One significant face per frame
  • Increasing timestamps, no duplicated frames
One liveness attempt: a centre frame, then a frame for each challenge in the issued order.

The vocabulary is turn_left, turn_right, smile and move_closer. The client captures one center frame, then frames for each challenge in the issued order, labelled with the challenge key and a millisecond timestamp, and uploads them un-mirrored.