Developer hub

One API call. Full verification.

Create a verification, send your user to the hosted flow, embed it on your own page or upload media directly — then receive a signed webhook with the result. Copy-paste snippets for curl, Node, Python and PHP.

Idempotent by design Signed webhooks Deterministic sandbox
POST /v1/verifications201 Created
POST https://api.okias.io/v1/verifications
Authorization: Bearer ok_live_...
Idempotency-Key: 9f2c4a1b-1e33-4c07-9c1e-2b7f0d5a1a10

{
  "level": ["FULL_KYC"],
  "country": "pk",
  "doc_type": "NATIONAL_ID",
  "end_user_ref": "user_8842"
}
Response
HTTP/1.1 201 Created

{
  "id": "cms80k9ix001moea2jxy64fgu",
  "status": "PENDING",
  "cost_credits": 1,
  "mode": "LIVE",
  "hosted_url": "https://okias.io/verify/cms80k9ix001moea2jxy64fgu",
  "liveness_challenge": { "actions": ["LOOK_DOWN", "TURN_RIGHT", "LOOK_UP", "TURN_LEFT"] },
  "reason_codes": []
}

One request in, one decision out — this is the entire integration surface.

Quickstart

Live in three steps.

Create a full-KYC verification with a single authenticated POST to https://api.okias.io/v1/verifications. Swap in your live key and go — no SDK required.

01

Create a verification

One authenticated POST returns a verification id and a hosted flow URL — with an Idempotency-Key so retries never double-charge.

02

Hosted flow, embed or upload

Redirect to the hosted flow, embed it on your own page, or upload the document and selfie yourself. We handle capture quality, liveness and OCR.

03

Receive a signed webhook

The moment the decision resolves you get an HMAC-SHA256 signed event — approved, declined or review — ready to provision the user.

The same request in the four most common stacks — copy one, paste it into your project and run it.

curlPOST /v1/verifications
curl https://api.okias.io/v1/verifications \
  -H "Authorization: Bearer ok_live_..." \
  -H "Idempotency-Key: 9f2c-4a1b-..." \
  -H "Content-Type: application/json" \
  -d '{
    "level": ["FULL_KYC"],
    "country": "pk",
    "doc_type": "NATIONAL_ID",
    "end_user_ref": "user_8842"
  }'
NodePOST /v1/verifications
import crypto from "node:crypto";

