İçeriğe geç
Zoi ID

Zoi ID ile geliştirin

Tek bir adreste iki API, altı dilde tipli istemciler, barındırılan bir akış ve bir sandbox. Kılavuzun tamamı okumaya açık, sandbox anahtarları erken erişimle gelir.

Temel URLhttps://kyc.zoi.network

Hızlı başlangıç

  1. 1

    Oturum oluşturun

    Sunucunuz, iş ortağı anahtarınızla POST /v1/partner/sessions çağrısı yapar.

  2. 2

    Akışı çalıştırın

    İstemci jetonunu SDK'ya verin veya verificationUrl adresini bir tarayıcıda açın.

  3. 3

    Sonucu alın

    Webhook imzasını kontrol edin, ardından kimlik numarasını ve durumunu saklayın.

shell
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" }'

İki API

İş ortağı API'si

Sunucudan sunucuya, /v1/partner altında. İş ortağı anahtarınızı Bearer jetonu olarak gönderin. Asla bir uygulamaya koymayın.

İstemci API'si

SDK tarafından, /v1/client altında kullanılır. Bir oturum için 60 dakika geçerli bir istemci jetonu gönderir.

Kurallar

  • Zamanlar epoch milisaniyedir ve adı At ile biten alanlardadır.
  • Tarihler YYYY-MM-DD biçimindedir. Bilinmeyen kısımlar XX olur, örneğin 1990-XX-XX.
  • Bir şey oluşturan veya karar veren POST istekleri Idempotency-Key başlığını kabul eder. Anahtarlar 24 saat tutulur.
  • Bir oturumdaki değişiklikler bekledikleri sürümü gönderir. Sürüm değiştiyse revision_conflict alırsınız.

Oturum akışı

Sunucunuz oturumu oluşturur. SDK adımları çalıştırır. Sunucu sırayı kontrol eder ve bir adım erken gelirse step_not_allowed döner.

1. Sunucunuzdan oturum oluşturun

Aynı kullanıcı için tekrar çağırırsanız açık oturum devam eder ve yeni bir istemci jetonu verilir.

POST /v1/partner/sessions
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. SDK'nın çalıştırdığı adımlar

  1. 01

    Oturumu ve hâlâ gereken adımları okur.

    GET /v1/client/session

  2. 02

    Yüz karşılaştırması için ayrı ve isteğe bağlı seçimle birlikte onayı kaydeder.

    POST /v1/client/consent

  3. 03

    Uygulamayı ve cihazı kontrol eder. Sonuç karara dahil edilir.

    POST /v1/client/attestation/challenge, POST /v1/client/attestation

  4. 04

    Belgeyi gönderir: MRZ taramasından sonra çipi okur ya da fotoğraf gönderir.

    POST /v1/client/document/mrz-scan, POST /v1/client/document/chip/challenge, POST /v1/client/document/chip or POST /v1/client/document/photos

  5. 05

    Uygulama baş hareketlerini gösterirken tek bir kısa ön kamera videosu kaydeder.

    POST /v1/client/liveness/challenge, POST /v1/client/liveness

  6. 06

    İkamet ülkesini, gelişmiş seviyede adresi de gönderir.

    POST /v1/client/profile

  7. 07

    Yalnızca adres gereksinimi varsa: bir belge yükler, ardından adresi onaylar. Kimlik belgesi adresi zaten verdiyse atlanır.

    POST /v1/client/address/document, POST /v1/client/address/confirm

  8. 08

    Yalnızca bir fon gereksinimi varsa: cevapları kaydeder, politika istediğinde belge ekler, ardından adımı tamamlar.

    POST /v1/client/funds/answers, POST /v1/client/funds/document, POST /v1/client/funds/remove, POST /v1/client/funds/complete

  9. 09

    İki soruyu cevaplar: siyasi nüfuz sahibi kişi mi ve kendi adına mı hareket ediyor.

    POST /v1/client/declarations

  10. 10

    Güncel sürümle gönderir.

    POST /v1/client/submit

Kullanıcı ayrıca otomatik bir sonucun bir kişi tarafından incelenmesini isteyebilir (POST /review-request) veya onayını geri çekebilir; bu, oturumu iptal eder ve dosyalarını hemen siler (POST /withdraw).

Adres doğrulama ve fon kaynağı

Kimliğin ötesini doğrulamak için POST /v1/partner/sessions isteğine requirements ekleyin. address adres doğrulaması ister. source_of_funds paranın nereden geldiğini sorar, source_of_wealth ise toplam serveti ve nasıl oluştuğunu da sorar. İki fon değeri birlikte tek bir adımdır ve ikisi de address ile birlikte kullanılabilir.

