Developers

API reference

One base URL, one bearer header, prepaid credits. Everything on this page is live.

Base URL
https://liveliness.neetix.in
Auth header
Authorization: Bearer <api_key>
Free tier
1,000 credits at signup

01

Getting started

Sign up with an email, get a live key + a free test key, and call the API from anywhere.

POST /v1/signup issues TWO DB-backed API keys in one call — a live key and a test key. Both are shown once — store them immediately. Every request to a /v1 endpoint must carry the bearer header; errors come back as JSON (see Errors).

signup.sh
$ curl -X POST https://liveliness.neetix.in/v1/signup \
    -H "Content-Type: application/json" \
    -d '{"email":"you@company.com"}'

{
  "api_key": "lv_9f2c4e8a…",
  "test_api_key": "lv_test_7b1d3f0c…",
  "client_id": "a1b2c3d4e5f6a7b8",
  "credits": 1000,
  "message": "Save both keys — each is shown only once."
}

Test mode: test_api_key (lv_test_… prefix) is free and unmetered — calls never deduct credits — and gets its own isolated `client_id`, so its gallery enrollments, dedupe/replay state and audit logs never touch your live data. Every inference response carries "mode": "live" or "mode": "test" so you can assert which key ran. Mint more test keys anytime from the console (POST /v1/keys with body {"test": true}).

02

Authentication

One bearer header on every request. No request signing, no OAuth handshake.

Every /v1 endpoint takes the same header — Authorization: Bearer <api_key>. Keys are issued at signup and shown once; balance, ledger and usage for a key live in the console.

A missing or invalid key returns 401 with message_code: "unauthorized". The cheapest way to verify a key is GET /v1/billing/balance — it reads your prepaid balance without consuming credits.

auth-check.sh
$ curl https://liveliness.neetix.in/v1/billing/balance \
    -H "Authorization: Bearer $LIVELINESS_API_KEY"

{ "status": "success", "client_id": "a1b2c3d4e5f6a7b8", "balance": 500, "metered": true }

03

Face match

Selfie vs. ID photo: same-face confidence, passive liveness, quality and forensics in one call.

POST/v1/face/face-match2 credits

Body is multipart/form-data. The response keeps a Digitap-compatible envelope (top level + result) and adds a lowercase aggregate verdictapproved | review | declined — plus a warnings[] array of { code, severity, description } risk signals such as LIVENESS_FACE_ATTACK, LOW_FACE_QUALITY and MULTIPLE_FACES_DETECTED.

FieldTypeRequiredNotes
personfileyesthe selfie (jpeg/png/gif/webp, ≤5 MB)
cardfileyesthe reference / ID photo
clientRefIdtextechoed back; generated if absent
customer_idtextpersisted to the audit log
lead_idtextpersisted to the audit log
face-match.sh
$ curl -X POST https://liveliness.neetix.in/v1/face/face-match \
    -H "Authorization: Bearer $LIVELINESS_API_KEY" \
    -F "person=@selfie.jpg" \
    -F "card=@aadhaar.jpg" \
    -F "clientRefId=lead-8841"
200 response
{
  "status": "success",
  "statusCode": 200,
  "clientRefId": "lead-8841",
  "requestId": "018f6a2e-…-v7",
  "verdict": "approved",
  "warnings": [],
  "result": {
    "is_same_face": true,
    "same_face_confidence": 87.34,
    "cosine_similarity": 0.5123,
    "decision": "APPROVED",
    "match_threshold": 70.0,
    "liveness_score": 92.1,
    "liveness_status": "genuine",
    "spoof_detected": false,
    "liveness_threshold": 70.0,
    "person_quality": { "sharpness": 210.4, "brightness": 129.7, "score": 88.2, "blurry": false },
    "card_quality":   { "sharpness": 160.1, "brightness": 141.2, "score": 74.0, "blurry": false },
    "model_version": "neetix-face-v1"
  }
}

If no face is found in either image the call returns 422 with the Digitap-compatible fail envelope: { "status": "fail", "statusCode": 422, "error": "Face not found in one or both of the images." }.

04

Liveness & sessions

Passive one-shot checks, active challenge–response sessions, and continuous V-CIP streams.

