@okyc/node
The server SDK for Node 18+, Bun, Deno and edge runtimes — typed, retried, never logs bodies.
Version0.1.1
Install
npm install @okyc/nodeimport { Okyc } from '@okyc/node';
const okyc = new Okyc(process.env.OKYC_SECRET_KEY!); // sk_test_… or sk_live_…| Option | Default | |
|---|---|---|
baseUrl | https://api.okyc.stream | API origin, for a dedicated or self-hosted deployment. Must be https except on localhost. |
apiVersion | — | Pins the OKYC-Version header. |
timeoutMs | 30000 | Per request. |
maxRetries | 3 | Network errors, 408, 429, 5xx; exponential backoff with jitter, honours Retry-After. |
fetch | global fetch | Custom fetch implementation. |
logger | — | Receives method, path, status, latency, attempt and request id — never bodies. |
The constructor refuses anything that isn't a secret key, so a client token can't be used by mistake.
Sessions
// 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' });
}
});| Method | Endpoint |
|---|---|
sessions.create(params, { idempotencyKey }) | POST /v1/sessions → { id, status, url, clientToken, expiresAt } |
sessions.retrieve(id, { expand: ['checks', 'applicant', 'business'] }) | GET /v1/sessions/:id |
sessions.list(params) | async iterator over every page (firstPage() for one page) |
sessions.listPage(params) | one page: { data, has_more } |
sessions.decide(id, { outcome, reasonCode, note, steps }) | POST /v1/sessions/:id/decision |
sessions.cancel(id) | POST /v1/sessions/:id/cancel |
sessions.createClientToken(id) | POST /v1/sessions/:id/client_token |
sessions.evidenceUrl(id, evidenceId) | GET /v1/sessions/:id/evidence/:evidence_id |
sessions.erasePii(id) | DELETE /v1/sessions/:id/pii |
create takes camelCase (workflowId, referenceId, redirectUrl, expiresIn, prefill.fullName);
retrieved sessions are returned as the API sends them (snake_case).
Webhooks
// Webhooks: verify against the RAW body, dedupe on event.id, then fetch details from the API.
const seen = new Set();
app.post('/okyc/webhook', express.raw({ type: 'application/json' }), async (req, res) => {
let event;
try {
event = await okyc.webhooks.constructEvent(
req.body,
req.header('okyc-signature'),
process.env.OKYC_WEBHOOK_SECRET,
);
} catch {
return res.sendStatus(400);
}
if (seen.has(event.id)) return res.sendStatus(200);
seen.add(event.id);
if (event.type === 'session.approved' || event.type === 'session.declined') {
const session = await okyc.sessions.retrieve(event.data.session.id);
console.log(`user ${session.reference_id} → ${session.status}`);
// mark the user verified / rejected in your database
}
res.sendStatus(200);
});webhooks.constructEvent(rawBody, header, secret, { toleranceSec }) throws WebhookSignatureError when the
header is missing, malformed, too old or wrong, or when the body isn't JSON. A valid event can arrive more than
once within the tolerance, so de-duplicate on its id (webhooks).
generateTestHeader(secret, body) signs a body for your tests.
Both use Web Crypto, so they work in edge runtimes.
Checks and other resources
| Method | |
|---|---|
checks.run(key, input, { async }) / checks.retrieve(id) | Direct checks, e.g. checks.run('in.pan.verify', { pan }). |
in.pan.verify, in.gstin.verify, in.bank.verify, in.mca.company, in.udyam.verify | Typed shortcuts for India checks. |
screening.sanctions({ name, dob, entity_type }) | Sanctions screening without a session. |
workflows.list() / workflows.retrieve(id) | Published workflows. |
webhookEndpoints.create/list/del | Manage endpoints (the secret is returned once by create). |
events.list({ type, limit }) | Recent events, for reconciliation. |
capabilities.list({ country }) | What a country supports. |
Errors are typed — see errors.
Errors
One error shape for every endpoint; branch on type and code, log the request id.
@okyc/web
Open the hosted flow from any website — modal, inline, popup or redirect. Zero dependencies, under 10 KB.
© 2026 Aiistic Technologies Private Limited. OKYC is a product of Aiistic Technologies Private Limited. Privacy notice