API Documentation

REST API reference for workflow-based identity verification: authentication, verifications, bans, workflows, billing and signed webhooks.

Markdown'ı görüntüle

Sayfanın tamamını Cursor, Claude Code veya Copilot gibi kod asistanınıza tek seferde verebilirsiniz.

API Reference · v1

REST API for workflow-based verification management. Every request authenticates with a server-side API key sent in the X-Authorization header, next to the ID the key belongs to.

On This Page

Base URL & Authentication

Send every request over HTTPS to the base URL, with two headers: an API key and the ID it belongs to. Verification endpoints take a workflow’s key; ban and workflow endpoints take your organization’s key.

Base URL

https://api.osvoy.com/api/v1

Headers

EndpointsSend These Headers
Verifications
All seven endpoints
X-Authorization: <workflow API key>
X-Workflow-ID: <workflow ID>
Bans, WorkflowsX-Authorization: <organization API key>
X-Organization-ID: <organization ID>
Requests with a bodyContent-Type: application/json

Example Request

curl -X POST https://api.osvoy.com/api/v1/verifications \
  -H "X-Authorization: $OSVOY_WORKFLOW_KEY" \
  -H "X-Workflow-ID: <workflow-id>" \
  -H "Content-Type: application/json" \
  -d '{"vendor_data": "cust_20931847"}'

Note: Keys are shown once — when they’re generated or rotated. Keep them on your server; never ship one in a browser or a mobile app.

Conventions

Shared rules across every endpoint — base URL, auth, IDs, pagination, rate limits and error format.

ConventionValue
Base URLhttps://api.osvoy.com/api/v1
AuthenticationX-Authorization plus X-Workflow-ID or X-Organization-ID — see Base URL & Authentication
Content Typeapplication/json
ID FormatUUID v4
TimestampsISO 8601, UTC — 2026-04-23T14:30:00Z
Pagination?page=<number>
Filtering?status=passed&workflow_id=…
IdempotencyThe last request sent is the one applied.
Rate Limit100 requests per minute per organization (burst 200). X-RateLimit-* headers are returned.
ErrorsRFC 7807 Problem Details with code and message.

HTTP Status Codes

CodeMeaning
200 OKSuccessful read / update / resource created
202 AcceptedPDF generation queued
204 No ContentSuccessful delete
400 Bad RequestValidation error
401 UnauthorizedMissing or invalid API key
402 Payment RequiredInsufficient credit balance
403 ForbiddenKey lacks scope for action
404 Not FoundResource does not exist
409 ConflictInvalid state transition or duplicate
422 Unprocessable EntitySemantic validation failed
429 Too Many RequestsRate limit exceeded
5xxServer error — retry with backoff

Resource Model

Verification  ── produced by ──>  Workflow
     │
     ├── status transitions
     │     (created → in_progress → manual_review → passed/failed/expired/cancelled)
     ├── verification data (document data, liveness results, checks, etc.)
     └── can be exported as PDF report

Ban           ── scoped by organization
Workflow      ── reusable, customizable template for hosted KYC flows
Balance       ── prepaid credits consumed per verification

Action Mapping

All 17 actions mapped to REST endpoints across four groups: Verifications, Bans, Workflows and Billing.

#ActionMethodPath
1create-verificationPOST/verifications
2retrieve-verificationGET/verifications/{id}
3list-verificationGET/verifications
4update-verification-statusPATCH/verifications/{id}/status
5update-verification-dataPATCH/verifications/{id}/data
6delete-verificationDELETE/verifications/{id}
7create-verification-pdfPOST/verifications/{id}/pdf
8list-bansGET/bans
9create-banPOST/bans
10delete-banDELETE/bans/{id}
11list-workflowsGET/workflows
12create-workflowPOST/workflows
13retrieve-workflowGET/workflows/{id}
14update-workflowPATCH/workflows/{id}
15delete-workflow——
16get-balanceGET/billing/balance
17balance-top-upPOST/billing/top-up

Verifications

A verification is an instance of a workflow applied to one end user. Creating one returns a hosted verification_url you redirect the user to.

Create Verification

POST /verifications

Action: create-verification · Workflow Key

Creates a new verification and returns a short-lived hosted verification_url — it lives for 1 hour.

Request Body

{
  "workflow_id": "8b2f3c4d-0a1e-4b2f-9c3d-1e2f3a4b5c6d",
  "vendor_data": "user-42"
}