EndpointPurposeCredits
POST /v1/livenesspassive anti-spoof on a single selfie → Approved | Declined + liveness_score1
POST /v1/session/startissue a randomized head-pose challenge script + session_id1
POST /v1/session/{id}/verifymultipart frame_0…frame_n, one per challenge → verdict; defeats static-photo replay2
POST /v1/stream/startopen a continuous-liveliness (V-CIP) session → session_id, stream_url, challenges5
WS /v1/stream/{id}send JPEG frames as binary; per-frame status + a final verdictincluded
session-flow.sh
# 1. start a session — returns a randomized challenge script
$ curl -X POST https://liveliness.neetix.in/v1/session/start \
    -H "Authorization: Bearer $LIVELINESS_API_KEY"

{ "session_id": "9f2c4e8a…", "challenges": ["center", "left", "right"] }

# 2. capture one frame per challenge, then verify
$ curl -X POST https://liveliness.neetix.in/v1/session/9f2c4e8a…/verify \
    -H "Authorization: Bearer $LIVELINESS_API_KEY" \
    -F "frame_0=@center.jpg" -F "frame_1=@left.jpg" -F "frame_2=@right.jpg"

The stream's temporal model scores every frame for sustained liveliness, real head motion and identity continuity — a mid-stream face-swap raises IDENTITY_SWITCH, a static photo raises NO_MOTION, and looped-video replays are rejected. A browser-hosted capture page is available at GET /capture if you don't want to ship an SDK.

05

Identity suite

The rest of the verification toolkit — screening, validation, monitoring and orchestration.

EndpointPurposeCredits
POST /v1/aml/screensanctions / watchlist name screening (name + optional dob, threshold)1
POST /v1/kyb/validatebusiness KYB — GSTIN checksum + state, PAN, CIN decoding2
POST /v1/txn/monitortransaction-pattern rules: STRUCTURING, VELOCITY, RAPID_IN_OUT, HIGH_VALUE1
POST /v1/wallet/screencrypto wallet address screening → hit + matches[]1
POST /v1/device/analyzedevice + IP fraud signals → risk_score 0–100, risk_level, flags[]1
POST /v1/document/mrzpassport / ID MRZ parse + per-field checksum verification1
POST /v1/document/idUS/CA driver's license & state-ID PDF417 barcode → parsed AAMVA identity + expiry / age checks2
POST /v1/validate/identityAadhaar / PAN / voter / DL format + checksum validation1
POST /v1/validate/contactemail + phone validation (disposable check, normalization)1
POST /v1/workflow/runrun many checks in one call (liveness, face_match, mrz, aml, device) → aggregate verdict3
POST /v1/face/enrolladd a subject to your tenant's 1:N gallery (optional blocklisted=true)1
POST /v1/face/search1:N search against the gallery → top matches + blocklist_hit1

POST /v1/document/id decodes the PDF417 barcode on the back of a US or Canadian driver's license / state ID and parses its AAMVA payload (versions 01–10) into structured identity fields plus expiry and underage checks. Send back (barcode side) and/or front (portrait side) — the front adds a face-presence check and document forensics. A back image without a readable barcode is not an error: the call returns 200 with checks.barcode_decoded: false and a BARCODE_UNREADABLE warning.

document-id.sh
$ curl -X POST https://liveliness.neetix.in/v1/document/id \
    -H "Authorization: Bearer $LIVELINESS_API_KEY" \
    -F "back=@license-back.jpg" \
    -F "front=@license-front.jpg"

{
  "status": "success",
  "aamva": {
    "version": 8, "issuer_id": "636014", "doc_type": "DL",
    "first_name": "JANE", "middle_name": "MARIE", "last_name": "SAMPLE",
    "dob": "1986-06-06", "expiry": "2031-06-06", "issue_date": "2015-08-24",
    "license_number": "D12345678",
    "address": { "street": "1234 MAIN STREET", "city": "SACRAMENTO",
                 "state": "CA", "postal": "958180000" },
    "sex": "female", "height": 173, "eye_color": "GRN",
    "country": "USA", "real_id_compliant": null
  },
  "face_found": true,
  "forensics": { "screen_replay_score": 8.5, "synthetic_score": 0.0,
                 "high_freq_ratio": 0.31, "spectral_peak": 12.4 },
  "checks": { "barcode_decoded": true, "aamva_parsed": true,
              "expired": false, "underage_18": false, "underage_21": false,
              "dates_valid": true },
  "warnings": []
}

The gallery is tenant-scoped by API key. Face-match automatically searches it to raise DUPLICATED_FACE and FACE_IN_BLOCKLIST on repeat or blocklisted faces.

06

Billing & credits

Prepaid credits, an append-only ledger, and hosted top-up checkout.

GET/v1/billing/balance
GET/v1/billing/ledger?limit=100
GET/v1/billing/packs
POST/v1/billing/topup
billing.sh
$ curl https://liveliness.neetix.in/v1/billing/balance \
    -H "Authorization: Bearer $LIVELINESS_API_KEY"

