# File: data-retention.md # Veri saklama ve mahremiyet modeli Kişisel veri korumasına öncelik verilir. Ham kimlik bilgileri yalnızca doğrulama sürecinin gerçekleştirilmesi için geçici işlenir; süreç bitince silinir; kalıcı arşivde tutulmaz. ## Yaşam döngüsü (özet) | Aşama | Veri | Saklama | | ----------------------------- | ---------------------------------------------- | --------------------------------------- | | API / doğrulama süreci | Ham kimlik | Şifreli; sonuç alınana veya talep iptal edilene kadar (geçici), ardından silinir | | Operasyonel kayıt | İstek kimliği, durum, sonuç meta, maskeli kimlik alanları (ham PII yok) | Operasyonel | | Önbellek | Pseudonimleştirilmiş anahtar + sonuç | `cache_max_age_days` (varsayılan 7 gün) | | API / webhook yanıtı | `request_id`, durum, `verified` | Ham PII yok | ## Kalıcı kayıt Kalıcı kayıtlarda TCKN, ad, soyad veya doğum tarihi açık olarak tutulmaz; denetim ve destek için yalnızca maskeli halleri (ör. TCKN'nin son iki hanesi, ad ve soyadın ilk harfi) saklanır. Önbellek eşleşmesi için girdilerden geri döndürülemez şekilde türetilmiş (pseudonimleştirilmiş) bir teknik anahtar kullanılır — bu otomatik anonimleştirme değildir. Pseudonimleştirme yönteminin uygulama detayı paylaşılmaz. ## Doğrulama sürecinde veri nasıl korunur? Canlı doğrulama talepleri, bizimle gizlilik sözleşmesi bulunan doğrulama ekibimiz tarafından manuel doğrulama işleminden geçirilerek sonuçlandırılır: - Ham kimlik bilgileri talep sonuçlanana kadar yalnızca şifreli olarak bekletilir. - Bilgiler yalnızca talebi üstlenen ekip üyesinin cihazına, şifreli bağlantı üzerinden ve iş başladığında iletilir. - Yardımcı uygulama formu kendisi doldurur; kimlik bilgileri ekip üyesinin ekranında maskeli gösterilir; maskeleme ayarı kapalı olan cihazlara iş atanmaz. - Sonuç bildirildiğinde (veya talep iptal edildiğinde) ham veri hemen silinir; ayrıca düzenli bir temizlik kontrolü çalışır. ## Önbellek - `cache_max_age_days` / uygulama ayarı - `skip_cache: true` ile cache atlanır ## Sizin tarafınızda önerilen kayıt Kimlik–sonuç eşlemesini kendi veritabanınızda tutmanızı öneririz (`kimlikapi_verification_attempts`). Kimlik API ham kimlik verisini kalıcı tutmadığı için, yeniden deneme veya destek süreçlerinde ihtiyaç duyacağınız ham veriyi kendi tarafınızda saklamanız beklenir — KVKK kapsamında veri sorumlusu sizsiniz. `kimlikapi_request_id` ve `reference_id` mutlaka saklanmalıdır. Hukuk biriminiz özellikle ham PII saklamayı yasaklıyorsa, istisnai olarak maskeleme veya minimum alan tutma tercih edebilirsiniz; bu bir zorunluluk değil, istisnai bir uyum tercihidir. KVKK: Kimlik API hizmet kapsamında veri işleyici rolünde hareket eder; bu özet hukuki tavsiye yerine geçmez. --- # File: endpoints.md # Endpoint özeti Tam şema: `/openapi.yaml` ## POST /v1/verify Kimlik doğrulama isteği. Auth: Bearer API key. Body: `id_number`, `first_name`, `last_name`, `birth_date`, `mode` (sync|async), `skip_cache`, `reference_id`. Yanıtlar: 200 (tamamlandı: sync sonuç veya önbellekten dönen sonuç), 202 (processing), 402, 403, 422, 429. `async` önerilir; sonuç çoğunlukla 1-2 dakikada webhook veya polling ile gelir. `sync` en fazla 90 sn bekler; sonuç gelmezse async gövdesiyle 202 döner ve istek sürer. Sync ileride kabul edilmeyebilir. Header’lar: `X-Request-Id`, `X-Credits-Remaining`. ## GET /v1/requests/{request_id} Polling. pending/processing/completed/failed gövdeleri. İlk kontrol ~30 sn sonra, ardından 30-60 sn aralıkla; uygulama başına dakikada 60 istek sınırına dahildir. ## GET /v1/account/credits `available`, dönem `total` / `used` / `start` / `end`. ## GET /v1/account/usage Dönem istatistikleri: total_requests, successful, failed, cache_hits, cache_hit_rate. --- # File: errors.md # Hata kodu kataloğu Yanıt gövdesi: ```json { "error": { "code": "...", "message": "...", "details": {} } } ``` | Kod | HTTP | Açıklama | | ---------------------- | ---- | ------------------------------------- | | validation_error | 422 | Doğulama hatası; `details` alan map | | unauthorized | 401 | Geçersiz/eksik API key | | insufficient_credits | 402 | Kredi yetersiz | | billing_setup_required | 402 | Ücretsiz kredi için fatura + kart gerekli | | email_unverified | 403 | E-posta doğrulanmamış | | subscription_suspended | 403 | Abonelik askıda / kullanılamaz | | app_inactive | 403 | Uygulama pasif | | request_not_found | 404 | İstek bulunamadı | | verification_error | 500 | Doğrulama süreci tamamlanamadı | | service_unavailable | 503 | Servis geçici olarak kullanılamıyor | `billing_setup_required`: aboneliği olmayan hesap, ücretsiz production kredilerini panelden fatura bilgilerini tamamlayıp kart ekleyince kullanabilir. Tekrar denemeyin. `service_unavailable`: yanıtta `Retry-After` (saniye) başlığı varsa en az o kadar bekleyip tekrar deneyin. Kredi iade edilir. Kredi: yalnızca sonuç eşleşme veya eşleşmeme (`verified` true/false) olduğunda düşer, önbellekten dönen sonuçlar dahil. `processing` istekte kredi ayrılmış kalır; sonuç üretilemezse istek `failed` olur ve kredi iade edilir. `processing` bir hata değildir: sonucu beklerken aynı bilgilerle yeni istek göndermeyin; her istek ayrı ücretlendirilir. Docs’ta ayrıca `invalid_tc_kimlik`, `forbidden`, `no_active_subscription` referansları olabilir; TC hataları genelde `validation_error` olarak döner. --- # File: integration-guide.md # Adım adım entegrasyon rehberi ## Ne kadar sürer? Canlı doğrulama talepleri, gizlilik sözleşmeli doğrulama ekibimiz tarafından manuel doğrulama işleminden geçirilerek sonuçlandırılır. Sonuçlar çoğunlukla 1-2 dakika içinde gelir; yoğun anlarda 10 dakikaya kadar uzayabilir. Bu bir hizmet seviyesi taahhüdü değil, beklenen süredir. Entegrasyonu asenkron kurun ve doğrulamayı kullanıcı akışınızda engel yapmayın (bkz. 5. adım). ## Mahremiyet ve sizin kaydınız Ham kimlik bilgileri yalnızca doğrulama için geçici işlenir; kalıcı arşivde tutulmaz. Size `request_id`, durum ve eşleşme sonucu (`verified`) döneriz. Denetim izi için kendi tablonuzu tutmanızı öneririz. Detay: veri saklama modeli. ## 1. App seçin veya oluşturun Kayıtta otomatik 1 sandbox (`test_`) + 1 production (`live_`) uygulama oluşur. Sandbox sınırsızdır; entegrasyonu önce orada bitirin. ## 2. Kendi tarafınızda doğrulama kaydı Önerilen tablo `kimlikapi_verification_attempts`: - `id` - `kimlikapi_request_id` — bizim `request_id` (mutlaka saklayın) - `reference_id` — sizin iç referansınız (yanıt ve webhook’ta geri döner) - isteğe bağlı PII: `id_number`, `first_name`, `last_name`, `birth_date` — kendi tarafınızda saklamanız önerilir (Kimlik API ham veriyi kalıcı tutmaz). Hukuk biriminiz ham PII saklamayı yasaklıyorsa maskeleme istisnai bir alternatiftir. - `status` - `verified` (nullable bool — eşleşme sonucu) - `requested_at`, `resolved_at` ## 3. İsteği gönderin `POST /v1/verify` — body: `id_number`, `first_name`, `last_name`, `birth_date` (`Y-m-d`), `mode` (`async` önerilir), `reference_id`, `skip_cache`. Dönen `request_id`’yi kendi kaydınıza yazın. ## 4. Sonucu alın 1. **Webhook (önerilen):** uygulama webhook URL’i + HMAC imza doğrulama. Gövde: `event` (`verification.completed` | `verification.failed`), `request_id`, `reference_id`, `data.status`, `data.verified`. 2. **Polling:** `GET /v1/requests/{request_id}` — ilk kontrol ~30 sn sonra, ardından 30-60 sn aralıkla; arka planda bir kuyruk işinde yapın. Her ikisinde kendi kaydınızı `completed` / `failed` olarak güncelleyin; `request_id` / `reference_id` ile eşleştirin. ## 5. Doğrulamayı kullanıcı akışınızda engel yapmayın 1. Kullanıcıyı içeri alın; kaydı ve doğrulama gerektirmeyen adımları tamamlayın. 2. Talebi arka planda `mode: async` ile gönderin, kimlik durumunu "doğrulama bekleniyor" yapın, "Doğrulama süreciniz başladı, tamamlanınca haber vereceğiz" mesajı gösterin. 3. Yalnızca doğrulanmış TC gerektiren işlemleri (ödeme alma, sözleşme onayı, para çekme vb.) bu durumda kilitli tutun. 4. Webhook/polling sonucu gelince durumu güncelleyin: `data.verified === true` → doğrulandı, `false` → eşleşmedi (kullanıcıdan bilgileri kontrol etmesini isteyip yeni talep), `failed` → yeniden deneme sunun. Laravel ve Node.js örnekleri: `/docs/integration-guide`. ## 6. Olası durumlar - Uzun süren işlem: talep iptal edilmez, `processing` kalır; sonuç gelince webhook gönderilir. Aynı bilgilerle yeni talep göndermeyin (her talep ayrı ücretlendirilir). - `failed`: sonuç üretilemedi; kredi düşmez, yeniden deneme sunun. - `402 insufficient_credits` - `402 billing_setup_required` (aboneliksiz hesap: ücretsiz kredi için panelden fatura bilgisi ve kart ekleyin) - `503 service_unavailable` (`Retry-After` başlığı varsa o kadar bekleyip tekrar deneyin; kredi iade edilir) - Önbellekten dönen sonuç (`from_cache`) — anında döner - `403 email_unverified` / `subscription_suspended` ## Süreç özeti Sizin backend (kullanıcıyı içeri al, kayıt aç) → Kimlik API verify (async) → webhook veya polling → sizin backend (kaydı güncelle, kilitli işlemleri aç, kullanıcıyı bilgilendir). --- # File: overview.md # Kimlik API — Genel Bakış Kimlik API'nin eski adı Kimlik API.com'dur. Kimlik API, T.C. kimlik bilgisi eşleşme kontrolünü yönetilen bir operasyon olarak sunan API’dir. Kurumların NVİ yönlendirmesiyle manuel yürütmek zorunda kaldığı eşleşme işlemini sizin yerinize yapar ve sonucu API / webhook ile iletir. **Resmî T.C. / KPS API değildir.** NVİ veya KPS ile resmî ortaklık yoktur. ## Ne yapar / ne yapmaz? - Yapar: TCKN + ad + soyad + doğum tarihi eşleşme kontrolü. - Yapmaz: kişinin kimliğini kanıtlamak, belge gerçekliği, canlılık, adres doğrulama, tek başına KYC/AML. API alanındaki `verified` = bilgiler eşleşti mi? ## Ortamlar | Ortam | Base URL | Anahtar öneki | | ------- | --------------------------- | ------------- | | Canlı | `https://api.kimlikapi.com/v1` | `live_` | | Sandbox | `https://api.kimlikapi.com/v1` (aynı adres) | `test_` | Sandbox sınırsızdır, sentetik senaryo döner, kredi tüketmez. Ücretsiz production kredileri ayrıdır; `live_` gerçek kontrol yapar. ## Kimlik doğrulama ``` Authorization: Bearer {api_key} ``` Secret yalnızca webhook HMAC imzası içindir. ## Nasıl çalışır, ne kadar sürer? Canlı doğrulama talepleri, gizlilik sözleşmeli doğrulama ekibimiz tarafından manuel doğrulama işleminden geçirilerek sonuçlandırılır. Sonuçlar çoğunlukla **1-2 dakika** içinde gelir; yoğun anlarda **10 dakikaya** kadar uzayabilir (beklenen süre, hizmet seviyesi taahhüdü değil). Bu yüzden canlı doğrulama asenkron çalışır: - `mode: async` kullanın, sonucu webhook veya polling ile alın. - Doğrulamayı kayıt/üyelik akışınızı kilitleyen bir adım yapmayın. Kullanıcıyı içeri alın, kimlik durumunu "doğrulama bekleniyor" olarak işaretleyin, yalnızca doğrulanmış TC gerektiren işlemleri sonuç gelene kadar kilitli tutun. - `mode: sync` hâlâ kabul edilir ama önerilmez: sunucu en fazla 90 sn bekler; sonuç gelmezse async gövdesiyle `202` döner ve istek sürer. Sync ileride kabul edilmeyebilir. - Kredi yalnızca sonuç eşleşme veya eşleşmeme olduğunda düşer. ## Entegrasyon ilkesi Ham kimlik bilgileri yalnızca işlem için geçici işlenir; kalıcı arşivde tutulmaz. Sonucu ve yeniden deneme için ihtiyaç duyacağınız veriyi **kendi tarafınızda** saklamanız önerilir (`request_id` / `reference_id` ile kendi tablonuza yazın). Hukuk biriminiz ham PII saklamayı yasaklıyorsa maskeleme istisnai bir alternatiftir. Başlangıç: `GetIntegrationGuideTool` veya `/docs/integration-guide`. Önerilen mod: `async` + webhook. --- # File: sandbox.md # Sandbox ve test senaryoları Sandbox app (`test_` anahtar) sınırsızdır; gerçek NVI çağrısı yapılmaz, kredi düşmez, yalnızca sentetik senaryolar döner. Ücretsiz production kredileri ayrı bir kavramdır (`live_` gerçek kontrol yapar). Base URL canlı ortamla aynıdır (`https://api.kimlikapi.com/v1`); ortam ayrımı `test_` / `live_` öneki ile yapılır. Gerçek TCKN kullanmayın. ## Tipik senaryolar (sandbox TCKN) | TCKN | Sonuç | | ----------- | ------------------------------ | | 10000000146 | verified: true | | 20000000282 | verified: true | | 30000000328 | verified: false | | 40000000464 | verified: false | | 50000000500 | verified: true (async gecikme) | | 60000000646 | hata / verified: null | Ad, soyad ve doğum tarihi sandbox sonucunda değişmez; karar yalnızca TCKN’ye göredir. Tabloda olmayan her TCKN anında `verified: true` döner. Doğru ya da yanlış kimlik bilgisi bu sonucu değiştirmez. Eşleşmeme için `30000000328` veya `40000000464` kullanın. Gerçek eşleşme kontrolü yalnızca `live_` anahtarıyla production uygulamasında yapılır. ## Önerilen akış 1. Sandbox key ile `POST /v1/verify` (async) 2. Webhook URL’ini ayarla veya polling yap 3. İmza doğrulamayı test et 4. Production app + abonelik + `live_` key ile canlıya geç --- # File: webhooks.md # Webhook’lar Uygulama ayarından webhook URL tanımlanır. Olay gövdesi JSON olarak gelir. İmza başlıkları: - `X-TCDogrula-Signature` — `sha256=` formatında (HMAC-SHA256, uygulama secret’ı ile ham JSON gövde üzerinden) - `X-TCDogrula-Timestamp` — ISO 8601 zaman damgası ## Doğrulama adımları 1. Ham body’yi oku (yeniden encode etme) 2. App secret ile HMAC-SHA256 hesapla; beklenen değeri `sha256=` önekiyle oluştur 3. `X-TCDogrula-Signature` ile `hash_equals` / timing-safe karşılaştır 4. Başarılıysa `request_id` / `status` / `result` ile kendi kaydını güncelle ## Diller `VerifyWebhookSignatureExampleTool` ile php / node / python örnekleri alın. ## Retry Başarısız teslimatta yeniden deneme politikası docs/webhooks sayfasında anlatılır. --- # File: openapi.yaml openapi: 3.0.3 info: title: Kimlik API version: 1.0.0 description: | Türkiye kimlik doğrulama API’si. Auth: `Authorization: Bearer {api_key}`. `test_` anahtarlar sandbox (ücretsiz sahte veri); `live_` anahtarlar kredi tüketir. Hata gövdesi: `{ "error": { "code", "message", "details?" } }`. Örnek kodlar: `email_unverified`, `subscription_suspended`, `insufficient_credits`, `billing_setup_required`, `unauthorized`, `app_inactive`, `validation_error`, `request_not_found`, `verification_error`, `service_unavailable`. Canlı doğrulama asenkron çalışır: sonuçlar çoğunlukla 1-2 dakikada (yoğunlukta ~10 dakikaya kadar) webhook veya `GET /v1/requests/{request_id}` ile gelir. `mode: async` önerilir. `mode: sync` en fazla 90 sn bekler; sonuç gelmezse async gövdesiyle 202 döner ve istek sürer. Sync ileride kabul edilmeyebilir. Kredi yalnızca sonuç eşleşme/eşleşmeme olduğunda düşer. servers: - url: 'https://api.kimlikapi.com' description: Kimlik API (paths include /v1) paths: /v1/verify: post: operationId: verify summary: Kimlik doğrulama isteği oluştur security: - bearerAuth: [] parameters: - in: header name: Authorization required: true schema: type: string requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/VerifyRequest' responses: '200': description: Completed (sync result within the wait window, or a cached result) headers: X-Request-Id: schema: type: string X-Credits-Remaining: schema: oneOf: - type: integer - type: string content: application/json: schema: $ref: '#/components/schemas/VerifySyncResponse' '202': description: Accepted and processing (async, or sync with no result within 90 s); receive the result via webhook or polling headers: X-Request-Id: schema: type: string X-Credits-Remaining: schema: oneOf: - type: integer - type: string content: application/json: schema: $ref: '#/components/schemas/VerifyAsyncResponse' '402': description: Insufficient credits (insufficient_credits) or free credits need billing info and a card (billing_setup_required) content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '403': description: Forbidden (email_unverified, subscription_suspended, app_inactive) content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '422': description: Validation error content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '429': description: Rate limited content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '503': description: Verification service temporarily unavailable (service_unavailable); the reserved credit is refunded headers: Retry-After: description: Seconds to wait before retrying. Present when the service is busy or asks the client to wait. schema: type: integer content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' /v1/requests/{request_id}: get: operationId: getRequest summary: Doğrulama isteği durumu (polling) security: - bearerAuth: [] parameters: - name: request_id in: path required: true schema: type: string responses: '200': description: Request status headers: X-Request-Id: schema: type: string content: application/json: schema: $ref: '#/components/schemas/RequestStatusResponse' '404': description: Not found content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' /v1/account/credits: get: operationId: getCredits summary: Kredi bakiyesi security: - bearerAuth: [] responses: '200': description: Credits content: application/json: schema: $ref: '#/components/schemas/CreditsResponse' /v1/account/usage: get: operationId: getUsage summary: Dönem kullanım istatistikleri security: - bearerAuth: [] responses: '200': description: Usage content: application/json: schema: $ref: '#/components/schemas/UsageResponse' components: securitySchemes: bearerAuth: type: http scheme: bearer bearerFormat: API key description: Panelden alınan API anahtarı. `test_` sandbox, `live_` production. schemas: Error: type: object required: [code, message] properties: code: type: string message: type: string details: type: object additionalProperties: true ErrorEnvelope: type: object required: [error] properties: error: $ref: '#/components/schemas/Error' VerifyRequest: type: object required: [id_number, first_name, last_name, birth_date] properties: id_number: type: string pattern: '^\d{11}$' first_name: type: string last_name: type: string birth_date: type: string format: date mode: type: string enum: [sync, async] default: async description: async önerilir. sync en fazla 90 sn bekler, ardından 202 döner; ileride kabul edilmeyebilir. skip_cache: type: boolean default: false reference_id: type: string maxLength: 255 nullable: true VerifySyncResponse: type: object properties: request_id: type: string reference_id: type: string nullable: true status: type: string enum: [completed] result: type: object properties: verified: type: boolean from_cache: type: boolean cached_at: type: string nullable: true processed_at: type: string nullable: true credits: type: object nullable: true properties: used: type: integer remaining: type: integer VerifyAsyncResponse: type: object properties: request_id: type: string reference_id: type: string nullable: true status: type: string enum: [processing] message: type: string RequestStatusResponse: type: object properties: request_id: type: string reference_id: type: string nullable: true status: type: string enum: [pending, processing, completed, failed] created_at: type: string result: type: object nullable: true error: $ref: '#/components/schemas/Error' credits: type: object nullable: true CreditsResponse: type: object properties: available: type: integer period: type: object properties: total: type: integer nullable: true used: type: integer nullable: true start: type: string nullable: true end: type: string nullable: true UsageResponse: type: object properties: period: type: object properties: start: type: string nullable: true end: type: string nullable: true total_requests: type: integer successful: type: integer not_verified: type: integer failed: type: integer cache_hits: type: integer cache_hit_rate: type: number