Response · 200 OK

{
  "id": "bbd23629-1a24-4d26-bb12-a905b9ae85b8",
  "workflow_id": "8b2f3c4d-0a1e-4b2f-9c3d-1e2f3a4b5c6d",
  "vendor_data": "user-42",
  "status": "created",
  "verification_url": "https://verify.yourdomain.com/bbd23629-1a24-4d26-bb12-a905b9ae85b8",
  "created_at": "2026-04-23T13:11:13.625Z",
  "expires_at": "2026-04-23T14:11:13.625Z"
}

Errors: 400 invalid workflow · 402 insufficient balance.

Retrieve Verification

GET /verifications/{id}

Action: retrieve-verification · Workflow Key

Returns the full verification record, including extracted data once the verification is complete.

Response · 200 OK

{
  "id": "84f56ba9-fcef-47b0-87f5-1a07ae70396e",
  "workflow_id": "8b2f3c4d-0a1e-4b2f-9c3d-1e2f3a4b5c6d",
  "vendor_data": null,
  "status": "passed",
  "created_by_api": false,
  "warnings": [],
  "files": [],
  "verification_data": {
    "document": {
      "document_type": "id_card",
      "document_number": null,
      "personal_number": null,
      "issuing_state": "TUR",
      "first_name": null,
      "last_name": null,
      "date_of_birth": null,
      "expiration_date": null,
      "gender": null,
      "is_document_verified": true
    },
    "liveness": {
      "active_score": null,
      "passive_score": null,
      "is_live": true
    },
    "face_match": {
      "face_similarity": null,
      "is_face_verified": true
    },
    "ip_analysis": {
      "time_zone": null,
      "isp": null,
      "organization": null,
      "is_datacenter": false,
      "is_vpn_tor": false
    }
  },
  "created_at": "2026-04-20T12:41:35.787Z",
  "finished_at": "2026-04-21T10:18:00.167Z",
  "webhook_sent_successfully": false
}

List Verifications

GET /verifications

Action: list-verification · Workflow Key

Paginated, filterable list of verifications.

Query Parameters

NameTypeRequiredDescription
pageintegerOptionalPage number
statusenumOptionalcreated, in_progress, manual_review, passed, failed, expired, cancelled
workflow_iduuidOptionalFilter by workflow
vendor_datastringOptionalFilter by your user identifier
issuing_statestringOptional3-letter country code (e.g. TUR for Türkiye)
created_afterdatetimeOptionalISO 8601
created_beforedatetimeOptionalISO 8601

Response · 200 OK

{
  "count": 22,
  "prevPage": 1,
  "nextPage": 3,
  "results": [
    {
      "id": "84f56ba9-fcef-47b0-87f5-1a07ae70396e",
      "status": "passed",
      "workflow_id": "8b2f3c4d-0a1e-4b2f-9c3d-1e2f3a4b5c6d",
      "vendor_data": "user-42",
      "created_at": "2026-04-20T12:41:35.787Z"
    }
  ]
}

Note: prevPage is null on the first page; nextPage is null on the last.

Update Verification Status

PATCH /verifications/{id}/status

Action: update-verification-status · Workflow Key

Manual review override. Only these transitions are allowed: manual_review → passed | failed, passed → failed, failed → passed. Every transition is audit logged.

Body Parameters

NameTypeRequiredDescription
statusenumRequiredpassed or failed
commentstringOptionalWhy you decided. Kept as the session’s note, up to 100 characters.

Request Body

{
  "status": "passed",
  "comment": "Verified against secondary documentation by agent."
}

Response · 200 OK

{
  "id": "84f56ba9-fcef-47b0-87f5-1a07ae70396e",
  "status": "passed",
  "updated_at": "2026-04-23T15:00:00Z"
}

Errors: 409 on an invalid transition (e.g. created → passed).

Update Verification Data

PATCH /verifications/{id}/data

Action: update-verification-data · Workflow Key

Updates writable fields on a verification — typically vendor_data and manual corrections to extracted fields. Core biometric and document results are immutable.

Request Body

{
  "vendor_data": "user-42-migrated",
  "document_data": {
    "document_type": "id_card",
    "document_number": "X12345678",
    "personal_number": "12345678901",
    "issuing_state": "TUR",
    "first_name": "Mehmet Ali",
    "last_name": "Yılmaz",
    "date_of_birth": "1990-06-15",
    "expiration_date": "2030-06-14",
    "gender": "M"
  }
}

