Bangun dengan Zoi ID
Dua API di satu host, klien bertipe dalam enam bahasa, alur terhosting, dan sandbox. Panduan lengkap sudah bisa dibaca, dan kunci sandbox diberikan bersama akses awal.
Base URLhttps://kyc.zoi.network
Mulai cepat
- 1
Buat sesi
Backend Anda memanggil
POST /v1/partner/sessionsdengan kunci mitra Anda. - 2
Jalankan alur
Berikan token klien ke SDK, atau buka
verificationUrldi browser. - 3
Terima hasilnya
Periksa tanda tangan webhook, lalu simpan ID identitas dan statusnya.
curl https://kyc.zoi.network/v1/partner/sessions \
-H "Authorization: Bearer $ZOI_ID_PARTNER_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: signup-user_42" \
-d '{ "externalUserId": "user_42", "level": "standard", "appId": "com.example.app" }'Dua API
API mitra
Server ke server, di bawah /v1/partner. Kirim kunci mitra Anda sebagai token Bearer. Jangan pernah menaruhnya di aplikasi.
API klien
Dipakai oleh SDK, di bawah /v1/client. SDK mengirim token klien yang berlaku untuk satu sesi selama 60 menit.
Konvensi
- Waktu ditulis dalam milidetik epoch, di field yang namanya berakhir dengan
At. - Tanggal ditulis
YYYY-MM-DD. Bagian yang tidak diketahui ditulisXX, misalnya1990-XX-XX. - Request POST yang membuat atau memutuskan sesuatu menerima header
Idempotency-Key. Kunci disimpan selama 24 jam. - Perubahan pada sesi mengirim revisi yang diharapkan. Jika revisinya sudah berubah, Anda mendapat
revision_conflict.
Alur sesi
Backend Anda membuat sesi. SDK menjalankan langkah-langkahnya. Server memeriksa urutan dan menjawab step_not_allowed jika suatu langkah datang terlalu cepat.
1. Buat sesi dari backend Anda
Memanggilnya lagi untuk pengguna yang sama akan melanjutkan sesi yang terbuka dan memberi token klien baru.
POST /v1/partner/sessions
Authorization: Bearer <partner key>
Content-Type: application/json
Idempotency-Key: 6f1c2a9e-signup-42
{
"externalUserId": "user_42",
"level": "standard",
"locale": "en",
"appId": "com.example.app"
}
200 OK
{
"sessionId": "ses_...",
"clientToken": "...",
"clientTokenExpiresAt": 1767225600000,
"status": "created",
"apiBaseUrl": "https://kyc.zoi.network",
"resumed": false
}2. Langkah yang dijalankan SDK
- 01
Membaca sesi dan langkah yang masih diperlukan.
GET /v1/client/session
- 02
Mencatat persetujuan, termasuk pilihan terpisah dan opsional untuk perbandingan wajah.
POST /v1/client/consent
- 03
Memeriksa aplikasi dan perangkat. Hasilnya menjadi bagian dari keputusan.
POST /v1/client/attestation/challenge, POST /v1/client/attestation
- 04
Mengirim dokumen: membaca chip setelah memindai MRZ, atau mengirim foto.
POST /v1/client/document/mrz-scan, POST /v1/client/document/chip/challenge, POST /v1/client/document/chip or POST /v1/client/document/photos
- 05
Merekam satu video singkat dengan kamera depan sambil aplikasi menampilkan gerakan kepala.
POST /v1/client/liveness/challenge, POST /v1/client/liveness
- 06
Mengirim negara tempat tinggal, dan alamat di level lanjutan.
POST /v1/client/profile
- 07
Hanya dengan requirement alamat: mengunggah dokumen, lalu mengonfirmasi alamat. Dilewati bila dokumen identitas sudah memberikan alamat.
POST /v1/client/address/document, POST /v1/client/address/confirm
- 08
Hanya dengan requirement dana: menyimpan jawaban, menambahkan dokumen bila kebijakan memintanya, lalu menyelesaikan langkah.
POST /v1/client/funds/answers, POST /v1/client/funds/document, POST /v1/client/funds/remove, POST /v1/client/funds/complete
- 09
Menjawab dua pertanyaan: orang yang terpapar politik, dan bertindak atas nama sendiri.
POST /v1/client/declarations
- 10
Mengirim dengan revisi saat ini.
POST /v1/client/submit
Pengguna juga bisa meminta petugas meninjau hasil otomatis (POST /review-request) atau menarik persetujuan, yang membatalkan sesi dan langsung menghapus file-nya (POST /withdraw).
Bukti alamat dan sumber dana
Tambahkan requirements ke POST /v1/partner/sessions untuk memverifikasi lebih dari sekadar identitas. address meminta bukti alamat. source_of_funds menanyakan asal uang, dan source_of_wealth juga menanyakan total kekayaan serta cara memperolehnya. Kedua nilai dana itu bersama-sama menjadi satu langkah, dan keduanya bisa digabung dengan address.
POST /v1/partner/sessions
Authorization: Bearer <partner key>
Content-Type: application/json
{
"externalUserId": "user_42",
"level": "standard",
"appId": "com.example.app",
"requirements": ["address", "source_of_funds"],
// Optional. Without them your partner default applies, else ours.
"addressPolicy": { "maxAgeDays": 90, "signedOnly": false },
"fundsPolicy": { "evidence": "optional", "currency": "EUR" }
}Kebijakan opsional
Tanpa kebijakan, default mitra Anda yang berlaku, jika tidak ada, default kami. Kebijakan disalin ke sesi saat sesi dibuat.
addressPolicy:maxAgeDays(default 90, 1 sampai 366),acceptedTypes(default: dokumen utilitas, telekomunikasi, dan bank, dokumen pajak, surat instansi pemerintah, dan surat keterangan domisili) dansignedOnly(default false).fundsPolicy:questions,evidence(none,optional, ataurequired, defaultnone),acceptedTypes,maxAgeDays(default 180),currency(ISO 4217, default USD) danbracketsuntuk rentangnya.- Sesi terbuka dengan requirement lain yang belum dikirim akan dibatalkan dan sesi baru dimulai, sama seperti saat level berubah.
- Uji setiap hasil dengan skenario sandbox seperti
address_signed_pdf,address_document_review,funds_signed_documents, danfunds_review.
Sesi lanjutan
Verifikasi hanya requirement-nya untuk pengguna yang identitasnya sudah aktif di layanan Anda. Kirim reuseIdentity: true bersama requirements.
- Pengguna memberi persetujuan dan hanya menyelesaikan langkah baru. Dokumen, selfie, atau pernyataan tidak diminta lagi.
- Saat disetujui, identitas tetap memakai ID, tanggal verifikasi, dan masa berlakunya, lalu mendapat hasil baru. Anda menerima
session.approveddanidentity.updated. - Tanpa identitas aktif, panggilan menjawab 409
step_not_allowed. - Mulai dari aturan risiko Anda sendiri, misalnya setoran besar, tanda PEP, atau negara berisiko. Aturan Anda tetap di backend Anda, di satu tempat.
POST /v1/partner/sessions
Authorization: Bearer <partner key>
Content-Type: application/json
Idempotency-Key: edd-user_42-2026-11
{
"externalUserId": "user_42",
"appId": "com.example.app",
"requirements": ["source_of_funds", "source_of_wealth"],
"reuseIdentity": true,
"fundsPolicy": { "evidence": "required" }
}
// No active identity for user_42:
409 { "error": { "code": "step_not_allowed", ... } }Hasil dan cakupan
Sesi yang disetujui membawa address dan funds, dan identitas menyimpan yang terbaru dari masing-masing. Kolom ringkasan tersedia di setiap cakupan. Detailnya memerlukan cakupan.
- Cakupan
address: baris alamat. Tanpa cakupan ini, Anda mendapatverified,method,evidenceLevel,documentType,documentDate,verifiedAt, dancountry. - Cakupan
financial_data:answers,documents, danfindings. Tanpa cakupan ini, Anda mendapatkinds,evidenceLevel,reviewed,documentCount, danverifiedAt. Tidak pernah menjadi bagian darieligibility. evidenceLevelbernilaihigh,medium,low, ataunone. Metode alamat, dari yang terkuat:wallet,id_document,signed_pdf,official_code,document_review, dandeclared.- Dokumen tidak dikirim lewat API. Anggota dengan peran kepatuhan bisa melihat halaman dokumen sumber dana di dasbor bila environment memiliki cakupan
financial_data. Setiap tampilan dicatat.
"session": {
"id": "ses_...",
"status": "approved",
"requirements": ["address", "source_of_funds"],
"reusesIdentity": false,
"address": {
"verified": true,
"method": "signed_pdf",
"evidenceLevel": "high",
"documentType": "bank_statement",
"documentDate": "2026-10-14",
"verifiedAt": 1767225600000,
"country": "DE",
// scope "address"
"address": { "line1": "Musterstrasse 12", "city": "Berlin", "postalCode": "10115", "country": "DE" }
},
"funds": {
"kinds": ["source_of_funds"],
"evidenceLevel": "medium",
"reviewed": true,
"documentCount": 2,
"verifiedAt": 1767225600000,
// scope "financial_data"
"answers": {
"employmentStatus": "employed",
"income": { "min": 50000, "max": 100000, "currency": "EUR" },
"sources": ["salary", "savings"],
...
},
"documents": [
{ "documentType": "payslip", "documentDate": "2026-10-31", "amount": 5200, "currency": "EUR",
"signature": "valid", "signedByKnownIssuer": true, "nameMatch": "match", "findings": [], ... },
...
],
"findings": []
}
}Alur web
Tidak memakai SDK? Arahkan pengguna ke halaman yang kami sediakan. Halaman ini memakai API, pemeriksaan, dan antrean peninjauan yang sama.
1. Dapatkan tautannya
POST /v1/partner/sessions mengembalikan verificationUrl. Kirim redirectUrl agar pengguna kembali ke Anda saat selesai. URL itu harus diawali salah satu origin pengalihan yang sudah Anda daftarkan.
POST /v1/partner/sessions
Authorization: Bearer <partner key>
Content-Type: application/json
{
"externalUserId": "user_42",
"level": "standard",
"locale": "en",
"appId": "com.example.app",
"redirectUrl": "https://example.com/kyc/done"
}
200 OK
{
"sessionId": "ses_...",
"clientToken": "...",
"verificationUrl": "https://kyc.zoi.network/verify/#token=...&lang=en",
...
}- Token klien ada di fragmen URL, setelah
#. Browser tidak pernah mengirim fragmen ke server, jadi token tidak masuk log atau headerReferer. Halaman membacanya, menghapusnya dari bilah alamat, dan hanya menyimpannya di memori. - Tambahkan
langke fragmen untuk memilih salah satu dari 19 bahasa. Tanpa itu, halaman memakai bahasa browser. - Memuat ulang halaman menghilangkan token. Buat tautan baru untuk sesi yang sama dari backend Anda.
- Halaman mengirim
channel: "web"bersama persetujuan. Browser tidak bisa membaca chip dokumen identitas, jadi sesi web memakai foto dokumen atau dompet ID digital. Sesi ini melewati pemeriksaan perangkat, dan foto dokumen dari web selalu diputuskan oleh pemeriksa terlatih. - Di komputer, halaman menampilkan kode QR agar pengguna bisa melanjutkan di ponsel.
2. Saat pengguna selesai
Saat alur berakhir (terkirim, dibatalkan, atau status akhir), halaman mengirim pesan ini ke setiap objek berikut yang ada: window.ReactNativeWebView, window.webkit.messageHandlers.zoiId, window.ZoiIdAndroid, dan window.opener. Lalu halaman membuka redirectUrl dengan tambahan zoiIdSession dan zoiIdStatus.
Jangan pernah memercayai pesan atau parameter pengalihan. Percayai hanya webhook Anda atau GET /v1/partner/sessions/:id.
// Sent to each bridge that exists:
// window.ReactNativeWebView.postMessage(JSON string)
// window.webkit.messageHandlers.zoiId.postMessage(object)
// window.ZoiIdAndroid.postMessage(JSON string)
// window.opener.postMessage(object, "<origin of your redirectUrl>")
// (popups only, and only when the session has a redirectUrl)
{
"source": "zoi-id",
"type": "finished", // or "cancelled"
"sessionId": "ses_...",
"status": "processing" // the session status at that moment
}
// Then, if redirectUrl was set (the page uses the one stored with the
// session, never one from the address bar):
https://example.com/kyc/done?zoiIdSession=ses_...&zoiIdStatus=processing3. Pengaturan webview
Android WebView
Aktifkan javaScriptEnabled dan domStorageEnabled, lalu setel mediaPlaybackRequiresUserGesture ke false. Di WebChromeClient, izinkan onPermissionRequest untuk RESOURCE_VIDEO_CAPTURE setelah aplikasi Anda punya izin CAMERA. Tambahkan pemilih file untuk cadangan foto.
webView.settings.javaScriptEnabled = true
webView.settings.domStorageEnabled = true
webView.settings.mediaPlaybackRequiresUserGesture = false
webView.webChromeClient = object : WebChromeClient() {
override fun onPermissionRequest(request: PermissionRequest) {
// Only after your app holds Manifest.permission.CAMERA.
if (request.resources.contains(PermissionRequest.RESOURCE_VIDEO_CAPTURE)) {
request.grant(arrayOf(PermissionRequest.RESOURCE_VIDEO_CAPTURE))
} else {
request.deny()
}
}
override fun onShowFileChooser(
view: WebView, callback: ValueCallback<Array<Uri>>, params: FileChooserParams,
): Boolean {
// Open a picker and pass the result to callback (photo fallback).
return true
}
}iOS WKWebView
iOS 14.3 atau lebih baru. Setel allowsInlineMediaPlayback ke true dan tambahkan NSCameraUsageDescription ke aplikasi Anda. Di iOS 15 ke atas, Anda bisa memutuskan izin kamera di UI delegate.
let config = WKWebViewConfiguration()
config.allowsInlineMediaPlayback = true
let webView = WKWebView(frame: .zero, configuration: config)
webView.uiDelegate = self // iOS 15+: decide camera access below
func webView(_ webView: WKWebView,
requestMediaCapturePermissionFor origin: WKSecurityOrigin,
initiatedByFrame frame: WKFrameInfo,
type: WKMediaCaptureType,
decisionHandler: @escaping (WKPermissionDecision) -> Void) {
decisionHandler(origin.host == "kyc.zoi.network" ? .grant : .deny)
}
// Info.plist: NSCameraUsageDescriptionReact Native WebView
Setel mediaCapturePermissionGrantType="grant", allowsInlineMediaPlayback, dan javaScriptEnabled. Aplikasi Anda perlu izin kamera.
<WebView
source={{ uri: verificationUrl }}
javaScriptEnabled
allowsInlineMediaPlayback
mediaCapturePermissionGrantType="grant"
onMessage={(event) => {
const message = JSON.parse(event.nativeEvent.data);
if (message.source === "zoi-id") {
// Close the webview, then ask your backend for the real status.
}
}}
/>iframe tidak didukung, karena izin kamera dan clickjacking. Gunakan tab browser, popup, atau webview.
Status
Sesi
created- Sesi sudah ada, belum ada yang diunggah.
in_progress- Persetujuan sudah diberikan, langkah sedang diunggah.
processing- Sudah dikirim, pemeriksaan sedang berjalan.
review- Menunggu pemeriksa terlatih.
approved- Final. Identitas terverifikasi.
rejected- Final. Lihat kode alasan.
resubmit- Pengguna harus mengulang langkah di requiredSteps.
expired- Tidak ada keputusan final tepat waktu.
cancelled- Dibatalkan oleh mitra, pengguna, atau penghapusan.
Identitas
active- Bisa dipakai.
suspended- Ditahan, misalnya setelah ada kandidat sanksi baru.
expired- Masa berlaku dokumen atau verifikasi sudah habis. Sesi baru akan memverifikasi ulang.
revoked- Final.
SDK
SDK React Native (Expo) memberi Anda klien API bertipe, pembacaan chip lewat NFC, dan pemeriksaan perangkat. SDK ini headless, jadi aplikasi Anda tetap memegang kendali penuh atas layar dan kameranya. Untuk server Anda, pakai klien bertipe untuk TypeScript, Python, Go, PHP, Java, dan Ruby.
import { ZoiIdClient, nextStep } from "@zoi/id-sdk";
// clientToken and apiBaseUrl come from your backend (POST /v1/partner/sessions).
const client = new ZoiIdClient({ baseUrl: apiBaseUrl, clientToken });
const session = await client.getSession();
switch (nextStep(session)) {
case "consent": /* show the notice and the biometric choice */ break;
case "document": /* chip read or photos */ break;
case "liveness": /* record the video */ break;
case "address": /* upload a document, then confirm the address */ break;
case "funds": /* answers, then documents when the policy asks */ break;
case "submit": await client.submit(session.revision); break;
case "done": /* wait for your backend to get the webhook */ break;
}Webhook
Kami mengirim webhook saat sesi atau identitas berubah. Selalu periksa tanda tangannya sebelum memercayai isinya.
- Setiap webhook membawa header
Zoi-Id-Signature:t=unix seconds,v1=hex. v1adalah HMAC-SHA256 dari tekst.raw bodydengan secret webhook Anda. Pakai body mentah, sebelum JSON diurai.- Saat secret sedang diganti, header membawa satu
v1untuk setiap secret aktif. Terima webhook jika salah satunya cocok. - Tolak jika
tberselisih lebih dari 300 detik dari sekarang. - Pengiriman yang gagal diulang selama 72 jam. Setiap pengulangan ditandatangani lagi dengan
tbaru. - Identitas membawa
revision. Terapkan peristiwa hanya jika revisinya lebih baru dari yang Anda simpan.
POST <your webhook URL>
Zoi-Id-Signature: t=1767225600,v1=5f2b...e9
{
"v": 1,
"eventId": "evt_...",
"type": "identity.suspended",
"createdAt": 1767225600000,
"object": "identity",
"externalUserId": "user_42",
"identity": {
"identityId": "idn_...",
"revision": 7,
"status": "suspended",
"level": "standard",
"verifiedAt": 1764547200000,
"validUntil": 1859155200000,
"ageOver18": true,
"captureMethod": "nfc"
}
}Jenis peristiwa
session.processingsession.reviewsession.approvedsession.rejectedsession.resubmitsession.expiredsession.cancelledidentity.updatedidentity.suspendedidentity.reinstatedidentity.expiredidentity.revoked
Periksa tanda tangan di TypeScript
import { createHmac, timingSafeEqual } from "node:crypto";
const TOLERANCE_SECONDS = 300;
export function verifyZoiIdSignature(
rawBody: string,
header: string | null,
secret: string,
nowSeconds = Math.floor(Date.now() / 1000),
): boolean {
if (!header) return false;
let t: string | undefined;
const signatures: Buffer[] = [];
for (const part of header.split(",")) {
const [key, value] = part.trim().split("=");
if (!value) continue;
if (key === "t") t = value;
if (key === "v1" && /^[0-9a-f]+$/i.test(value)) signatures.push(Buffer.from(value, "hex"));
}
if (!t || !/^\d+$/.test(t) || signatures.length === 0) return false;
if (Math.abs(nowSeconds - Number(t)) > TOLERANCE_SECONDS) return false;
const expected = createHmac("sha256", secret).update(`${t}.${rawBody}`).digest();
return signatures.some((sig) => sig.length === expected.length && timingSafeEqual(sig, expected));
}
// Example handler: read the raw body first, parse JSON only after the check.
export async function POST(request: Request) {
const rawBody = await request.text();
const ok = verifyZoiIdSignature(rawBody, request.headers.get("Zoi-Id-Signature"), process.env.ZOI_ID_WEBHOOK_SECRET!);
if (!ok) return new Response("bad signature", { status: 400 });
const event = JSON.parse(rawBody);
// Store event.eventId to skip duplicates, then apply it if the revision is newer.
return new Response(null, { status: 204 });
}Periksa tanda tangan di Go
package zoiid
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"strconv"
"strings"
"time"
)
const toleranceSeconds = 300
// VerifySignature checks the Zoi-Id-Signature header against the raw body.
func VerifySignature(rawBody []byte, header, secret string, now time.Time) bool {
var t string
var sigs [][]byte
for _, part := range strings.Split(header, ",") {
key, value, ok := strings.Cut(strings.TrimSpace(part), "=")
if !ok || value == "" {
continue
}
switch key {
case "t":
t = value
case "v1":
if b, err := hex.DecodeString(value); err == nil {
sigs = append(sigs, b)
}
}
}
ts, err := strconv.ParseInt(t, 10, 64)
if err != nil || len(sigs) == 0 {
return false
}
if d := now.Unix() - ts; d > toleranceSeconds || d < -toleranceSeconds {
return false
}
mac := hmac.New(sha256.New, []byte(secret))
mac.Write([]byte(t + "."))
mac.Write(rawBody)
expected := mac.Sum(nil)
for _, sig := range sigs {
if hmac.Equal(sig, expected) {
return true
}
}
return false
}Feed peristiwa
GET /v1/partner/events mengembalikan semua peristiwa 30 hari terakhir, dari yang paling lama. Kirim after dengan nextCursor terakhir untuk membaca halaman berikutnya. Gunakan setelah gangguan panjang, atau untuk memastikan tidak ada yang terlewat.
GET /v1/partner/events?after=<nextCursor>&limit=100
Authorization: Bearer <partner key>
200 OK
{
"items": [ /* webhook payloads, oldest first */ ],
"nextCursor": "..." // null when there is nothing more
}Laporan penipuan
Beri tahu kami bila sesi yang sudah diputuskan ternyata penipuan, misalnya setelah chargeback. Laporan membantu kami mengukur persetujuan yang keliru. Laporan tidak mengubah sesi, identitas, atau hasil pengguna.
- Cakupan
sessions:write. Hanya untuk sesi yang sudah diputuskan (disetujui atau ditolak). Sebelum ada keputusan, panggilan menjawab 409. - Body kosong melaporkan
confirmed_frauddengan kategoriother.statusjuga bisasuspected_fraud, ataucleareduntuk menarik kembali laporan Anda sendiri. - Kategori:
forged_document,impostor,deepfake_or_replay,synthetic_identity,account_takeover, danother. Tidak ada kategori untukcleared. noteadalah teks bebas untuk analis kami, maksimal 1000 karakter. Jangan pernah mengisinya dengan nama, nomor dokumen, atau data pribadi lainnya.- Laporan baru menjawab 201. Laporan yang sama bila dikirim lagi mengembalikan laporan tersimpan dengan 200. Kirim
Idempotency-Keyagar aman saat mencoba ulang. Maksimal 20 laporan per sesi. - Laporan yang sama bisa dibuat dengan satu klik di halaman sesi pada dasbor.
POST /v1/partner/sessions/ses_.../fraud-reports
Authorization: Bearer <partner key>
Content-Type: application/json
Idempotency-Key: chargeback-8812
{
"status": "confirmed_fraud",
"category": "impostor",
"note": "Chargeback on the first deposit"
}
201 Created
{
"id": "flb_...",
"sessionId": "ses_...",
"status": "confirmed_fraud",
"category": "impostor",
"noteKept": true,
"createdAt": 1767225600000
}Penghapusan
DELETE /v1/partner/users/:externalUserId menghapus data pengguna saat ia menutup akun atau meminta penghapusan. Jawabannya mencantumkan apa yang sudah dihapus sekarang, dan apa yang disimpan, alasannya, dan sampai kapan.
DELETE /v1/partner/users/user_42
Authorization: Bearer <partner key>
200 OK
{
"deleted": ["images", "chip_files", "video", "personal_data", "address"],
"retained": [
{ "category": "dedup_keys", "reason": "fraud_prevention", "until": 1924992000000 },
{ "category": "sanctions_screening_records", "reason": "legal_obligation", "until": 2082758400000 }
],
"backupsPurgedWithinDays": 30
}Error
Setiap error punya bentuk yang sama dan status HTTP tetap untuk setiap kode.
{
"error": {
"code": "step_not_allowed",
"message": "This step is not allowed now.",
"requestId": "req_..."
}
}| Kode | HTTP | Arti |
|---|---|---|
bad_request | 400 | Request tidak sesuai kontrak. |
unauthorized | 401 | Kunci atau token tidak ada atau salah. |
token_expired | 401 | Token klien sudah kedaluwarsa. Buat yang baru dari backend Anda. |
forbidden | 403 | Kunci ini tidak boleh melakukan ini. |
not_found | 404 | Sesi atau pengguna tersebut tidak ada. |
session_closed | 409 | Sesi sudah final. Tidak bisa unggah lagi. |
step_not_allowed | 409 | Urutan salah, atau langkah ini tidak diperlukan sekarang. |
revision_conflict | 409 | Revisi sesi sudah berubah. Baca ulang. |
idempotency_conflict | 409 | Idempotency-Key yang sama dipakai untuk request yang berbeda. |
challenge_expired | 410 | Tantangan sudah kedaluwarsa atau sudah dipakai. Minta yang baru. |
payload_too_large | 413 | Unggahan terlalu besar. |
unsupported_media_type | 415 | Jenis file tidak diterima. |
rate_limited | 429 | Terlalu banyak request. Coba lagi nanti. |
internal | 500 | Ada masalah di pihak kami. |
dependency_unavailable | 503 | Layanan yang kami butuhkan sedang tidak berjalan. Coba lagi nanti. |
Kode alasan
Sesi membawa reasonCodes saat perlu dikirim ulang atau ditolak. Tampilkan pesan terjemahan Anda sendiri untuk setiap kode. Jangan pernah menampilkan kode mentah kepada pengguna.
consent_missingconsent_withdrawnattestation_faileddocument_expireddocument_unreadabledocument_not_supporteddocument_suspected_tamperingdocument_number_visiblechip_verification_failedchip_proof_missingchip_data_mismatchmrz_invalidphoto_qualityface_not_foundface_mismatchliveness_failedunderagelocation_not_supportedresidence_not_supportedsanctions_matchpep_reviewduplicate_identitypossible_duplicatedeclaration_requires_reviewuser_requested_reviewreviewer_otheraddress_unreadableaddress_document_too_oldaddress_document_not_acceptedaddress_name_mismatchaddress_signature_requiredfunds_document_unreadablefunds_document_too_oldfunds_document_not_acceptedfunds_more_evidencefunds_evidence_rejected