📘 Public beta · Endpoints are stable; OpenAPI specs and SDKs ship monthly. See changelog →
Products
Identity Platform
KTP capture

KTP capture

The KTP (Kartu Tanda Penduduk) is the Indonesian national ID card. Identity Platform supports capturing it via SDK or raw API. Two endpoints are involved:

  1. Flash challenge — single-use color sequence the SDK shows during capture.
  2. Capture submit — bundle of frames + OCR + sensor data.

Issue a flash challenge

POST/api/identity/document/ktp/challenge
Auth · API keyScope · verifications:viewRate limit · 30/min

Request

customerIdstringRequired
CUID of the customer being verified.
stepsinteger
Number of color steps in the challenge (3–10).
Example: 5
ttlMsinteger
Time-to-live in milliseconds. Range 15000–300000.
Example: 90000

Response

{
  "flashChallenge": {
    "id": "fc_01HXY...",
    "purpose": "ktp",
    "nonce": "9f8e7d6c-...",
    "colors": ["#FF0000", "#00FF00", "#0000FF", "#FFFFFF", "#000000"],
    "holdMs": [500, 300, 400, 500, 400],
    "expiresAt": "2026-05-24T08:15:52.481Z",
    "hmacSecret": "qe_whsec_..."
  }
}

The challenge can only be consumed once. The hmacSecret is used by web SDKs to sign the eventual capture bundle. Native SDKs derive their own signing key from a device-provisioned secret.

Submit a capture

POST/api/identity/document/ktp/capture
Auth · API keyScope · verifications:viewRate limit · 20/min

Bundle shape

Top-level

customerIdstringRequired
CUID of the customer.
bundleobjectRequired
The signed capture bundle (see below).
hmacKeystring
HMAC signing key (web SDKs derive from flashChallenge.hmacSecret; native SDKs use a device-provisioned key).

bundle

versionstringRequired
Bundle schema version. Current: "1.0".
sdkVersionstringRequired
SDK identifier + version, e.g. "qe-identity-sdk-rn@0.1.0".
platformstringRequired
rn-ios · rn-android · ios · android · flutter · web
framesstring[]Required
Base64-encoded JPEG or PNG frames. 1 frame minimum. Each frame ≤ 12 MB after base64.
capturedAtstring (ISO-8601)Required
Wall-clock time when the bundle was captured.
signaturestringRequired
HMAC-SHA256 of the canonical bundle JSON, signed with hmacKey.
flashChallengeNoncestring
Echo of the nonce from the flash challenge. Required for "high" assurance tier.
flashSamplesobject[]
Per-step mean RGB samples from the front-facing camera. Used to verify the screen actually flashed the challenge colors.
ocrFieldsobject
Client-side OCR results. Use this when your SDK has on-device OCR; we re-verify server-side.
ocrConfidenceobject
Per-field confidence scores (0–1) for ocrFields.

Response

{
  "verification": {
    "id": "ver_01HXY...",
    "status": "verified | failed | pending",
    "score": 87
  },
  "ktpBundle": {
    "id": "ktpb_01HXY...",
    "verdict": "passed | failed | requires_review",
    "assuranceTier": "high | standard | low",
    "framesStored": 1
  },
  "antiSpoof": {
    "fused": "live | spoof | unclear",
    "assuranceTier": "high | standard | low",
    "voters": [{ "name": "flash_reflectance", "passed": true }, ...],
    "passed": 4,
    "present": 6
  },
  "tamper": {
    "fused": "authentic | tampered | unclear",
    "voters": [
      { "name": "nik_consistency", "passed": true,  "reason": "checksum ok" },
      { "name": "font_match",      "passed": true,  "reason": "Arial Latin Indonesian" },
      { "name": "hologram_check",  "passed": false, "reason": "no reflective specular ring" }
    ]
  },
  "faceEnrolment": {
    "id": "fe_01HXY...",
    "fallbackStub": false,
    "modelId": "qe-face-v3"
  }
}

Assurance tiers

TierRequires
highFlash challenge satisfied + anti-spoof and tamper both pass
standardAnti-spoof pass + tamper pass, no flash challenge (e.g. older SDK or web fallback)
lowOne or both fused checks failed — bundle is persisted for analyst review, not auto-trusted

A high or standard outcome bumps the customer's KYC tier to standard. A low outcome creates the verification but does not move the tier; an analyst can override via the dashboard.

OCR fields we extract

The KTP has 16 standard fields. Identity Platform extracts and validates:

FieldOCRValidated against
nikYesProvince · regency · gender · DOB consistency (NIK is structured)
fullNameYesLatin or Arabic-Latin only
placeOfBirthYes
dateOfBirthYesCross-checked with nik
genderYesCross-checked with nik
bloodTypeYes
addressYes
rtRwYesFormat NNN/NNN
kelurahanYes
kecamatanYes
religionYesEnum (Islam, Kristen, …)
maritalStatusYesEnum
occupationYes
nationalityYesEnum (WNI · WNA)
validUntilYesDate or "SEUMUR HIDUP"
issueDateYes

Failure modes

Common reasons a capture lands in `requires_review`

  • Glare on the laminate hiding the hologram (hologram_check fails).
  • Photocopy or scan instead of original KTP (specular_check fails).
  • NIK checksum doesn't match birth date or gender (nik_consistency fails).
  • Screen-capture replay attack (screen_moire detects display-emitted moiré pattern).
  • Camera flash mode disabled — flash samples can't validate the challenge colors.

A requires_review bundle is fully persisted (frames sealed at rest, embeddings stored, voters recorded). Your analyst override from the dashboard creates a new verification row marked actorUserId = <analyst> and bumps the tier appropriately.