const res = await fetch("https://api.okias.io/v1/verifications", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.OKIAS_API_KEY}`,
    "Idempotency-Key": crypto.randomUUID(),
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    level: ["FULL_KYC"],
    country: "pk",
    doc_type: "NATIONAL_ID",
    end_user_ref: "user_8842",
  }),
});

const verification = await res.json();
console.log(verification.id, verification.status);
PythonPOST /v1/verifications
import os, uuid, requests

res = requests.post(
    "https://api.okias.io/v1/verifications",
    headers={
        "Authorization": f"Bearer {os.environ['OKIAS_API_KEY']}",
        "Idempotency-Key": str(uuid.uuid4()),
    },
    json={
        "level": ["FULL_KYC"],
        "country": "pk",
        "doc_type": "NATIONAL_ID",
        "end_user_ref": "user_8842",
    },
)

verification = res.json()
print(verification["id"], verification["status"])
PHPPOST /v1/verifications
<?php
$ch = curl_init("https://api.okias.io/v1/verifications");
curl_setopt_array($ch, [
  CURLOPT_POST => true,
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER => [
    "Authorization: Bearer " . getenv("OKIAS_API_KEY"),
    "Idempotency-Key: " . bin2hex(random_bytes(16)),
    "Content-Type: application/json",
  ],
  CURLOPT_POSTFIELDS => json_encode([
    "level" => ["FULL_KYC"],
    "country" => "pk",
    "doc_type" => "NATIONAL_ID",
    "end_user_ref" => "user_8842",
  ]),
]);

$verification = json_decode(curl_exec($ch), true);
echo $verification["id"] . " " . $verification["status"];

A FULL_KYC verification runs the document check, active liveness, 1:1 face match and sanctions screening against the official OFAC, EU, UK and UN lists — one credit at $0.15, charged only on approval.

Get your API key
Authentication

One bearer token, two environments.

Authenticate every request with your secret key in an Authorization: Bearer header. Test keys hit the deterministic sandbox and never spend a credit; live keys run real verifications.

Test modeSandbox key
ok_test_4f8a2c9e1b7d…

Points at the deterministic sandbox. Force any outcome with test refs — never billed.

Live modeProduction key
ok_live_4f8a2c9e1b7d…

Runs real document, liveness, face-match and sanctions checks. One credit per full KYC.

Keep secret keys server-side. Every key is fixed to one mode at creation (ok_test_ or ok_live_), scoped to the checks it is allowed to run, and stored only as a SHA-256 hash — we never hold the plaintext. Revocation is instant: the next request with a revoked key gets 401, and your other keys keep working. All API traffic is TLS-only; requests over plain HTTP are rejected.

Deterministic sandbox

Break it before your users can.

Test keys run against a sandbox with simulated outcomes. Force approved, declined or review with test refs, and exercise every branch of your integration — webhooks included — without spending a credit.

Force APPROVEDForce DECLINEDForce REVIEWWebhooks fire for realNever billed
Webhooks

Subscribe once. Never poll.

Every event is signed with HMAC-SHA256 and retried with backoff until you return 2xx. Verify the X-Okias-Signature header, then acknowledge fast.

verification.approved

The verification ran and passed. Provision the user.

verification.declined

The verification ran and failed. Block or retry per policy.

verification.review

Routed to manual review. A final event follows.

verification.error

Processing could not complete. The credit hold is released.

verify-signature.jsHMAC-SHA256
import crypto from "node:crypto";

// X-Okias-Signature: t=<unix-seconds>,v1=<hex-hmac>
export function verifyOkiasWebhook(rawBody, header, secret) {
  const { t, v1 } = Object.fromEntries(
    header.split(",").map((kv) => kv.split("=")),
  );
  if (Math.abs(Date.now() / 1000 - Number(t)) > 300) {
    return false; // replay protection
  }

  const expected = crypto
    .createHmac("sha256", secret)
    .update(`${t}.${rawBody}`) // sign the RAW body bytes
    .digest("hex");

  const a = Buffer.from(v1, "hex");
  const b = Buffer.from(expected, "hex");
  return a.length === b.length && crypto.timingSafeEqual(a, b);
}
Embed SDK

The full flow, on your page.

One script tag and one function call render the verification flow in an iframe on your own domain — capture hints, liveness and upload included. Events post back to your code as the user progresses.

  • No redirect — users never leave your site
  • onComplete callback with the final status
  • Document and selfie go straight to OKIAS, not your servers
  • Prefer a redirect? The hosted flow URL works out of the box
embed.html — runs on your domainiframe SDK
<script src="https://okias.io/embed/okias.js"></script>
<div id="kyc"></div>
<script>
  OkiasKYC.render({
    container: '#kyc',
    id: 'cms80k9ix001moea2jxy64fgu', // from your server
    onComplete: (r) => console.log(r.status),
  });
</script>
API reference

A small, predictable surface area.

REST over HTTPS, JSON in and out, and standard status codes. A handful of resources runs KYC end to end — KYB is on the roadmap.

MethodEndpointDescription
POST/v1/verificationsCreate a verification and get a hosted flow URL.
POST/v1/verifications/:id/submitSubmit the document and selfie assets for a verification.
GET/v1/verifications/:idRetrieve a verification and its decision.
GET/v1/credits/balanceRead your current credit balance.
POST/v1/webhooksRegister a signed webhook endpoint.
Base URL https://api.okias.io/v1 JSON · idempotent writes · OpenAPI specA dedicated api.okias.io host is being provisioned and will be announced.
Built for production

The details that keep you safe.

Everything you need to run identity verification at scale — without the enterprise contract.

Idempotency keys

Send an Idempotency-Key on every create — safe retries never double-charge or duplicate a verification.

HMAC-signed webhooks

Every webhook is signed with HMAC-SHA256 so you can verify authenticity before acting on it.

Deterministic sandbox

Force approved, declined or review with test refs — exercise every branch before spending a credit.

Mode- and check-scoped keys

Each key is fixed to test or live mode and to the checks it may run, stored only as a SHA-256 hash. Revoke one and it 401s on its next request — the rest keep working.

Prompt-injection detection

Instruction-like text hidden in a submitted image is detected and the verification is routed to human review instead of trusting the AI verdict. Surfaces as PROMPT_INJECTION_SUSPECTED.

Real sanctions data

Names are screened against the official OFAC (SDN + non-SDN), EU, UK OFSI and UN lists, refreshed daily. A possible match routes to review — it never auto-declines.

Ship compliant onboarding today.

100 free credits, no card required. A full KYC — document, liveness, face match and screening — is one credit at $0.15.

Charged only on approved verifications Signed webhooks Sandbox included