> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orbit.devotel.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Onay Yönetimi ve Makbuzlar

> Orbit üzerinde kanal bazlı mesajlaşma onayını kaydedin, sorgulayın ve denetleyin — GDPR hukuki dayanak takibi ve Hindistan DPDP Consent-Manager imzalı makbuzları dahil.

# Onay Yönetimi ve Makbuzlar

Düzenlemeye tabi bir kanalda bir kişiye mesaj göndermeden önce
genellikle hukuki bir dayanağa — çoğunlukla da **onaya** — ihtiyacınız vardır.
Orbit'in onay API'si; kimin hangi kanalda, ne zaman ve hangi hukuki dayanakla
opt-in veya opt-out yaptığının kayıt sistemidir. Her yazma işlemi, gönderimlerinizin
denetlendiği yüzeylere yayılır; dolayısıyla onayı burada kaydetmek, bir mesajı
gerçekten engelleyen (veya engelini kaldıran) eylemdir. Ayrıca tüm kayıt izini
[denetime hazır CSV veya JSON dosyası olarak dışa aktarabilirsiniz](#exporting-the-consent-proof-of-record).

Aşağıdaki tüm uç noktalar şu kökte bulunur:
`https://api.orbit.devotel.io/api/v1/compliance`.

<Warning>
  Onayı Orbit'te kaydetmek denetlenebilir bir iz oluşturur; ancak tek başına
  bir gönderimi hukuken geçerli kılmaz. Geçerli onay almaktan ve gönderdiğiniz
  içerikten siz sorumlusunuz. Bu sayfa hukuki tavsiye değildir.
</Warning>

***

## Kanallar ve durumlar

Onay **kanal başına** takip edilir. Desteklenen kanal kümesi şunlardır:

`email`, `fax`, `instagram`, `line`, `messenger`, `push`, `rcs`,
`sms`, `viber`, `voice`, `whatsapp`.

Bir `(contact, channel)` çifti üç durumdan birine çözümlenir:

| Durum       | Anlam                                                               |
| ----------- | ------------------------------------------------------------------- |
| `opted_in`  | Onay verilmiş ve geri alınmamış.                                    |
| `opted_out` | Onay geri alınmış veya açık bir opt-out kaydedilmiş.                |
| `unknown`   | Çift için onay kaydı yok — varsayılanı gönderim geçidiniz belirler. |

***

## Onay kaydetme

`POST /compliance/consent`, tek bir çağrıda bir veya daha fazla kanalda
opt-in veya opt-out kaydeder. Kişiyi `contact_id` ile **ya da** `identifier` ile
(e-posta, E.164 telefon veya WhatsApp ID — Orbit türü otomatik olarak çözümleyerek)
tanımlayın.

```bash theme={null}
curl -X POST https://api.orbit.devotel.io/api/v1/compliance/consent \
  -H "Authorization: Bearer $ORBIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "identifier": "jordan@example.com",
    "channels": ["email", "sms"],
    "opt_in": true,
    "source": "web_form",
    "consent_type": "marketing",
    "lawful_basis": "consent",
    "purpose": "Weekly product newsletter and order updates",
    "consent_text_version": "tos-2026-04",
    "consent_proof_url": "https://example.com/proofs/abc123.png"
  }'
```

`201 Created` döndürür:

```json theme={null}
{
  "contact_id": "cnt_9f…",
  "consent_record_ids": ["cr_a1…", "cr_b2…"],
  "channels": ["email", "sms"],
  "state": "opted_in",
  "valid_until": null
}
```

| Alan                        | Tür                   | Notlar                                                                                                                         |
| --------------------------- | --------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| `contact_id` / `identifier` | string                | İkisinden birini sağlayın.                                                                                                     |
| `channels`                  | string\[]             | Kanal kümesinden bir veya daha fazla; tekilleştirilmiş ve sıralıdır.                                                           |
| `opt_in`                    | boolean               | **Zorunlu.** `true` = opt-in, `false` = opt-out.                                                                               |
| `source`                    | string                | Onayın nasıl yakalandığı (örn. `web_form`, `import`, `double_opt_in`). Varsayılan `consent_api`.                               |
| `consent_type`              | string                | Amaç kategorisi; örn. `marketing`, `transactional`. Varsayılan `messaging`.                                                    |
| `lawful_basis`              | enum                  | GDPR Madde 6 dayanağı: `consent`, `contract`, `legal_obligation`, `vital_interests`, `public_task`, `legitimate_interests`.    |
| `purpose`                   | string                | Kullanımı açıklayan serbest metin (≤ 500).                                                                                     |
| `consent_text_version`      | string                | Veri sahibinin kabul ettiği bildirimin sürümü.                                                                                 |
| `consent_proof_url`         | string (url)          | Ekran görüntüsüne veya imzalı belgeye bağlantı.                                                                                |
| `valid_until`               | string (ISO-8601 UTC) | Onayın sona erdiği mutlak an. Yalnızca opt-in — opt-out'ta yoksayılır. `expires_in_days` ile karşılıklı olarak dışlayıcıdır.   |
| `expires_in_days`           | integer               | Göreli geçerlilik penceresi (bugünden itibaren 1–3650 gün). Yalnızca opt-in. `valid_until` ile karşılıklı olarak dışlayıcıdır. |
| `metadata`                  | object                | İsteğe bağlı özel anahtar/değer çiftleri.                                                                                      |

**Hem** `valid_until` **hem** `expires_in_days` sağlamak belirsizlik
yaratır ve `422 VALIDATION_ERROR` ile reddedilir. Bir pencere
ayarladığınızda `201` yanıtı çözümlenen `valid_until` değerini (mutlak
geçerlilik anı) yansıtır; sona ermeyen bir onay veya opt-out için bu
değer `null`'dır. Zaten opt-in durumda olan bir kanal için onayı tazelemek,
meta veri/kanıtı yeniler ancak **orijinal `granted_at` korunur** — yalnızca
geçerlilik süresi güncellenir.

**Bir yazma işleminin yaptıkları.** Kaydedilen her kanal, senkronize
dört yüzeyi günceller: `consent_records` denetim tablosu, gönderim kontrol
noktalarınızın okuduğu hızlı yol olan kişinin `channel_preferences` aynası,
`suppression_list` (opt-out durumunda) ve uçuş halindeki kampanya
yığınlarının değişikliği \~10 dakika içinde uygulamasını sağlayan kısa
ömürlü bir Redis STOP-fence'i.

<Note>
  Yazma işlemleri **kısmen-hata-güvenlidir**: bir kanal başarısız olursa
  diğerleri yine de uygulanır. Kısmi bir yazmayı tespit etmek için
  `consent_record_ids.length` değerini istediğiniz kanal sayısıyla
  karşılaştırın. Zaten opt-in durumda olan bir kanal için onayı
  yeniden kaydetmek, meta veri/kanıtı tazeler ancak **orijinal
  `granted_at` değerini korur**.
</Note>

***

## Onay sorgulama

`GET /compliance/consent/lookup`, tek bir `(contact, channel)` çiftinin
güncel durumunu döndürür — gönderim öncesi geçit olarak kullanın.

```bash theme={null}
curl "https://api.orbit.devotel.io/api/v1/compliance/consent/lookup?identifier=jordan@example.com&channel=sms" \
  -H "Authorization: Bearer $ORBIT_API_KEY"
```

```json theme={null}
{
  "contact_id": "cnt_9f…",
  "channel": "sms",
  "state": "opted_in",
  "source": "web_form",
  "granted_at": "2026-04-02T10:11:00.000Z",
  "revoked_at": null,
  "lawful_basis": "consent",
  "purpose": "Weekly product newsletter and order updates",
  "consent_text_version": "tos-2026-04",
  "consent_proof_url": "https://example.com/proofs/abc123.png",
  "valid_until": null,
  "expired": false,
  "requires_reconfirmation": false
}
```

`state` değerinin `unknown` olması, çift için kayıt olmadığı anlamına gelir —
uygulamanız, bunun onay anlamına mı gelip gelmediğine (bazı işlemsel akışlar)
veya gönderimi engellemesi gerekip gerekmediğine (çoğu pazarlama akışı)
karar verir.

Son üç alan, zamana bağlı onay hakkında bilgi verir ve **her zaman
mevcuttur**:

| Alan                      | Tür            | Notlar                                                                                                                                                       |
| ------------------------- | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `valid_until`             | string \| null | Onayın sona erdği an; onayın hiç sona ermediği durumlarda (veya çift opt-out durumdaysa) `null`.                                                             |
| `expired`                 | boolean        | Opt-in onayının `valid_until` değeri artık geçmişte kaldığında `true`. Süresi dolmuş bir onayı gönderim geçidinizde artık-onay-olmayan olarak değerlendirin. |
| `requires_reconfirmation` | boolean        | `expired` aynası — yeniden izin akışı tetikleme ipucu. Yeni bir opt-in kaydı (isteğe bağlı yeni bir pencere ile) kaydettirerek temizleyin.                   |

***

## Süresi dolmakta olan onayları bulma

`GET /compliance/consent/expiring`, geçerlilik penceresi dolmuş veya
dolmak üzere olan opt-in'leri kiracı genelinde tarar — bu, yeniden izin
(yeniden onay) kampanyasının girdisidir. Yalnızca `valid_until` taşıyan
onaylar döndürülür; sona ermeyen onaylar hiçbir zaman görünmez.

```bash theme={null}
curl "https://api.orbit.devotel.io/api/v1/compliance/consent/expiring?within_days=30&status=all" \
  -H "Authorization: Bearer $ORBIT_API_KEY"
```

Sorgu parametreleri:

| Parametre     | Tür     | Notlar                                                                                                                                                                                |
| ------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `within_days` | integer | İleriye bakış ufku (0–3650, varsayılan 30). `valid_until` değeri şu an + `within_days` değerine eşit veya öncesinde olan onayları döndürür; süresi dolmuş onaylar her zaman dahildir. |
| `channel`     | enum    | İsteğe bağlı — tek bir kanal ile sınırlayın.                                                                                                                                          |
| `status`      | enum    | `all` (varsayılan), `expired` (`valid_until` zaten geçilmiş) veya `expiring` (hâlâ geçerli ancak ufukta).                                                                             |
| `limit`       | integer | Sayfa boyutu (1–100, varsayılan 50).                                                                                                                                                  |
| `cursor`      | string  | Opak sayfalama imleci — değişim yapılmadan ileri geri aktarılmalıdır.                                                                                                                 |

```json theme={null}
{
  "within_days": 30,
  "channel": null,
  "status": "all",
  "as_of": "2026-05-01T09:00:00.000Z",
  "items": [
    {
      "id": "cr_b2…",
      "contact_id": "cnt_9f…",
      "channel": "sms",
      "consent_type": "marketing",
      "source": "web_form",
      "lawful_basis": "consent",
      "granted_at": "2025-05-02T10:11:00.000Z",
      "valid_until": "2026-04-20T00:00:00.000Z",
      "expired": true,
      "status": "expired",
      "requires_reconfirmation": true
    }
  ],
  "next_cursor": null
}
```

Öğeler en eski süresi dolan önce olacak şekilde sıralanır. Her biri `status`
(`expired` veya `expiring`) taşır; böylece "hemen yeniden onay zorunlu"
ile "pencere kapanmadan uyar" ayrımı yapabilirsiniz. Yeniden onay, sıradan bir
`POST /compliance/consent` opt-in'dir — isteğe bağlı olarak taze bir
`valid_until` veya `expires_in_days` ile.

<Tip>
  `next_cursor` değerini opak olarak ele alın ve değişim olmadan
  ileri geri aktarın; `null` değeri son sayfa anlamına gelir. Geçersiz
  veya eski bir imleç, hata yerine yeni bir ilk sayfa olarak işlenir.
</Tip>

***

## Onaylı onay (çift opt-in) el sıkışmaları

Düz `POST /compliance/consent`, onayı belirtir — kendi yüzeyiniz
onayı aldıktan sonra kayıt sistemidir. Kanıt katmanı kayıtlı bir
**alıcı yanıtı** gerektirdiğinde (TCPA açık yazılı onay, AB onaylı
opt-in, 10DLC kampanya incelemesi), yönetilen **çift opt-in el
sıkışmasını** devreye alın:

1. `POST /compliance/consent/double-opt-in` — **başlat**: çift için
   *beklemede* (henüz onay verilmemiş) satır kaydedir ve onay istemi
   metnini döndürür.
2. Alıcı yanıt verir; metni `POST /compliance/consent/double-opt-in/confirm`
   — **onayla**: bekleyen isteme olumlu bir anahtar kelime, çifti
   onaylanmış bir `opted_in` onayına dönüştürür.
3. `GET /compliance/consent/double-opt-in/status` — **oku**:
   yan etkisiz (side-effect free) olarak mevcut durum (`opted_in` |
   `opted_out` | `pending` | `none`) artı `confirmed` /
   `awaiting_reply` bayrakları.

Onaylanan el sıkışmaları, bu sayfanın belgeleddiği onay defterine
kaydedilir — `/lookup`, `/history` ve dışa aktarım, bunları aynı şekilde
okur. Onaylanana kadar bekleyen bir el sıkışması onay verisi değildir.
Kiracıya ait: platform adına hiçbir el sıkışması başlatılmaz. Tam
mekaniği [Onaylı Onay (Çift Opt-In) El Sıkışmaları](/compliance/double-opt-in) sayfasında bulun.

***

## Onay geçmişi

`GET /compliance/consent/history`, bir kişiye ait tam sayfalanabilir
denetim izini döndürür — her onay verme ve geri alma, en yeniden
eskiye.

Sorgu parametreleri: `contact_id` veya `identifier` (bir zorunlu),
isteğe bağlı bir `channel` filtresi, `limit` (≤ 100, varsayılan 50)
ve bir opak `cursor`.

```json theme={null}
{
  "contact_id": "cnt_9f…",
  "channel": null,
  "items": [
    {
      "id": "cr_b2…",
      "channel": "sms",
      "consent_state": "opted_in",
      "granted": true,
      "source": "web_form",
      "granted_at": "2026-04-02T10:11:00.000Z",
      "revoked_at": null,
      "lawful_basis": "consent",
      "created_at": "2026-04-02T10:11:00.000Z"
    }
  ],
  "next_cursor": "eyJ0…"
}
```

<Tip>
  `next_cursor` değerini opak ele alın — bir sonraki sayfayı almak için
  değişim yapılmadan aktarın. Geçersiz veya eski bir imleç, hata yerine
  yeni bir ilk sayfa olarak işlenir.
</Tip>

***

## Onay-kanıt kaydını dışa aktarma

`GET /compliance/consent/export`, kiracı genelindeki onay izinizi
tek bir dosya olarak indirir — TCPA denetimi, GDPR Madde 7(1) ispat
yükü veya keşif talebi ("kim, ne zaman, hangi kanalda, hangi kaynağı
kullanarak opt-in veya opt-out yaptı") yanıtı. `/lookup` ve `/history`'nin
toplu muadilidir.

```bash theme={null}
curl "https://api.orbit.devotel.io/api/v1/compliance/consent/export?format=csv&state=opted_out" \
  -H "Authorization: Bearer $ORBIT_API_KEY" \
  -o consent-proof-of-record.csv
```

Sorgu parametreleri:

| Parametre     | Tür     | Notlar                                                                                                   |
| ------------- | ------- | -------------------------------------------------------------------------------------------------------- |
| `format`      | enum    | `csv` (varsayılan — RFC-4180, bir elektronik tabloda açılır) veya `json`.                                |
| `channel`     | enum    | Tek bir kanaldaki onayları kısırla.                                                                      |
| `state`       | enum    | `all` (varsayılan), `opted_in`, `opted_out` veya `unknown`.                                              |
| `contact_id`  | string  | Onayı tek bir kişiyle sınırlayın — keşif taleplerinin şekli.                                             |
| `from` / `to` | string  | Kayıt `created_at` üzerinde tarih aralığı. Düz `YYYY-MM-DD` tarihi veya RFC-3339 tarih saati kabul eder. |
| `limit`       | integer | Dahil edilecek satır sayısı (1–50.000, varsayılan 50.000).                                               |

Her satır bir onay olayının, kişinin tanımlayıcılarıyla birleşmesini
taşır — `record_id`, `contact_id`, `email`, `phone`,
`whatsapp_id`, `channel`, `consent_state`, `granted`, `consent_type`,
`source` ve GDPR ispat-yükü sütunları `lawful_basis`, `purpose`,
`policy_template`, `consent_text_version`, `consent_proof_url`,
`ip_address`, `valid_until` ile onay verme/ret/güncelleme zaman siempeleri.

CSV indirmeleri, tarihli bir dosya adı (`consent-proof-of-record-YYYY-MM-DD.csv`)
ile gelir ve bir okuma önbelleğini asla geçmez (`Cache-Control: no-store`).
`format=json` isteyin ve yanıt bunun yerine `columns` / `items` / `count`
zarfı döndürmesi gerçekleşir — programatik tüketiciler için aynı veriler.

Erişim, **owner** ve **admin** anahtarlarıyla sınırlıdır — içerik
kiracı genelinde ham alıcı tanımlayıcıları ortaya çıkarır; bu,
suppression import ile aynı güven katmanıdır. Her dışa aktarım çalıştırması,
filtreleri ve satır sayısıyla denetim günlüğüne yazılır.

<Note>
  Defteriniz 50.000 satırı aştığında dışa aktarım, kemanı kesi seker:
  CSV yanıtları `X-Export-Truncated: true` başlığını taşır ve JSON
  zarfı `truncated: true` ayarlar. Kanal veya duruma göre daraltın, ya da
  `from`/`to` kullanarak ardışık tarih pencereleriyle sayfalayın.
</Note>

***

Hindistan'ın **Dijital Kişisel Veri Koruma Yasası (DPDP)**, **Consent
Manager** kavramını tanıtır — veri sahibinin adını kullanarak kriptografik
olarak **imzalanmış onay makbuzlarını** basan sorumluluk sahibi kayıtlı
aracı. Orbit, kullanıcılarınızın kullanıdığı yöneticileri kaydedebilir ve
verdikleri makbuzları doğrular.

### Bir Consent Manager kaydetme

`POST /compliance/consent/managers` (admin/owner), bir yönetici kaydeder
ve her makbuzu doğrulamak için kullanılan ortak anahtarını (ECDSA P-256
SPKI PEM) saklar.

```bash theme={null}
curl -X POST https://api.orbit.devotel.io/api/v1/compliance/consent/managers \
  -H "Authorization: Bearer $ORBIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Acme Consent Manager",
    "manager_id": "acme-cm-001",
    "manager_url": "https://cm.acme.example",
    "public_key": "-----BEGIN PUBLIC KEY-----\n…\n-----END PUBLIC KEY-----",
    "country_code": "IN"
  }'
```

* `GET /compliance/consent/managers`, kayıtlı yöneticileri listeler
  (etkin olanlar önce).
* `PUT /compliance/consent/managers/{id}`, bir yöneticiyi günceller
  veya devre dışı bırakır (kısmi güncelleme; tüm alanlar isteğe bağlı).

### İmzalı makbuz saklama

`POST /compliance/consent/receipts`, yönetici tarafından imzalanan bir
makbuzu doğrular ve onay olarak kalıcı hale getirir. İmza (ECDSA P-256 /
SHA-256, IEEE-P1363, base64url), kayıtlı yöneticinin ortak anahtarına
karşı, **herhangi bir şey depolanmadan önce**, yük üzerinde JCS'den
esinlenen, sıralı anahtarlı bir JSON kanonikleştirmesiyle kontrol edilir.
Bu kanonikleştirme, nesne anahtarlarını UTF-16 kod birimi ile artana göre
sıralar ve anlamsız boşlukları siler; ancak tam bir RFC 8785 uygulaması
değildir — özellikle JCS'nin zorunlu sayı serileştirme kurallarını
uygulamıyor. Spec'e tam uyan bir RFC 8785 doğrulayıcısı eşleşen bir hash
üreteceğini varsaymak yerine, makbuzları Orbit'in kullandığı aynı
sıralı anahtar biçibiyle imzalayın.

```bash theme={null}
curl -X POST https://api.orbit.devotel.io/api/v1/compliance/consent/receipts \
  -H "Authorization: Bearer $ORBIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "contact_id": "cnt_9f…",
    "consent_manager_id": "acme-cm-001",
    "channel": "sms",
    "consent_type": "marketing",
    "receipt": {
      "receipt_id": "rcpt_77…",
      "issued_at": "2026-05-01T09:00:00.000Z",
      "purpose": "Promotional SMS",
      "fiduciary_id": "fid_acme",
      "signature": "MEUCIQ…",
      "payload": { "…": "…" }
    }
  }'
```

`201` döndürür: `{ "id": …, "receipt_id": …, "verified": true }`.
Hatalı imza veya kayıtsız/inaktif yönetici, `422 CONSENT_RECEIPT_INVALID`
döndürür — ayrıntı, yükün değiştirilmiş olabileceğini veya yöneticinin
anahtarları rotasyon ettiğini notlar.

### Saklanan makbuzu yeniden doğrulama

`POST /compliance/consent/receipts/{id}/verify`, daha önce saklanmış bir
makbuzu yöneticinin **güncel** anahtarıyla yeniden kontrol eder — bir
denetim sırasında makbuzun hâlâ geçerli olduğunu ve yöneticinin hâlâ
etkin olup olmadığını doğrulamak için kullanın. `{id}`, onay kaydı kimliği
ya da `receipt_id` kabul eder.

<Note>
  Onay makbuzları, kiracının `consent_managers` migrasyonunu gerektirir.
  Bunu önceden geçen kiracılarda, okuma yolları hoş bir şekilde bozulur:
  yönetici listesi boş bir liste döndürür ve yeniden doğrulama uç noktası
  `404` döndürür. Makbuz basmak fail-closed'dur; dolayısıyla `POST
      /compliance/consent/receipts`, migrasyon öncesi kiracılarda bozulma
  yerine `422 CONSENT_RECEIPT_INVALID` döndürür — makbuz basmadan önce
  migrasyonu çalıştırın.
</Note>

***

## İlgili referanslar

* [Bir GDPR Duruşunu Uçstante Uca Kurma](/compliance/gdpr-posture-guide) —
  bu onay katmanını besleyen sıra.
* [Onaylı Onay (Çift Opt-In) El Sıkışmaları](/compliance/double-opt-in) —
  düz bir onay kaydı üzerindeki başlat/onayla/durum akışı.
* [Onay Duruşu: Bilinmeyen-Onay Politikaları](/compliance/consent-default-policy) —
  defter satırı olmayan kişilere neyin gönderileceğine karar veren
  (pazarlama gönderileri veya CDP fanout) kuruluş düzeyindeki düğmeler.
* [Opt-Out ve Suppression Listeleri](/compliance/opt-out-suppression) —
  opt-out'ları toplu içe aktarma ve suppression listesinin gönderimleri
  nasıl kapıdışı yaptığını.
* [DSAR](/compliance/dsar) — onay kaydı üzerinde erişim/silme taleplerini
  yerine getirme.
* [DLT-Hindistan Onboarding](/compliance/dlt-india) — Hint SMS'teki DPDP
  onayıyla eşleşen kayıt katmanı.
* [API Referans → Uyum](/api-reference/endpoints/compliance) — tam
  istek/yanıt şemaları (canlı API'den yeniden üretilmiştir).
