Sessions
Create a verification session for each applicant, hand its URL to your frontend, and read the result.
A session is one applicant going through one workflow. Create it on your backend with a secret key; everything the frontend needs is in the response.
Create a session
// Your frontend calls this, then passes { clientToken, sessionUrl } to @okyc/web or @okyc/react.
app.post('/api/kyc/session', express.json(), async (req, res) => {
const userId = req.header('x-user-id') ?? 'demo-user'; // use your own auth here
try {
const session = await okyc.sessions.create(
{
workflowId: process.env.OKYC_WORKFLOW_ID,
referenceId: userId,
redirectUrl: process.env.REDIRECT_URL,
},
{ idempotencyKey: `kyc-${userId}-${new Date().toISOString().slice(0, 10)}` },
);
res.json({ clientToken: session.clientToken, sessionUrl: session.url });
} catch (e) {
res.status(e.statusCode ?? 500).json({ error: e.code ?? 'error' });
}
});| Field | Required | Notes |
|---|---|---|
workflow_id | yes | A published workflow. New sessions use its current version. |
reference_id | Your user's id (max 128 characters). Use it to find sessions and in webhooks. | |
country | Two-letter code; defaults to the workflow's country. | |
prefill | phone, email, full_name shown pre-filled to the applicant. | |
locale | Flow language, one of the workflow's languages (en, hi). | |
redirect_url | Where redirect mode returns (with ?session_id=&status=). Must be an allowed origin. | |
metadata | String key/value pairs (values up to 500 characters) returned with the session. | |
expires_in | Seconds, 300 to 2,592,000 (30 days). Default: the workflow's TTL (7 days). |
The full schema is in the API reference. Send an
Idempotency-Key so a retried request doesn't create a second session.
The response:
{
"id": "ses_…",
"status": "created",
"url": "https://verify.okyc.stream/s/ses_…#t=st_…",
"client_token": "st_…",
"expires_at": "2026-10-08T09:30:00.000Z"
}- Pass
urlto a mobile SDK, orclient_token+urlto@okyc/web/@okyc/react. - The client token is valid for 30 minutes, sliding while the applicant is active. To resume later, issue a new
one with
POST /v1/sessions/:id/client_token; the flow continues at the first unfinished step. - Don't log the
url: it carries the token.
Read the result
curl "https://api.okyc.stream/v1/sessions/ses_…?expand=checks,applicant" \
-H "Authorization: Bearer $OKYC_SECRET_KEY"status is the session's state (statuses); decision and decision_source (auto or
manual) say how it was decided. expand=checks adds every check with its result; expand=applicant (KYC) or
expand=business (KYB) adds the verified profile.
Fetch a session when a webhook arrives rather than polling.
List sessions
GET /v1/sessions?status=review&limit=50 returns a page (data, has_more). Pass the last id as
starting_after for the next page, or filter by reference_id. @okyc/node iterates every page for you:
for await (const s of okyc.sessions.list({ status: 'review' })).
Other actions
| Endpoint | Use |
|---|---|
POST /v1/sessions/:id/decision | Decide a session in review (approved, declined, resubmission_requested + reason_code). |
POST /v1/sessions/:id/cancel | Cancel an active session. |
POST /v1/sessions/:id/client_token | New client token to resume in the frontend. |
GET /v1/sessions/:id/evidence/:evidence_id | Short-lived URL for an evidence file (audited). |
DELETE /v1/sessions/:id/pii | Erase personal data (DPDP erasure); the decision skeleton is kept. |
Evidence files are served for download: images (JPEG, PNG, WebP) inline, everything else — PDFs, ZIPs — as an
attachment with Content-Type: application/octet-stream and a sandboxing Content-Security-Policy, so a
malicious document can never run in a browser. Every upload is virus-scanned before it is stored.
Direct checks (no hosted flow)
Run a single check server-to-server, for example to re-verify a PAN you already hold:
curl https://api.okyc.stream/v1/checks/in.pan.verify \
-H "Authorization: Bearer $OKYC_SECRET_KEY" -H "Content-Type: application/json" \
-d '{ "pan": "ABCPE1234F" }'Use a country key (in.pan.verify) or a generic key with country (tax_id.verify + "country": "IN").
?async=true returns 202 and sends check.completed when done. GET /v1/capabilities?country=IN lists
what a country supports.
10-minute quick start
Create a test session, complete it with sandbox values and receive the webhook.
Webhooks
Signed, retried event deliveries — the authoritative way to learn a session's decision.
© 2026 Aiistic Technologies Private Limited. OKYC is a product of Aiistic Technologies Private Limited. Privacy notice