{ "status": "success", "client_id": "a1b2c3d4e5f6a7b8", "balance": 431, "metered": true }

$ curl "https://liveliness.neetix.in/v1/billing/ledger?limit=100" \
    -H "Authorization: Bearer $LIVELINESS_API_KEY"

{
  "status": "success",
  "client_id": "a1b2c3d4e5f6a7b8",
  "balance": 431,
  "entries": [
    { "delta": -2,  "balance_after": 431, "reason": "charge:face_match",
      "ref_id": "018f6a2e-…-v7", "created_at": "2026-08-10T09:14:02Z" },
    { "delta": 1000, "balance_after": 1000, "reason": "signup_bonus",
      "ref_id": null, "created_at": "2026-08-09T18:30:11Z" }
  ]
}

Ledger reason values: signup_bonus, charge:<endpoint>, topup:dodo, refund:<endpoint>, refund:dodo. When the balance runs out, billable calls return 402 with message_code: "insufficient_credits" — handle it like a quota error.

Top-ups rolling out

GET /v1/billing/packs may return an empty list while top-ups are being enabled, and POST /v1/billing/topup returns 400 bad_request. Need more credits now? Contact us.

Once enabled, POST /v1/billing/topup with { "pack": "starter", "email": "billing@co.com" } returns { checkout_url, session_id, credits, pack }. Open checkout_url — a Dodo Payments hosted checkout with UPI, cards and PayPal. Credits are granted when the payment settles (Indian UPI and cards can take up to ~48 h) — poll the balance or watch the ledger for a topup:dodo entry.

CheckCredits per call
face_match2
session_verify2
kyb_validate2
document_id2
workflow_run3
stream_start5
All other checks1

07

Errors

Every error is JSON with a stable machine-readable message_code.

error envelope
{
  "statusCode": 402,
  "message": "Insufficient credits. Top up to continue.",
  "message_code": "insufficient_credits"
}
message_codeHTTPMeaning
bad_request400malformed body, or the feature is disabled (e.g. top-ups)
unauthorized401missing or invalid Authorization: Bearer key
insufficient_credits402prepaid balance exhausted — top up to continue
payload_too_large413an uploaded image exceeds the 5 MB limit
no_face_detected422no usable face found in the submitted image(s)
rate_limited429too many requests — back off and retry

Exception: the face-match no-face case also ships the Digitap-compatible fail envelope (status: "fail" + an error string) so existing Digitap integrations keep working unchanged.

08

Webhooks & signing

Verify that results really came from us — on both the response and the webhook path.

When signing is enabled, every verification response carries an X-Neetix-Signature header — an Ed25519 signature over the exact response bytes. Fetch the public key from GET /v1/verification-key, pin it, and verify the signature before parsing the body.

Results can also be mirrored to your endpoint as signed webhooks: each result is POSTed with an X-Signature-V2: sha256=<hex> header — an HMAC-SHA256 of the raw body using your webhook secret. Recompute it and compare in constant time before trusting the payload.

signature-headers
# fetch the Ed25519 verification key once and pin it
$ curl https://liveliness.neetix.in/v1/verification-key

# then, on traffic from us:
X-Neetix-Signature: <base64 Ed25519 signature over the exact response bytes>
X-Signature-V2:     sha256=<hex HMAC-SHA256(webhook_secret, raw_body)>

09

SDKs

The REST API is the stable contract. Client SDKs wrap the same endpoints and are pre-release.

Every SDK wraps the same HTTPS + JSON contract documented above, including the Digitap-compatible face-match envelope. Client SDKs are pre-release — interfaces may change before 1.0. If you don't want to ship one, the REST API and the hosted capture page at GET /capture cover the full flow.

REST

Stable

https://liveliness.neetix.in/v1

Plain HTTPS + JSON — the contract every SDK wraps.

Web / TypeScript

Pre-release

@neetix/liveliness-web

Typed client with browser camera capture.

React Native

Pre-release

@neetix/liveliness-react-native

Hooks and capture for iOS and Android apps.

Flutter

Pre-release

neetix_liveliness

Dart client with platform camera integration.

Swift (iOS)

Pre-release

NeetixLiveliness

Swift Package Manager library for native iOS.

Kotlin (Android)

Pre-release

in.neetix.liveliness

Kotlin module for native Android capture and checks.

Get started

Start with 1,000 free credits

POST /v1/signup with an email returns your API key — shown once. Checks cost 1–5 credits each.