POST /v1/partner/sessions
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" }
}

İsteğe bağlı politikalar

Politika göndermezseniz iş ortağı varsayılanınız, o da yoksa bizimki geçerli olur. Politika, oturum oluşturulurken oturuma kopyalanır.

  • addressPolicy: maxAgeDays (varsayılan 90, 1 ile 366 arası), acceptedTypes (varsayılan: fatura, telekom ve banka belgeleri, vergi belgeleri, kamu kurumu yazıları ve ikametgah belgeleri) ve signedOnly (varsayılan false).
  • fundsPolicy: questions, evidence (none, optional veya required, varsayılan none), acceptedTypes, maxAgeDays (varsayılan 180), currency (ISO 4217, varsayılan USD) ve aralıklar için brackets.
  • Başka gereksinimlerle açılmış ve henüz gönderilmemiş bir oturum, seviye değişikliğinde olduğu gibi iptal edilir ve yenisi başlar.
  • Her sonucu address_signed_pdf, address_document_review, funds_signed_documents ve funds_review gibi sandbox senaryolarıyla test edin.

Takip oturumları

Kimliği sizde zaten aktif olan bir kullanıcı için yalnızca gereksinimleri doğrulayın. requirements ile birlikte reuseIdentity: true gönderin.

  • Kullanıcı onay verir ve yalnızca yeni adımları tamamlar. Belge, selfie veya beyanlar yeniden istenmez.
  • Onaylandığında kimlik, id'sini, doğrulama tarihini ve geçerliliğini korur ve yeni sonucu alır. Siz session.approved ve identity.updated alırsınız.
  • Aktif bir kimlik yoksa çağrı 409 step_not_allowed döner.
  • Büyük bir para yatırma işlemi, bir PEP işareti veya riskli bir ülke gibi kendi risk kurallarınıza göre başlatın. Kurallarınız sunucunuzda, tek bir yerde kalır.
POST /v1/partner/sessions
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", ... } }

Sonuçlar ve kapsamlar

Onaylanan oturumlar address ve funds taşır, kimlik de her birinin en güncelini saklar. Özet alanları her kapsamla gelir. Ayrıntılar için kapsam gerekir.

  • address kapsamı: adres satırları. Bu kapsam olmadan verified, method, evidenceLevel, documentType, documentDate, verifiedAt ve country alırsınız.
  • financial_data kapsamı: answers, documents ve findings. Bu kapsam olmadan kinds, evidenceLevel, reviewed, documentCount ve verifiedAt alırsınız. Hiçbir zaman eligibility içinde yer almaz.
  • evidenceLevel değeri high, medium, low veya none olur. En güçlüden başlayarak adres yöntemleri: wallet, id_document, signed_pdf, official_code, document_review ve declared.
  • Belgeler API üzerinden gönderilmez. Ortamda financial_data kapsamı varsa uyum rolüne sahip üyeler fon kaynağı belge sayfalarını panelde görüntüleyebilir. Her görüntüleme kaydedilir.
GET /v1/partner/sessions/:id
"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": []
  }
}

Web akışı

SDK kullanmıyor musunuz? Kullanıcıyı barındırdığımız sayfaya gönderin. Aynı API'yi, aynı kontrolleri ve aynı inceleme kuyruğunu kullanır.

1. Bağlantıyı alın

POST /v1/partner/sessions, verificationUrl döndürür. Kullanıcı bitirdiğinde geri göndermek için redirectUrl verin. Bu adres, kayıtlı yönlendirme kaynaklarınızdan biriyle başlamalıdır.

POST /v1/partner/sessions
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",
  ...
}
  • İstemci token'ı URL'nin fragment kısmındadır, # işaretinden sonra. Tarayıcılar fragment'i hiçbir sunucuya göndermez, bu yüzden token loglarda veya Referer başlığında yer almaz. Sayfa onu okur, adres çubuğundan siler ve yalnızca bellekte tutar.
  • 19 dilden birini seçmek için fragment'e lang ekleyin. Eklemezseniz sayfa tarayıcının dilini kullanır.
  • Sayfa yenilenirse token kaybolur. Aynı oturum için arka ucunuzdan yeni bir bağlantı oluşturun.
  • Sayfa, onayla birlikte channel: "web" gönderir. Tarayıcılar kimlik çiplerini okuyamaz, bu yüzden web oturumları belge fotoğraflarını veya bir dijital kimlik cüzdanını kullanır. Cihaz kontrolünü atlarlar ve webden gelen belge fotoğraflarına her zaman eğitimli bir inceleyici karar verir.
  • Bilgisayarda sayfa bir QR kodu gösterir, böylece kullanıcı telefonunda devam edebilir.

