Adım adım entegrasyon rehberi

Bu rehber, Kimlik API'yi kendi backend'inize bağlamanın uçtan uca yoludur. Amaç yalnızca bir istek atmak değil; sonucu kendi kayıtlarınızda güvenle eşleştirip iş sürecinize devam edebilmektir.

1. App seçin veya oluşturun

Kayıt sonrası hesabınızda otomatik olarak bir test (test_) ve bir canlı (live_) uygulama oluşturulur.

  • Sandbox: sınırsızdır, sentetik senaryo verisi döner, kredi tüketmez. Entegrasyonu burada bitirin.
  • Production: gerçek eşleşme kontrolü yapar ve kredi tüketir. Canlıya geçmeden önce webhook ve kayıt şemanızın çalıştığını doğrulayın.

Detay: Sandbox · API anahtarı

2. Kendi tarafınızda doğrulama kaydı açın

Her istek için kendi veritabanınızda bir satır tutun. Bizden dönen request_id değerini mutlaka saklayın; kendi reference_id'nizle eşleştirin. Bize gönderdiğiniz kimlik alanlarını kendi tarafınızda saklamanız önerilir — Kimlik API ham veriyi kalıcı tutmadığı için yeniden deneme ve destek süreçlerinde bu kayıtlara ihtiyaç duyabilirsiniz. Hukuk biriminiz ham PII saklamayı yasaklıyorsa maskeleme istisnai bir alternatiftir.

CREATE TABLE kimlikapi_verification_attempts (
  id                     BIGINT PRIMARY KEY,
  kimlikapi_request_id   CHAR(36) NULL UNIQUE,      -- bizim request_id (mutlaka saklayın)
  reference_id           VARCHAR(255) NOT NULL UNIQUE, -- sizin iç referansınız
  -- önerilen: ham PII (Kimlik API kalıcı tutmaz; yeniden deneme için sizde saklayın)
  id_number              VARCHAR(11) NULL,
  first_name             VARCHAR(100) NULL,
  last_name              VARCHAR(100) NULL,
  birth_date             DATE NULL,
  status                 VARCHAR(32) NOT NULL,         -- pending|processing|completed|failed
  verified               BOOLEAN NULL,                 -- eşleşme sonucu (nullable)
  requested_at           TIMESTAMP NOT NULL,
  resolved_at            TIMESTAMP NULL
);

3. İsteği gönderin

Önce kendi kaydınızı pending olarak oluşturun, ardından POST /v1/verify çağırın. Dönen request_id'yi hemen kendi satırınıza yazın. reference_id yanıt, webhook ve polling yanıtlarında da aynı şekilde geri döner.

curl -sS -X POST "$BASE_URL/v1/verify" \
  -H "Authorization: Bearer test_xxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "id_number": "10000000146",
    "first_name": "Test",
    "last_name": "Kullanici",
    "birth_date": "1990-01-15",
    "mode": "async",
    "reference_id": "order-123"
  }'

Sync/async seçimi için POST /v1/verify sayfasındaki karar rehberine bakın. Üretimde async önerilir.

4. Sonucu alın

Önerilen: webhook. Sonuç geldiğinde imzayı doğrulayın, kendi kaydınızı request_id veya reference_id ile bulun ve status / verified alanlarını güncelleyin.

// Laravel örneği (özet)
$raw = $request->getContent();
$signature = $request->header('X-TCDogrula-Signature', '');
$expected = 'sha256=' . hash_hmac('sha256', $raw, $appSecret);

if (! hash_equals($expected, $signature)) {
    abort(401);
}

$event = json_decode($raw, true);

// event: verification.completed | verification.failed
DB::table('kimlikapi_verification_attempts')
    ->where('kimlikapi_request_id', $event['request_id'])
    ->update([
        'status' => data_get($event, 'data.status'),
        'verified' => data_get($event, 'data.verified'),
        'resolved_at' => now(),
    ]);

return response()->noContent();

Webhook alamıyorsanız polling kullanın: ilk kontrolü 30 sn sonra yapın, ardından 30-60 sn aralıkla devam edin. Her iki yolda da kendi kaydınızı güncelleyin; biz size bağlanacak net bir request_id / reference_id ve eşleşme sonucu döneriz, böylece iş sürecinizi kendi sisteminizde tamamlayabilirsiniz.

5. Doğrulamayı kullanıcı akışınızda engel yapmayın

Doğrulama sonucu dakikalar içinde gelir. Bu yüzden onu kayıt veya üyelik formunun son adımı gibi kurgulamayın; kullanıcı ekranda sonucu beklememeli. Önerdiğimiz yapı:

  1. Kullanıcıyı içeri alın. Kaydı ve doğrulama gerektirmeyen adımları her zamanki gibi tamamlayın.
  2. Doğrulama talebini arka planda (mode: async) gönderin, kullanıcının kimlik durumunu doğrulama bekleniyor olarak işaretleyin ve “Doğrulama süreciniz başladı, tamamlanınca haber vereceğiz” gibi bir mesaj gösterin.
  3. Yalnızca doğrulanmış T.C. kimlik bilgisi gerektiren işlemleri (ör. ödeme alma, sözleşme onayı, para çekme) bu durumda kilitli tutun; kullanıcı diğer bölümleri kullanmaya devam etsin.
  4. Sonuç webhook (veya polling) ile geldiğinde durumu güncelleyin, kilidi açın ve kullanıcıyı bilgilendirin. Bilgiler eşleşmezse kullanıcıdan bilgilerini kontrol etmesini isteyip yeni bir talep gönderin.

