Ana içeriğe geç

01 · GET /config — Config Çekme Sözleşmesi

Görev: 00 · AUTH'un döndürdüğü token ile cihazın tam config'ini (tema + ekranlar + gruplar + metinler) sunucudan çeker; SDK config'i parsel edip onay ekranını (banner/manager/detail) kurar.

Ne zaman çalışır: AUTH'un yanıtında decision.updateRequired === true olduğunda. Değilse (içerik değişmedi) bu adım atlanır; cihazdaki mevcut config önbellekten kullanılır.

Bu dosyadan sonra kullanıcı onay ekranında bir seçim yaptığında 02 · POST_CONSENT'e geçersiniz.


1. Genel Bakış

GET /config, açılış döngüsünün orta halkasıdır: AUTH onu besler (token verir), o da onay kaydına zemin hazırlar (UI'ı kurar, aynı token'ı taşır).

SDK sunucuya:

  • Kimlik taşır → path'te consentId + header'da X-Consent-Token (+ gövdede opsiyonel locale/sdkVersion)

Sunucu karşılığında:

  • Tam config gövdesi döndürür → config (tema, ekranlar, gruplar, metinler; detay §5.2)
  • Çerçeve (envelope) döndürür → success / code / consentId / deliveredAt / contentVersion / tokenConsumed

Tasarım felsefesi: Bu bir OKUMA (read) işlemidir — durumu değiştirmez, idempotent'tir. AUTH hafif tutulur (yalnız versiyonlar + token + decision); tam config yalnızca gerçekten gerektiğinde bu adım ile çekilir. Böylece büyük çoğunluk açılışta config hiç transfer edilmez → açılış hızlı, veri tasarruflu, gecikme düşük.

GET /config, AUTH'ın "gerekli mi?" sorusuna verdiği cevabı (decision.updateRequired) hayata geçiren adımdır. updateRequired === false ise bu adımı atlayın, cihazdaki mevcut config'i kullanın.


2. Döngüdeki Yeri

AUTH (00) GET /config (BU) POST_CONSENT (02)
kimlik + localState ──▶ token ─▶ tam config ────▶ onay kaydı
│ token │ parse → UI kur │ consent + localState
└── decision.updateRequired ──┘ (aynı token) │

bir sonraki AUTH ◀─────────────── localState geri besleme
AdımKoşulSDK davranışı
00 — AUTHHer açılıştaKimlik + localState gönder; versiyon + token + decision al
01 — GET /config (bu adım)decision.updateRequired === trueToken ile tam config indir, parsel et, önbelleğe yaz, UI'ı yeniden kur
02 — POST_CONSENTKullanıcı onay ekranında karar verirseAynı token ile onay eylemini post et

Neden iki aşamalı? İçerik değişmiyorsa config hiç transfer edilmez. Değişiyorsa, AUTH'ın verdiği token ile tek istekte tam config çekilir — ayrı bir anahtar imzalama derdi yoktur (o iş AUTH'ta yapıldı).


3. Endpoint & Güvenlik

3.1 Endpoint

ÖzellikDeğer
MethodPOST
Path/v2/consent/{consentId}/config
Base URL{{SDK_BASE_URL}}
Gövde formatıapplication/json (UTF-8)
Timeout15 sn
IdempotentEvet — okuma işlemidir; aynı istek tekrarlandığında aynı config'i döndürür (retry güvenli).

Neden POST (REST GET değil)? İki neden: (1) SDK'nın üç sözleşmesi tutarlı biçimde POST'tur — tek transport modeli. (2) GET, ara katmanlarda (proxy/CDN/tarayıcı) önbelleğe alınabilir; token + kimlik taşıyan hassas bir istek önbelleğe alınmamalıdır. POST bunu garanti eder. Adımdaki "GET" okuma semantiğidir, HTTP fiilini değil.

3.2 Güvenlik (token-bearer — imza/nonce YOK)

GET /config, AUTH'taki HMAC + nonce + timestamp modelini kullanmaz. Kimlik yalnızca AUTH'tan alınan imzalı, oturum bazlı token ile yapılır:

HeaderDeğer / Açıklama
Content-Typeapplication/json
X-Consent-TokenAUTH yanıtındaki token (imzalı, oturum bazlı, tokenExpiresIn'e bağlı). Örnek: cfg_t_8a3f5c2d1e0b.
  • Doğrulama (sunucu): (1) token biçimi/doğrulaması geçerli mi? (2) süresi doldu mu? (3) daha önce tüketildi mi? (4) token'ın bağlı olduğu consentId == path/gövde consentId mi? → her ihlal ilgili 401/404 kodu.
  • Replay: Okuma işlemi zararsızdır (aynı config'in tekrar çekilmesi idempotent'tir). Bu yüzden nonce/timestamp gerekmez; replay koruması token'ın bağlı olduğu consentId + sınırlı geçerlilik penceresi (tokenExpiresIn) + oturum bazlı tüketimi (§4) ile sağlanır.

POST_CONSENT ile fark (önemli): 02 · POST /consent bir YAZMA işlemidir → durumu değiştirir, mükerrer yazma riski taşır → bu yüzden HMAC + nonce + timestamp zorunludur. GET /config bir OKUMA işlemidir → idempotent + retry-tolerant → bearer token yeterlidir, ek imza/nonce eklenmez. Bu ayrım, SDK'nın ağ kesintisi gibi okuma hatasında rahatça retry yapabilmesini sağlar; nonce tabanlı bir okuma ise retry'ı reddederdi.


4. İstek (request)

Gövde minimaldir: kimlik path'te, token header'dadır. Gövde yalnızca opsiyonel çözümleme/telemetri alanlarını taşır. camelCase zorunludur.

AlanTipZorunluAçıklama
consentIdstringEvetOnay kaydı kimliği (ör. ck_mobildev_0001). Path'teki {consentId} ile birebir aynı olmalıdır; sunucu path ↔ gövde ↔ token üçlüsünü çapraz-doğrar, uyumsuzluk → 401 INVALID_TOKEN.
localestring (BCP-47)HayırKullanıcı tercih edilen dil (ör. tr-TR). Response'u daraltmaz (bkz. Not 1); telemetri + SDK'ın aktif dil çözümlemesine ipuç. Yoksa SDK behavior.defaultLanguage'i kullanır.
sdkVersionstring (semver)HayırSDK sürümü. AUTH çağrısıyla korelasyon + uyumluluk/telemetri.

Not 1 — locale response'u değiştirmez: Sunucu, request locale'i ne olursa olsun tam config'i (tüm localization blokları) döndürür. Dil çözümlemesi SDK tarafında yapılır (behavior.defaultLanguage + kullanıcı tercihi + availableLanguages). Böylece response deterministik kalır ve SDK, dil değiştirdiğinde yeniden istek atmak zorunda kalmaz.

Not 2 — Token yalnız header'dadır: Token gövde içine yazılmaz; X-Consent-Token header'ında taşınır (§3.2). Bu yüzden gövde küçük ve sade kalır.

4.1 Örnek İstek

{
"consentId": "ck_mobildev_0001",
"locale": "tr-TR",
"sdkVersion": "1.4.0"
}

Ayrıca header'da: X-Consent-Token: cfg_t_8a3f5c2d1e0b. Bu örneğin aynısı ayrıca [01-config.request.json](./01-config.request.json) dosyasında yer alır.


5. Yanıt (response)

Response, diğer sözleşmelerle tutarlı bir envelope + içinde tam config taşır. HTTP 200 → başarılı; 4xx/5xx → ortak hata envelope'u.

5.1 Envelope Alanları (200)

AlanTipAçıklama
successbooleantrue — config başarıyla getirildi. (Hatalarda false ortak envelope döner, bkz. §7.)
codestringKod (başarıda OK).
consentIdstringÇözülen consentId (eko; log + doğrulama).
deliveredAtstring (ISO 8601 UTC)Config'in sunucu tarafından servis edildiği an (audit/telemetri).
contentVersionstringConfig'in içerik versiyonu. SDK bunu cihazdaki installedContentVersion'ıyla karşılaştırıp reprompt kararını hızla üretebilir.
tokenConsumedbooleanBu çağrı token'ı tüketmiş midir? GET /config'de false (okuma token'ı bitirmez). SDK bu değere bakarak token'ın onay adımı için hâlâ geçerli olduğunu bilir (bkz. §6).
configobjectTAM config gövdesi = §5.2'deki blok yapısı.

5.2 config Gövdesi (üst düzey yapı)

config, uygulamanızın onay deneyiminin tamamını tanımlayan tek JSON'dır. Üst düzey bloklar:

Blokİçerik
schemaVersion"2.0" — SDK feature-gate.
metaconsentId / organization / contentVersion / contentMode / generatedAt.
behaviordefaultLanguage / availableLanguages / allowLanguageChange / showConsentId / promptATTdialog / displayATTStatus / retrigger{…}.
themescheme + light/dark renk token'ları + typography + radius + spacing.
bannerlayout / logo / title / description / buttons.list[] (ilk onay ekranı).
managertitle / showBack / groupRow / groups[] (her grupta consentKeys[] + items[]) / footer.actions[] (ana tercih ekranı).
detailshowBack / sections / links[] / actions[] (öğe/grup detay ekranı).
localizationtr-TR / en-US / de-DE — tüm metinlerin i18n anahtarları.

Alt bloklarda öne çıkanlar:

  • manager.groups[] — izin kategorileri: essential / functionality / targeting / tracking. Her grupta: id, titleLangKey, descLangKey, isEssential, lockState, defaultState, consentKeys[] (etiketlere karşılık gelen key listesi) ve items[] (o gruptaki teknoloji/vendor satırları — bilgilendirme amaçlı, etiket key taşımaz).
  • Tema token'ları — Bileşenler renk hex değerini değil, token ismin referans verir (primary, surface, onSurface…). Aynı token seti light ve dark bloklarında ayrı değerlerle tanımlanır → tek config ile açık+koyu mod.
  • consentKeys grup seviyesindediritems[] yalnız teknoloji/amacı açıklar; onay durumu grubun kimliğinde taşır. Etiketlere dağıtım SDK tarafında yapılır (02 adımında, §6).

5.3 Örnek Yanıt (örnek config gövdesi — özet)

Aşağıda envelope + config'in ilk kısımları gösterilir. Üretimdeki config, gerçek markaya/müşteriye göre doldurulur; buradaki değerler örnek (placeholder) amaçlıdır.

{
"success": true,
"code": "OK",
"consentId": "ck_mobildev_0001",
"deliveredAt": "2026-09-20T11:33:30Z",
"contentVersion": "2",
"tokenConsumed": false,
"config": {
"schemaVersion": "2.0",
"meta": {
"consentId": "ck_mobildev_0001",
"organization": "Mobildev",
"contentVersion": "2",
"contentMode": "sample",
"generatedAt": "2026-09-18T10:20:00Z"
},
"behavior": {
"defaultLanguage": "tr-TR",
"availableLanguages": ["tr-TR", "en-US", "de-DE"],
"allowLanguageChange": true,
"showConsentId": false,
"promptATTdialog": true,
"displayATTStatus": false,
"retrigger": { "onConfigChange": true, "onMajorChange": true, "interval": null }
},
"theme": {
"scheme": "system",
"light": { "primary": "#1976D2", "onPrimary": "#FFFFFF", "surface": "#F6F8FB", "onSurface": "#1F2328" },
"dark": { "primary": "#8AB4F8", "onPrimary": "#0B2E5C", "surface": "#1B2027", "onSurface": "#E6E9EF" },
"typography": { "family": "system-ui, sans-serif", "title": { "size": 18, "weight": 700 }, "body": { "size": 14, "weight": 400 } },
"radius": 16,
"spacing": 20
},
"banner": {
"layout": { "type": "bottomSheet", "showDragHandle": true, "maxHeightPercent": 82 },
"logo": { "show": true, "src": "", "size": 46, "position": "center" },
"title": { "langKey": "banner_title" },
"description": { "langKey": "banner_description", "maxLines": 6, "format": "plain" },
"buttons": {
"direction": "vertical", "gap": 10, "height": 50, "stretch": true,
"list": [
{ "id": "accept_all", "style": "filled", "langKey": "banner_btn_accept_all", "colorToken": "primary" },
{ "id": "reject_all", "style": "outlined", "langKey": "banner_btn_reject_all", "colorToken": "primary" },
{ "id": "modify", "style": "text", "langKey": "banner_btn_modify", "colorToken": "primary" }
]
}
},
"manager": {
"title": { "langKey": "manager_title" },
"showBack": true,
"groupRow": { "showToggle": true, "showChevron": true, "showIcon": false },
"groups": [
{ "id": "essential", "lockState": true, "defaultState": "on",
"consentKeys": ["security_storage"],
"items": [ { "id": "session", "scope": "first_party" }, { "id": "fraud", "scope": "first_party" } ] },
{ "id": "functionality", "lockState": null, "defaultState": "off",
"consentKeys": ["personalization_storage", "functionality_storage"] },
{ "id": "targeting", "lockState": null, "defaultState": "off",
"consentKeys": ["ad_storage", "ad_user_data", "ad_personalization"] },
{ "id": "tracking", "lockState": null, "defaultState": "off",
"consentKeys": ["analytics_storage"] }
],
"footer": { "position": "sticky", "actions": [
{ "id": "accept_all", "style": "outlined", "langKey": "banner_btn_accept_all", "colorToken": "primary" },
{ "id": "save", "style": "filled", "langKey": "manager_btn_save", "colorToken": "primary" }
] }
},
"detail": { "showBack": true, "sections": { "showTechnology": true, "showPurpose": true, "showToggle": true }, "links": [], "actions": [ { "id": "save", "style": "filled", "langKey": "manager_btn_save", "colorToken": "primary" } ] },
"localization": { "tr-TR": { "…": "…" }, "en-US": { "…": "…" }, "de-DE": { "…": "…" } }
}
}

localization bloğu, config'deki tüm langKey alanlarına karşılık gelen metindir (banner, manager, gruplar, öğeler, runtime durum metinleri). Her dil bloğu aynı anahtar setine sahiptir; behavior.availableLanguages'indeki her dil için bir blok zorunludur. Eksik anahtar → SDK defaultLanguage'ye fallback eder.

Bu örneğin aynısı, envelope ve tam config gövdesiyle birlikte ayrıca [01-config.response.json](./01-config.response.json) dosyasında yer alır. Not: bu .md içinde localization bloğu yer tasarrufu için özetlenmiş görünür; .json dosyasında üç dilin tam metin setiyle geçer.


6. Token Yaşam Döngüsü (KRİTİK)

Token = imzalı, oturum bazlı bir kimlik (session credential). "Tek kullanımlık" ifadesi tek HTTP çağrısı değil, tek consent-oturumu anlamına gelir. Döngü, aynı token'ın hem bu adımda hem onay adımında kullanılmasını gerektirir.

ÖzellikAçıklama
KökenAUTH (00), her başarılı çağrısında bir token üretir. Bir AUTH → bir token.
BağlılıkToken belirli bir consentId'ye bağlıdır. Başka bir consentId ile kullanılamaz (→ INVALID_TOKEN).
Geçerlilik penceresitokenExpiresIn (sn; varsayılan 300 = 5 dk). Pencere dolunca token geçersiz olur (TOKEN_EXPIRED).
GET /config (bu adım, okuma)Token'ı tüketmez. Config çekilir; token oturumda yaşamaya devam eder, tokenConsumed: false döner. Aynı pencerede yeniden denenebilir (retry güvenli).
POST /consent (02, yazma)Başarılı onay kaydı, oturumu tamamlar → token'ı tüketir. Sonrası için token ölüdür.
Yaşam sonuPencere dolunca veya onay kaydı oturumu kapatınca token geçersizleşir → sonraki etkileşim yeni AUTH ile başlar.
AUTH ──üretir──▶ TOKEN (consentId'ye bağlı, 300 sn)

┌───────────┴───────────┐
│ (okuma) │ (yazma)
▼ ▼
GET /config POST_CONSENT
token TÜKELENMEZ token TÜKETİLİR (oturum kapanır)
(retry serbest) ──────────────────────────▶
│ │
└──► pencere dolunca / oturum kapanınca ──► YENİ AUTH

Sonuç: AUTH'tan gelen token, bir consent oturumu boyunca hem config okuma (tüketmez) hem onay yazma (tüketir) için geçerlidir. Bu adımı başarıyla tamamladıktan sonra aynı token'la 02 · POST_CONSENT'e güvenle geçebilirsiniz. Token yalnızca gerçek durum değişikliği (onay kaydı) sonucunda veya süresi dolunca ömürden düşer.


7. Hata Kodları

Hatalarda ortak gövde döner: { success:false, code, message, retryable, requestId }. (message teşhis metnidir; UI'da gösterilmez — kullanıcıya gösterilecek metin localization bloklarından gelir, ör. error_state.)

GET /config bir token-bearer okuma olduğu için, AUTH'taki HMAC bağlı kodlar (SIGNATURE_MISMATCH, REPLAY_DETECTED…) bu sözleşmede yoktur. Yalnız token/consent kaynaklı kodlar:

codeHTTPretryableAçıklama / SDK müdahalesi
OK200Config başarıyla getirildi.
INVALID_TOKEN401HayırToken geçersiz/bilinmiyor, veya bağlı consentId ≠ path/gövde consentId → yeni AUTH (taze token).
TOKEN_EXPIRED401HayırtokenExpiresIn dolmuş → yeni AUTH, ardından config'i yeniden çek.
TOKEN_CONSUMED401HayırToken daha önce bir onay kaydı ile tüketilmiş → yeni AUTH.
CONSENT_NOT_FOUND404HayırBu consentId için yayımlanmış config yok → consentId doğrulanmalı; varsa bundled config fallback (§8).
CONFIG_UNAVAILABLE503EvetConfig mevcut ama şu an servis edilemiyor → bundled config fallback, arka planda backoff ile dene.
VALIDATION_ERROR400HayırGövde şemayı karşılamıyor (örn. locale biçimi, zorunlu eksik alan) → detail[] alan hatalarını düzelt.
RATE_LIMITED429EvetHız sınırı → Retry-After (sn) kadar bekle, yeniden dene.
SERVER_ERROR500EvetSunucu iç hata → bundled config fallback, arka planda backoff ile dene.

retryable semantiği: false → aynı istekle (aynı token) tekrar denemek işe yaramaz; yeni AUTH gerekir. true → aynı istek (token hâlâ geçerliyse) daha sonra yeniden denenebilir.


8. Offline / Fallback Davranışı (KRİTİK)

Onay deneyimi sessizce bozulmamalı. Config getirilemese bile kullanıcı onay akışını yaşar.

SenaryoSDK davranışı
INVALID_TOKEN / TOKEN_EXPIRED / TOKEN_CONSUMEDYeni AUTH başlat → taze al → config'i yeniden çek. (Eski bir token ile retry boşuna 401 üretir.)
SERVER_ERROR / CONFIG_UNAVAILABLE / RATE_LIMITED / timeout (15 sn)Bundled (SDK'ya dahil) config ile devam et; arka planda exponential backoff ile sunucuyu dene. Bağlantı gelince + taze token ile config yenile.
Hiç önbellek yok ve çevrimdışı (ilk kurulum)Bundled varsayılan config ile onay akışı çalışır; kullanıcı boş ekranda bırakılmaz.
CONSENT_NOT_FOUNDconsentId geçersiz/yayınlanmamış → bundled config varsa onunla devam, yoksa onay UI'ı zarifçe devre dışı (uygulama normal akışına döner).

Kural: Hiçbir hatada onay deneyimi "boş ekran" veya "kilitlenmiş durum" üretmez. Okuma retry'ye toleranslı olduğu için backoff sınırlıdır; sonsuz döngü üretilmez.


9. Developer Notları

  1. GET /config = OKUMA yolu; yalnız bearer token (HMAC/nonce yok). Sunucu token'ı X-Consent-Token header'ından doğrular; replay koruması token'ın consentId-bağlılığı + tokenExpiresIn penceresi + oturum tüketimi ile sağlanır. SDK, ağ kesintisinden sonra güvenle retry yapabilir. (Yazma yolu olan POST_CONSENT ise HMAC+nonce ister.)
  2. Token = oturum kimliği (one per AUTH), tek HTTP çağrısı DEĞİL. Bu adım tamamlanınca tokenConsumed: false döner → aynı token ile POST_CONSENT'e güvenle geçilir.
  3. Response config alanı = tam config. SDK parse eder: behavior (dil/ATT/retrigger), theme, banner, manager.groups[] (+consentKeys[]+items[]), detail, localization. Config değişikliğinde örnek de güncellenir.
  4. Sunucu tüm dilleri döndürür; dil çözümlemesi SDK'da. Request locale'i response'u daraltmaz; SDK behavior.defaultLanguage + kullanıcı tercihi + availableLanguages ile aktif dili seçer. Dil değiştirmek yeniden istek atmayı gerektirmez.
  5. Akışı sırala: AUTH (token al) → updateRequired ise bu adım (tam config, parse → UI kur) → kullanıcı karar verirse POST_CONSENT (aynı token ile) → response localState'ı önbelleğe yaz → döngü kapalı.
  6. consentKeys grup seviyesindedir; etiket dağıtımı SDK'dadır. Config'deki groups[].consentKeys ve onay adımının döndürdüğü {[groupId]: state} haritası, SDK tarafında etiket key'lerine yayılır (02 adımında). Sunucu config'i ham olarak döndürür; çevirimi SDK sorumluluğudur.
  7. Çapraz-doğrulama: Sunucu path {consentId} ↔ gövde consentId ↔ token'ın bağlı consentId üçlüsünü karşılaştırır; uyumsuzluk 401 INVALID_TOKEN döndürür. SDK üçünü de AUTH çıktısından/istekten doğru üretmelidir.