2. Kullanıcı bitirdiğinde

Akış bittiğinde (gönderildi, iptal edildi veya son bir duruma ulaştı) sayfa bu mesajı şunlardan var olan her birine gönderir: window.ReactNativeWebView, window.webkit.messageHandlers.zoiId, window.ZoiIdAndroid ve window.opener. Sonra zoiIdSession ve zoiIdStatus eklenmiş olarak redirectUrl adresini açar.

Mesaja veya yönlendirme parametrelerine asla güvenmeyin. Yalnızca webhook'unuza veya GET /v1/partner/sessions/:id yanıtına güvenin.

postMessage
// 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=processing

3. Webview ayarları

Android WebView

javaScriptEnabled ve domStorageEnabled ayarlarını açın, mediaPlaybackRequiresUserGesture değerini false yapın. Uygulamanız CAMERA iznini aldıktan sonra bir WebChromeClient içinde onPermissionRequest ile RESOURCE_VIDEO_CAPTURE iznini verin. Fotoğraf yedeği için bir dosya seçici ekleyin.

Kotlin
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 veya üstü. allowsInlineMediaPlayback değerini true yapın ve uygulamanıza NSCameraUsageDescription ekleyin. iOS 15 ve üstünde kamera iznine UI delegate içinde karar verebilirsiniz.

Swift
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: NSCameraUsageDescription

React Native WebView

mediaCapturePermissionGrantType="grant", allowsInlineMediaPlayback ve javaScriptEnabled ayarlayın. Uygulamanızın kamera izni olmalıdır.

TSX
<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.
    }
  }}
/>

Kamera izinleri ve clickjacking nedeniyle iframe desteklenmez. Bir tarayıcı sekmesi, bir açılır pencere veya bir webview kullanın.

Durumlar

Oturum

created
Oturum var, henüz bir şey yüklenmedi.
in_progress
Onay verildi, adımlar yükleniyor.
processing
Gönderildi, kontroller çalışıyor.
review
Eğitimli bir inceleyiciyi bekliyor.
approved
Son durum. Kimlik doğrulandı.
rejected
Son durum. Gerekçe kodlarına bakın.
resubmit
Kullanıcı requiredSteps içindeki adımları yeniden yapmalı.
expired
Zamanında son karar verilmedi.
cancelled
İş ortağı, kullanıcı veya silme işlemiyle iptal edildi.

Kimlik

active
Kullanılabilir.
suspended
Beklemede, örneğin yeni bir yaptırım adayından sonra.
expired
Belgenin veya doğrulamanın süresi bitti. Yeni bir oturum yeniden doğrular.
revoked
Son durum.

SDK

React Native (Expo) SDK'sı size tipli bir API istemcisi, NFC ile çip okuma ve cihaz kontrolleri verir. Headless çalışır, yani ekranların ve kameranın kontrolü tamamen uygulamanızda kalır. Sunucularınız için TypeScript, Python, Go, PHP, Java ve Ruby tipli istemcilerini kullanın.

@zoi/id-sdk
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'lar

Bir oturum veya kimlik değiştiğinde webhook göndeririz. İçeriğe güvenmeden önce her zaman imzayı kontrol edin.

  • Her webhook bir Zoi-Id-Signature başlığı taşır: t=unix seconds,v1=hex.
  • v1, t.raw body metninin webhook gizli anahtarınızla HMAC-SHA256 değeridir. JSON ayrıştırmadan önceki ham gövdeyi kullanın.
  • Bir gizli anahtar değiştirilirken başlık her etkin anahtar için bir v1 taşır. Herhangi biri eşleşirse webhook'u kabul edin.
  • t şimdiden 300 saniyeden fazla uzaksa reddedin.
  • Başarısız gönderimler 72 saat boyunca yeniden denenir. Her deneme yeni bir t ile yeniden imzalanır.
  • Kimlikler bir revision taşır. Bir olayı yalnızca sürümü sakladığınızdan yeniyse uygulayın.
identity.suspended
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"
  }
}

Olay türleri

  • session.processing
  • session.review
  • session.approved
  • session.rejected
  • session.resubmit
  • session.expired
  • session.cancelled
  • identity.updated
  • identity.suspended
  • identity.reinstated
  • identity.expired
  • identity.revoked

TypeScript'te imzayı kontrol edin

verify.ts
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 });
}

Go'da imzayı kontrol edin

verify.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
}

Olay akışı