Response · 200 OK

{
  "id": "84f56ba9-fcef-47b0-87f5-1a07ae70396e",
  "vendor_data": "user-42-migrated",
  "updated_at": "2026-04-23T15:05:00Z"
}

Errors: 422 if a field is immutable or has an invalid value.

Delete Verification

DELETE /verifications/{id}

Action: delete-verification · Workflow Key

GDPR-style hard delete with no recovery. Removes the record and its artefacts (images, videos, PDFs).

Errors: 404 not found · 409 if the verification is currently in_progress.

Create Verification PDF

POST /verifications/{id}/pdf

Action: create-verification-pdf · Workflow Key

Generates a signed PDF report of the verification. The PDF is deleted 3 hours after creation.

Body Parameters

NameTypeRequiredDescription
languageenumRequireden or tr

Request Body

{
  "language": "en"
}

Response · 200 OK

{
  "pdf_url": "https://cdn.osvoy.com/pdf/pdf_01HX....pdf",
  "expires_at": "2026-04-24T14:30:00Z"
}

Note: language accepts en or tr.

Bans

A ban blocks a subject — by vendor_data, document_number, personal_number or ip — from being approved in future verifications. Any matching session auto-flips to failed, with an audit log entry.

List Bans

GET /bans

Action: list-bans · Organization Key

Lists ban entries, optionally filtered by data type and an exact-match lookup.

Query Parameters

NameTypeRequiredDescription
pageintegerOptionalPagination
data_typeenumOptionalvendor_data, personal_number, document_number, ip
datastringOptionalExact-match lookup

Response · 200 OK

{
  "count": 22,
  "prevPage": 1,
  "nextPage": 3,
  "results": [
    {
      "id": 1,
      "data_type": "document_number",
      "data": "X12345678",
      "reason": "Confirmed fraudulent document",
      "created_at": "2026-04-20T09:10:00Z"
    }
  ]
}

Create Ban

POST /bans

Action: create-ban · Organization Key

Blocks a subject by vendor_data, document_number, personal_number or ip. Any matching session auto-flips to failed, with an audit log entry.

Body Parameters

NameTypeRequiredDescription
data_typeenumRequiredvendor_data, personal_number, document_number, ip
datastringRequiredThe value to block, up to 500 characters.
reasonstringOptionalWhy it’s blocked, up to 500 characters.

Request Body

{
  "data_type": "document_number",
  "data": "X12345678",
  "reason": "Confirmed fraudulent document"
}

Response · 200 OK

{
  "id": 1,
  "data_type": "document_number",
  "data": "X12345678",
  "reason": "Confirmed fraudulent document",
  "created_at": "2026-04-20T09:10:00Z"
}

Errors: 409 if the same subject is already banned.

Delete Ban

DELETE /bans/{id}

Action: delete-ban · Organization Key

Removes a ban. Verifications it already declined stay declined.

Workflows

A workflow is a reusable template that defines which verification modules run, in what order, and with what decision rules.

List Workflows

GET /workflows

Action: list-workflows · Organization Key

Query Parameters

NameTypeRequiredDescription
pageintegerOptionalPage number
limitintegerOptionalResults per page

Response · 200 OK

{
  "results": [
    {
      "id": "8b2f3c4d-0a1e-4b2f-9c3d-1e2f3a4b5c6d",
      "name": "Standard KYC",
      "created_at": "2026-01-10T10:00:00Z",
      "updated_at": "2026-04-01T12:00:00Z"
    }
  ]
}

Create Workflow

POST /workflows

Action: create-workflow · Organization Key

Workflows are reusable templates defining which verification modules run, in what order, and with what decision rules. id_verification.maximum_age is a year of birth: anyone born earlier is rejected.

Request Body

{
  "name": "Standard KYC",
  "primary_color": "#2563EB",
  "font": "inter",
  "redirection_url": "https://example.com",
  "redirection_enabled": true,
  "id_verification": {
    "minimum_age": 18,
    "maximum_age": 1961
  },
  "liveness": {
    "method": "3d_action",
    "liveness_3d_action_order": ["left", "right", "up"],
    "active_decline": 30,
    "active_review": 60,
    "passive_decline": 30,
    "passive_review": 60
  },
  "face_match": {
    "decline_max": 30,
    "review_max": 60
  },
  "ip_analysis": {
    "ip_mismatch": "review",
    "tor_vpn": "decline",
    "expected_ip": "review"
  }
}