Laravel örneği

// 1) Kayıttan sonra: kullanıcıyı içeri al, doğrulamayı kuyruğa bırak
$user->update(['identity_status' => 'pending']);
SubmitIdentityVerification::dispatch($user, $identityInput);

return redirect()->route('dashboard')
    ->with('info', 'Doğrulama süreciniz başladı, tamamlanınca haber vereceğiz.');

// 2) Kuyruk işi: talebi async gönder, request_id'yi sakla
public function handle(): void
{
    $referenceId = 'user-'.$this->user->id.'-'.Str::uuid();

    $response = Http::withToken(config('services.kimlikapi.api_key'))
        ->post(config('services.kimlikapi.base_url').'/v1/verify', [
            ...$this->identity,
            'mode' => 'async',
            'reference_id' => $referenceId,
        ])
        ->throw();

    DB::table('kimlikapi_verification_attempts')->insert([
        'kimlikapi_request_id' => $response->json('request_id'),
        'reference_id' => $referenceId,
        'status' => $response->json('status'),
        'requested_at' => now(),
    ]);
}

// 3) Yalnızca doğrulama gerektiren rotaları kilitle
Route::middleware(['auth', 'identity.verified'])->group(function () {
    Route::post('/payouts', [PayoutController::class, 'store']);
});

// EnsureIdentityVerified middleware
if ($request->user()->identity_status !== 'verified') {
    return redirect()->route('dashboard')
        ->with('warning', 'Bu işlem için T.C. kimlik doğrulamanızın tamamlanması bekleniyor.');
}

// 4) Webhook geldiğinde (imza doğrulandıktan sonra)
$user->update([
    'identity_status' => match (data_get($event, 'data.verified')) {
        true => 'verified',
        false => 'mismatch',
        default => 'failed', // sonuç üretilemedi; yeniden deneme sunun
    },
]);

Node.js (Express) örneği

// 1) Kayıt: kullanıcıyı hemen içeri al, doğrulamayı arka planda başlat
app.post('/signup', async (req, res) => {
  const user = await users.create({ ...req.body.account, identityStatus: 'pending' });

  startVerification(user, req.body.identity).catch((err) => logger.error(err));

  res.status(201).json({
    user,
    message: 'Doğrulama süreciniz başladı, tamamlanınca haber vereceğiz.',
  });
});

async function startVerification(user, identity) {
  const referenceId = 'user-' + user.id + '-' + crypto.randomUUID();
  const response = await fetch(process.env.TCDOGRULA_BASE_URL + '/v1/verify', {
    method: 'POST',
    headers: {
      Authorization: 'Bearer ' + process.env.TCDOGRULA_API_KEY,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ ...identity, mode: 'async', reference_id: referenceId }),
  });
  const body = await response.json();

  await attempts.insert({
    kimlikapiRequestId: body.request_id,
    referenceId,
    userId: user.id,
    status: body.status,
  });
}

// 2) Yalnızca doğrulama gerektiren işlemleri kilitle
function requireVerifiedIdentity(req, res, next) {
  if (req.user.identityStatus !== 'verified') {
    return res.status(403).json({
      code: 'identity_verification_pending',
      message: 'Bu işlem için T.C. kimlik doğrulamanızın tamamlanması bekleniyor.',
    });
  }
  next();
}

app.post('/payouts', requireVerifiedIdentity, createPayout);

// 3) Webhook (imza doğrulandıktan sonra)
const verified = event.data.verified;
const attempt = await attempts.findByRequestId(event.request_id);
await users.update(attempt.userId, {
  identityStatus: verified === true ? 'verified' : verified === false ? 'mismatch' : 'failed',
});

6. Olası durumlar

  • İşlem beklenenden uzun sürüyor: talep iptal edilmez; processing durumunda kalır ve sonuç geldiğinde webhook gönderilir. Aynı bilgilerle yeni talep göndermeyin; her talep ayrı değerlendirilir ve sonuç üretirse ayrı ücretlendirilir.
  • Sonuç üretilemedi (failed): status: failed geldiğinde kendi kaydınızı başarısız işaretleyin; kullanıcıya yeniden deneme sunun. Bu durumda kredi düşmez.
  • Kredi yetersiz (402): production anahtarında bakiye bitmiş demektir. Sandbox bu hatayı vermez.
  • Önbellek: from_cache: true sonuçları da geçerlidir ve anında döner; yine kendi kaydınıza yazın. Taze sorgu için skip_cache kullanın.

Süreç özeti

  1. Sizin backend: kullanıcıyı içeri alın, kendi kaydınızı açın (pending).
  2. Sizin backend → Kimlik API: POST /v1/verify.
  3. Kimlik API → sizin backend: webhook (veya sizin polling çağrınız).
  4. Sizin backend: imza doğrula, kaydı güncelle, kilitli işlemleri aç ve kullanıcıyı bilgilendir.