GET /v1/partner/events son 30 günün tüm olaylarını en eskiden başlayarak döner. Sonraki sayfayı okumak için son nextCursor değerini after olarak gönderin. Uzun bir kesintiden sonra veya hiçbir şeyi kaçırmadığınızı kontrol etmek için kullanın.

GET /v1/partner/events
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
}

Dolandırıcılık bildirimleri

Karara bağlanmış bir oturumun dolandırıcılık olduğu ortaya çıkarsa, örneğin bir ters ibrazdan sonra, bize bildirin. Bildirimler hatalı onayları ölçmemize katkı sağlar. Oturumu, kimliği veya kullanıcının sonucunu değiştirmez.

  • Kapsam sessions:write. Yalnızca karara bağlanmış oturumlar için (onaylanmış veya reddedilmiş). Karardan önce çağrı 409 döner.
  • Boş bir gövde, other kategorisiyle confirmed_fraud bildirir. status ayrıca suspected_fraud olabilir ya da kendi bildiriminizi geri almak için cleared.
  • Kategoriler: forged_document, impostor, deepfake_or_replay, synthetic_identity, account_takeover ve other. cleared ile kategori gönderilmez.
  • note, analistlerimiz için en fazla 1000 karakterlik serbest bir metindir. İçine asla isim, belge numarası veya başka kişisel veri yazmayın.
  • Yeni bir bildirim 201 döner. Aynı bildirim tekrar gönderilirse kayıtlı olan 200 ile döner. Güvenle yeniden denemek için Idempotency-Key gönderin. Oturum başına en fazla 20 bildirim.
  • Aynı bildirim, panelde oturum sayfasından tek tıkla yapılabilir.
POST /v1/partner/sessions/:id/fraud-reports
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
}

Silme

DELETE /v1/partner/users/:externalUserId, kullanıcı hesabını kapattığında veya silinmesini istediğinde verisini siler. Cevap, şimdi neyin silindiğini ve neyin, neden ve ne zamana kadar tutulduğunu listeler.

DELETE /v1/partner/users/:externalUserId
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
}

Hatalar

Her hata aynı biçimdedir ve her kodun sabit bir HTTP durumu vardır.

error
{
  "error": {
    "code": "step_not_allowed",
    "message": "This step is not allowed now.",
    "requestId": "req_..."
  }
}
KodHTTPAnlamı
bad_request400İstek sözleşmeye uymuyor.
unauthorized401Anahtar veya jeton eksik ya da yanlış.
token_expired401İstemci jetonunun süresi doldu. Sunucunuzdan yenisini oluşturun.
forbidden403Bu anahtar bunu yapamaz.
not_found404Böyle bir oturum veya kullanıcı yok.
session_closed409Oturum son durumda. Başka yükleme yok.
step_not_allowed409Yanlış sıra veya adım şu an gerekli değil.
revision_conflict409Oturum sürümü değişti. Yeniden okuyun.
idempotency_conflict409Aynı Idempotency-Key farklı bir istekle kullanıldı.
challenge_expired410Doğrulama sorusunun süresi doldu veya zaten kullanıldı. Yenisini isteyin.
payload_too_large413Yükleme çok büyük.
unsupported_media_type415Dosya türü kabul edilmiyor.
rate_limited429Çok fazla istek. Daha sonra tekrar deneyin.
internal500Bizim tarafımızda bir şeyler ters gitti.
dependency_unavailable503İhtiyaç duyduğumuz bir hizmet çalışmıyor. Daha sonra tekrar deneyin.

Gerekçe kodları

Oturumlar yeniden gönderim gerektiğinde veya reddedildiğinde reasonCodes taşır. Her kod için kendi çevrilmiş mesajınızı gösterin. Ham kodu asla kullanıcıya göstermeyin.

  • consent_missing
  • consent_withdrawn
  • attestation_failed
  • document_expired
  • document_unreadable
  • document_not_supported
  • document_suspected_tampering
  • document_number_visible
  • chip_verification_failed
  • chip_proof_missing
  • chip_data_mismatch
  • mrz_invalid
  • photo_quality
  • face_not_found
  • face_mismatch
  • liveness_failed
  • underage
  • location_not_supported
  • residence_not_supported
  • sanctions_match
  • pep_review
  • duplicate_identity
  • possible_duplicate
  • declaration_requires_review
  • user_requested_review
  • reviewer_other
  • address_unreadable
  • address_document_too_old
  • address_document_not_accepted
  • address_name_mismatch
  • address_signature_required
  • funds_document_unreadable
  • funds_document_too_old
  • funds_document_not_accepted
  • funds_more_evidence
  • funds_evidence_rejected