Response · 200 OK

{
  "id": "8b2f3c4d-0a1e-4b2f-9c3d-1e2f3a4b5c6d",
  "name": "Standard KYC",
  "created_at": "2026-04-23T13:11:13.625Z"
}

Retrieve Workflow

GET /workflows/{id}

Action: retrieve-workflow · Organization Key

Returns the full workflow, including modules, configs and decision rules. Same shape as the create response.

Update Workflow

PATCH /workflows/{id}

Action: update-workflow · Organization Key

Partial update — only the supplied fields change, and a settings object you send is merged into the stored one.

Request Body

{
  "name": "Standard KYC (v2)",
  "id_verification": {
    "minimum_age": 21
  }
}

Response · 200 OK

{
  "id": "8b2f3c4d-0a1e-4b2f-9c3d-1e2f3a4b5c6d",
  "name": "Standard KYC (v2)",
  "updated_at": "2026-04-23T15:10:00Z"
}

Errors: 409 on a conflicting update.

Deleting Workflows

Warning: delete-workflow — deleting a workflow through the API isn’t allowed, to prevent accidental data loss. Delete one from the Workflows page instead.

Billing

Prepaid credits are consumed per verification. Top up with a saved payment method or a one-time payment token.

Get Balance

GET /billing/balance

Action: get-balance

Each verification module has a credit cost (id_verification = 10, liveness = 5, aml = 3). The cost is deducted when a verification is created and refunded if it expires unused.

Response · 200 OK

{
  "balance": 4275,
  "currency": "credits",
  "last_updated": "2026-04-23T14:25:00Z"
}

Balance Top-Up

POST /billing/top-up

Action: balance-top-up

Purchases credits, charged to a saved payment method on the account or a one-time payment token.

Request Body

{
  "amount": 10000
}

Response · 200 OK

{
  "transaction_url": "https://api.osvoy.com/txn_01HX..."
}

Errors: 402 if the payment method fails · 409 on a duplicate idempotency_key.

Webhooks

Register destination URLs out of band (console or a separate endpoint) and receive signed POSTs. Each request is signed with HMAC-SHA256 in X-Signature.

verification.status

Event

POST <your-webhook-url>

Sent whenever a verification transitions to a terminal state.

Payload

{
  "session_id": "sess_8f3a2c1d-4b5e-6f7a-8b9c-0d1e2f3a4b5c",
  "status": "passed",
  "timestamp": "2026-05-15T14:32:18Z",
  "vendor_data": "customer_ref_98765",
  "webhook_type": "status.updated",
  "workflow_id": 3,
  "created_at": "2026-05-15T14:28:42Z",
  "webhook_url": "https://api.example.com/webhooks/kyc",
  "redirect_url": "https://app.example.com/verification/complete",
  "face_match": {
    "similarity_score": 0.82,
    "verified": true,
    "selfie_image_url": "https://cdn.example.com/sessions/sess_8f3a2c1d/selfie.jpg",
    "warnings": [
      {
        "label": "face-features-match-reference-image",
        "type": "danger"
      }
    ]
  },
  "document": {
    "front_side_image_url": "https://cdn.example.com/sessions/sess_8f3a2c1d/doc_front.jpg",
    "front_side_video_url": "https://cdn.example.com/sessions/sess_8f3a2c1d/doc_front.mp4",
    "back_side_image_url": "https://cdn.example.com/sessions/sess_8f3a2c1d/doc_back.jpg",
    "back_side_video_url": "https://cdn.example.com/sessions/sess_8f3a2c1d/doc_back.mp4",
    "face_image_url": "https://cdn.example.com/sessions/sess_8f3a2c1d/doc_face.jpg",
    "issuing_state": "TR",
    "nationality": "TR",
    "document_type": "id_card",
    "document_number": "A12B34567",
    "personal_number": "12345678901",
    "first_name": "Mehmet Ali",
    "last_name": "Yılmaz",
    "full_name": "Mehmet Ali Yılmaz",
    "date_of_birth": "1990-06-15",
    "expiration_date": "2030-06-14",
    "gender": "M",
    "warnings": [
      {
        "label": "user-meets-minimum-age-requirement",
        "type": "danger"
      }
    ],
    "verified_by_gov_db": true
  },
  "ip_analysis": {
    "location": "Istanbul, Turkey",
    "time_zone": "Europe/Istanbul",
    "isp": "Turk Telekom",
    "organization": "TTNet A.S.",
    "is_vpn_tor": false,
    "is_datacenter": false,
    "device": "iPhone 14 Pro",
    "browser": "Safari 17.4",
    "os_name": "iOS",
    "platform": "mobile",
    "verified": true,
    "warnings": []
  },
  "liveness": {
    "verified": true,
    "selfie_image_url": "https://cdn.example.com/sessions/sess_8f3a2c1d/liveness_selfie.jpg",
    "selfie_video_url": "https://cdn.example.com/sessions/sess_8f3a2c1d/liveness_selfie.mp4",
    "warnings": [],
    "active_liveness": {
      "mode": "active",
      "actions_matched": ["left", "right"],
      "actions_requested": ["left", "right"],
      "liveness_score": 0.78
    },
    "passive_liveness": {
      "verified": true,
      "liveness_score": 0.71
    }
  }
}

Note: Set the destination URL on each workflow, under Customization in the workflow editor. Deliveries go to that workflow’s URL.

Verifying Deliveries

Every delivery carries three headers. Recompute the signature over the raw body with the workflow’s secret key and compare before you trust the payload.

Delivery Headers

HeaderDescription
content-typeapplication/json; charset=utf-8
x-timestampUnix time, in seconds, when the delivery was sent. It isn’t part of the signature.
x-signatureHex-encoded HMAC-SHA256 of the raw request body, keyed with the workflow’s secret key. No prefix.

Example · Node.js

import crypto from "node:crypto";

// rawBody: the exact bytes you received — check them before JSON.parse.
// secretKey: the workflow's secret key (sk_…), kept on your server.
export function isGenuineDelivery(rawBody, signatureHeader, secretKey) {
  const expected = crypto
    .createHmac("sha256", secretKey)
    .update(rawBody)
    .digest("hex");
  const received = String(signatureHeader || "");
  return (
    received.length === expected.length &&
    crypto.timingSafeEqual(Buffer.from(received), Buffer.from(expected))
  );
}

Note: A delivery that fails or doesn’t answer 2xx is retried up to 3 times, 60 seconds apart. Answer quickly and do slow work afterwards.

verification.status_update

Event · Opt-In

POST <your-webhook-url>

Sent on every status change — created → in_progress → manual_review → passed — so you can follow a session without polling. It carries what changed, not the results; those still arrive once in verification.status. Turned on per workflow: ask Support.

Payload

{
  "session_id": "84f56ba9-fcef-47b0-87f5-1a07ae70396e",
  "webhook_type": "verification.status_update",
  "status": "manual_review",
  "previous_status": "in_progress",
  "is_final": false,
  "current_step": "liveness",
  "fail_reason": null,
  "reject_reason": null,
  "vendor_data": "customer_ref_98765",
  "workflow_id": 3,
  "webhook_url": "https://api.example.com/webhooks/kyc",
  "redirect_url": "https://app.example.com/verification/complete",
  "created_at": "2026-05-15T14:28:42Z",
  "finished_at": null,
  "changed_at": "2026-05-15T14:31:05Z",
  "timestamp": 1778855465
}

Security & Operations

API Keys
API keys are scoped per organization and manage all organization data. For testing or playground access, contact Support.

PII at Rest
Encrypted with per-tenant keys. The DELETE /verifications/{id} action guarantees physical removal at the same time.

Audit Log
Maintained for every POST, PATCH and DELETE — retrievable separately for a compliance review.

Consent & Disclosure
The caller’s responsibility. Show the end user who is verifying them and link to your privacy policy before redirecting to the hosted verification_url.

Osvoy Verify

Makine öğrenmesi ve biyometri destekli kimlik doğrulama altyapısı.

Çözümler

Kimlik Belgesi DoğrulamaCanlılık TespitiBiyometrik Yüz EşleştirmeAML Taraması
Gizlilik PolitikasıKullanım KoşullarıÇerez PolitikasıVeri İşleme SözleşmesiTeslimat ve İade ŞartlarıMesafeli Satış Sözleşmesi

© 2026 Osvoy. Tüm hakları saklıdır.

iyzico ile öde — Mastercard, Visa, American Express ve TroyPayTR ile güvenli ödeme