> ## 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.

# إدارة الموافقة والإيصالات

> تسجيل الموافقة على الرسائل لكل قناة والاستعلام عنها ومراقبتها في Orbit — بما في ذلك تتبع الأساس القانوني وفق GDPR وإيصالات موقّعة من مدير الموافقة وفق قانون DPDP الهندي.

# إدارة الموافقة والإيصالات

قبل مراسلة أي جهة اتصال عبر قناة خاضعة للتنظيم، تحتاج عمومًا إلى أساس
قانوني — وغالبًا ما يكون **الموافقة**. تُعد واجهة Consent API في Orbit
السجل المرجعي لمن وافق أو رفض، وعلى أي قناة، ومتى، وبموجب أي أساس
قانوني. كل عملية كتابة تتشر إلى الواجهات التي تُستخدم لتحديد السماح بالإرسال،
وبالتالي فإن تسجيل الموافقة هنا هو ما يتيح (أو يمنع) الرسالة فعليًا. ويمكنك أيضًا
[تصدير المسار الكامل](#exporting-the-consent-proof-of-record) كملف
CSV أو JSON جاهز للتدقيق.

جميع نقاط النهاية أدناه متجذرة على
`https://api.orbit.devotel.io/api/v1/compliance`.

<Warning>
  تسجيل الموافقة في Orbit يُنشئ مسارًا قابلًا للتدقيق، لكنه وحده لا
  يجعل الإرسال قانونيًا. تظل مسؤولًا عن الحصول على موافقة صالحة وعن
  المحتوى الذي تُرسله. هذه الصفحة ليست استشارة قانونية.
</Warning>

***

## القنوات والحالات

تُتتبع الموافقة **لكل قناة على حدة**. مجموعة القنوات المدعومة هي:

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

كل زوج `(contact, channel)` يُحوّل إلى إحدى ثلاث حالات:

| الحالة      | المعنى                                                               |
| ----------- | -------------------------------------------------------------------- |
| `opted_in`  | الموافقة ممنوحة ولم تُسحَب.                                          |
| `opted_out` | الموافقة سُحبت، أو سُجّل رفض صريح.                                   |
| `unknown`   | لا يوجد سجل موافقة للزوج — وبوابة الإرسال لديك هي من يقرر الافتراضي. |

***

## تسجيل الموافقة

`POST /compliance/consent` يسجّل موافقة أو رفضًا عبر قناة أو
أكثر في استدعاء واحد. حدّد جهة الاتصال بـ `contact_id`
**أو** بـ `identifier` (بريد إلكتروني أو هاتف بصيغة E.164 أو معرّف WhatsApp — وOrbit
يحدد النوع تلقائيًا).

```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`:

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

| الحقل                       | النوع                 | ملاحظات                                                                                                                        |
| --------------------------- | --------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| `contact_id` / `identifier` | string                | قدّم أحدهما.                                                                                                                   |
| `channels`                  | string\[]             | قناة واحدة أو أكثر من المجموعة؛ تُزال التكرارات وتُرتّب.                                                                       |
| `opt_in`                    | boolean               | **إلزامي.** `true` = موافقة، `false` = رفض.                                                                                    |
| `source`                    | string                | كيف التُقطت الموافقة (مثل `web_form`, `import`, `double_opt_in`). الافتراضي `consent_api`.                                     |
| `consent_type`              | string                | فئة الغرض، مثل `marketing`, `transactional`. الافتراضي `messaging`.                                                            |
| `lawful_basis`              | enum                  | الأساس وفق GDPR المادة 6: `consent`, `contract`, `legal_obligation`, `vital_interests`, `public_task`, `legitimate_interests`. |
| `purpose`                   | string                | نص حر يصف الاستخدام (≤ 500).                                                                                                   |
| `consent_text_version`      | string                | إصدار الإشعار الذي وافق عليه الشخص.                                                                                            |
| `consent_proof_url`         | string (url)          | رابط لقطة شاشة أو مستند موقّع.                                                                                                 |
| `valid_until`               | string (ISO-8601 UTC) | اللحظة المطلقة التي تنتهي فيها الموافقة. للموافقة فقط — تُتجاهل عند الرفض. متبادل الاستبعاد مع `expires_in_days`.              |
| `expires_in_days`           | integer               | نافذة صلاحية نسبية (1–3650 يومًا من الآن). للموافقة فقط. متبادل الاستبعاد مع `valid_until`.                                    |
| `metadata`                  | object                | مفاتيح/قيم مخصصة اعتباطية.                                                                                                     |

تقديم **كليهما** `valid_until` و `expires_in_days` أمر ملتبِس ويُرفَض
بـ `422 VALIDATION_ERROR`. عند تحديد نافذة، يُرجع الرد `201`
قيمة `valid_until` المحسوبة (لحظة الانتهاء المطلقة)؛ وتكون `null`
لمنح غير منتهية الصلاحية أو للرفض. إعادة تسجيل الموافقة بنافذة جديدة
**تمدّد** الصلاحية — يبقى `granted_at` الأصلي محفوظًا، لكن تُحدَّث
نهاية الصلاحية.

**ماذا يفعل الكتابة.** كل قناة مسجّلة تحدّث أربع وُجوه متزامنة:
جدول التدقيق `consent_records`، مرآة `channel_preferences` لجهة
الاتصال (المسار السريع للقراءة الذي تتحقق منه إرسالاتك)،
`suppression_list` (عند الرفض)، وسياج STOP قصير العمر في Redis
بحيث تلتزم دُفعات الحملة الجارية بالتغيير خلال \~10 دقائق.

<Note>
  الكتابات **آمنة جزئيًا**: إن فشلت قناة واحدة، تبقى القنوات الأخرى
  سارية. قارن `consent_record_ids.length` بعدد القنوات التي طلبتها
  لاكتشاف كتابة جزئية. إعادة تسجيل الموافقة لقناة موافق عليها أصلًا
  تحدّث البيانات الوصفية/الإثبات لكن **تحافظ على `granted_at` الأصلي**.
</Note>

***

## الاستعلام عن الموافقة

`GET /compliance/consent/lookup` يُرجع الحالة الحالية لزوج
`(contact, channel)` واحد — استخدمه كبوابة قبل الإرسال.

```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
}
```

حالة `unknown` تعني عدم وجود سجل للزوج — ويقرر تطبيقك ما إذا
كان ذلك يعني وجود موافقة (بعض التدفقات التعاملية) أو منع الإرسال
(معظم التدفقات التسويقية).

الحقول الثلاثة الأخيرة تُبلغ عن الموافقة المقيدة زمنيًا وهي **دائمًا
حاضرة**:

| الحقل                     | النوع          | ملاحظات                                                                                                                  |
| ------------------------- | -------------- | ------------------------------------------------------------------------------------------------------------------------ |
| `valid_until`             | string \| null | لحظة انتهاء المنح، أو `null` عندما لا تنتهي الموافقة (أو يكون الزوج رافضًا).                                             |
| `expired`                 | boolean        | `true` عندما يكون المنح موافقًا عليه لكن `valid_until` أصبح في الماضي. عامِل المنح المنتهي كلا موافقة عند بوابة الإرسال. |
| `requires_reconfirmation` | boolean        | يعكس `expired` — إشارة لتشغيل تدفق إعادة الإذن. امسحه بتسجيل موافقة جديدة (مع نافذة جديدة اختياريًا).                    |

***

## العثور على الموافقات المنتهية

`GET /compliance/consent/expiring` يمسح المستأجر بحثًا عن الموافقات
التي انتهت نافذة صلاحيتها أو على وشك الانتهاء — وهو المدخل لحملة
إعادة الإذن (إعادة التأكيد). تُرجع فقط المنح التي تحمل `valid_until`؛
الموافقة غير المنتهية لا تظهر أبدًا.

```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"
```

معاملات الاستعلام:

| المعامل       | النوع   | ملاحظات                                                                                                                                       |
| ------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| `within_days` | integer | أفق الاستشراف (0–3650، الافتراضي 30). يُرجع المنح التي `valid_until` فيها عند أو قبل الآن + `within_days`؛ المنح المنتهية أصلًا تُضمّ دائمًا. |
| `channel`     | enum    | اختياري — تقييد لقناة واحدة.                                                                                                                  |
| `status`      | enum    | `all` (الافتراضي), `expired` (تجاوز `valid_until` أصلًا), أو `expiring` (ما زال صالحًا لكن ضمن الأفق).                                        |
| `limit`       | integer | حجم الصفحة (1–100، الافتراضي 50).                                                                                                             |
| `cursor`      | string  | مؤشر ترقيم مُعْتَم — مرِّره حرفيًا كما هو.                                                                                                    |

```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
}
```

العناصر مُرتَّبة من الأقدم انتهاءً أولًا. كل عنصر يحمل `status`
(`expired` أو `expiring`) لتفصل "يجب إعادة التأكيد الآن" عن
"تحذير قبل إغلاق النافذة". إعادة التأكيد هي موافقة عادية عبر
`POST /compliance/consent` — اختياريًا مع `valid_until`
أو `expires_in_days` جديدة.

<Tip>
  عامِل `next_cursor` كمُعْتَم ومرِّره حرفيًا؛ القيمة `null` تعني
  الصفحة الأخيرة. المؤشر غير الصالح أو المنتهي يُعامَل كصفحة أولى
  جديدة لا كخطأ.
</Tip>

***

## مصافحات الموافقة المؤكدة (الاشتراك المزدوج)

تؤكّد `POST /compliance/consent` العادية المنح — فهي السجل المرجعي
بمجرد حصول سطحك الخاص على الموافقة. عندما تتطلب طبقة الدليل
**ردًا مسجّلًا من المستلِم** (الموافقة الكتابية الصريحة وفق TCPA، أو
الاشتراك المؤكد في الاتحاد الأوروبي، أو مراجعة حملة 10DLC)، وجّه
**مصافحة الاشتراك المزدوج** المُدارة بدلًا من ذلك:

1. `POST /compliance/consent/double-opt-in` — **البدء**: يسجّل
   صفًا *معلّقًا* (ليس منحة موافقة بعد) ويُرجع نص
   موجه التأكيد للزوج.
2. يردّ المستلِم؛ فمرِّر النص إلى
   `POST /compliance/consent/double-opt-in/confirm` — **التأكيد**:
   كلمة مفتاحية إيجابية مقابل الموجه المعلّق تحوّل الزوج إلى منحة
   `opted_in` مؤكدة.
3. `GET /compliance/consent/double-opt-in/status` — **القراءة**:
   الحالة الحالية (`opted_in` | `opted_out` | `pending` | `none`)
   مع علمَي `confirmed` / `awaiting_reply`، دون آثار جانبية.

المصافحات المؤكدة تدخل في نفس سجل الموافقة الذي توثّقه هذه الصفحة —
ويقرؤها `/lookup` و `/history` والتصدير بالطريقة ذاتها. حتى
تؤكَّد، فإن المصافحة المعلّقة ليست منحة موافقة. ملكية المستأجر:
لا شيء يبدأ مصافحة نيابة عن المنصة. الآليات الكاملة في
[مصافحات الموافقة المؤكدة (الاشتراك المزدوج)](/compliance/double-opt-in).

***

## سجل الموافقة

`GET /compliance/consent/history` يُرجع مسار التدقيق الكامل
المُصفَّح لجهة اتصال — كل منحة وسحب، الأحدث أولًا.

معاملات الاستعلام: `contact_id` أو `identifier` (أحدهما إلزامي)،
معامل اختياري `channel` للتصفية، و `limit` (≤ 100، الافتراضي 50)،
و `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` كمُعْتَم — مرِّره حرفيًا لجلب الصفحة
  التالية. المؤشر غير الصالح أو المنتهي يُعامَل كصفحة أولى
  جديدة لا كخطأ.
</Tip>

***

## تصدير إثبات سجل الموافقة

`GET /compliance/consent/export` ينزّل مسار الموافقة على مستوى
المستأجر كملف واحد — وهو الجواب على تدقيق TCPA، أو عبء الإثبات وفق
GDPR المادة 7(1)، أو طلب الاكتشاف ("أظهر من وافق أو رفض،
ومتى، وعلى أي قناة، ومن أي مصدر"). وهو النظير الجماعي
لـ `/lookup` و `/history`.

```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
```

معاملات الاستعلام:

| المعامل       | النوع   | ملاحظات                                                                                          |
| ------------- | ------- | ------------------------------------------------------------------------------------------------ |
| `format`      | enum    | `csv` (الافتراضي — RFC-4180، يفتح في جدول بيانات) أو `json`.                                     |
| `channel`     | enum    | تقييد لقناة واحدة.                                                                               |
| `state`       | enum    | `all` (الافتراضي), `opted_in`, `opted_out`, أو `unknown`.                                        |
| `contact_id`  | string  | تقييد التصدير بجهة اتصال واحدة — شكل طلب الاكتشاف.                                               |
| `from` / `to` | string  | نطاق تاريخي على `created_at` للسجل. يقبل تاريخًا مجردًا `YYYY-MM-DD` أو تاريخًا ووقتًا RFC-3339. |
| `limit`       | integer | الصفوف المطلوب تضمينها (1–50,000، الافتراضي 50,000).                                             |

كل صف يحمل حدث موافقة واحدًا مُربَطًا بمعرّفات جهة الاتصال —
`record_id`, `contact_id`, `email`, `phone`,
`whatsapp_id`, `channel`, `consent_state`, `granted`, `consent_type`,
`source`، إضافة إلى أعمدة عبء الإثبات وفق GDPR: `lawful_basis`,
`purpose`, `policy_template`, `consent_text_version`,
`consent_proof_url`, `ip_address`, `valid_until`، وطوابع
المنح/السحب/التحديث الزمنية.

تنزيلات CSV تصل باسم ملف مؤرخ
(`consent-proof-of-record-YYYY-MM-DD.csv`) ولا تعبر ذاكرة تخزين
مؤقتة للقراءة (`Cache-Control: no-store`). اطلب `format=json`
فيُرجع الرد بدلًا من ذلك غلاف `columns` / `items` / `count` —
نفس البيانات للمستهلكين البرمجيين.

الوصول مقيّد بمفاتيح **owner** و **admin** — فالحمولة تكشف
معرّفات المستلِمين الخام على مستوى المستأجر، وهي نفس طبقة الثقة
كاستيراد قائمة المنع. وكل تشغيل تصدير يُكتب هو نفسه في سجل
التدقيق مع مرشحاته وعدد صفوفه.

<Note>
  عندما يتجاوز سجلّك 50,000 صف يُقتطع التصدير عند الحد: تحمل
  استجابات CSV ترويسة `X-Export-Truncated: true`، ويضبط غلاف
  JSON `truncated: true`. ضيّق البحث بالقناة أو الحالة، أو صفّح
  بتصدير نوافذ تاريخ متتالية بـ `from`/`to`.
</Note>

***

قانون الهند **لحماية البيانات الشخصية الرقمية (DPDP)** يقدّم
مفهوم **مدير الموافقة (Consent Manager)** — وسيط مسؤول ومسجّل
ينتج **إيصالات موافقة موقّعة تشفيريًا** نيابة عن صاحب البيانات.
يمكن لـ Orbit تسجيل المدراء الذين يمرّ عبرهم المستخدمون والتحقق من
الإيصالات التي يصدرونها.

### تسجيل مدير موافقة

`POST /compliance/consent/managers` (admin/owner) يسجّل مديرًا
ويخزّن مفتاحه العام (ECDSA P-256 SPKI PEM) المستخدم في التحقق
من كل إيصال يوقّعه.

```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` يسرد المدراء المسجّلين
  (النشطون أولًا).
* `PUT /compliance/consent/managers/{id}` يحدّث واحدًا أو يعطّله
  (تحديث جزئي؛ جميع الحقول اختيارية).

### تخزين إيصال موقّع

`POST /compliance/consent/receipts` يتحقق من إيصال موقّع من مدير
ويستمرّ بتخزينه كموافقة. يُفحَص التوقيع (ECDSA P-256 / SHA-256,
IEEE-P1363, base64url) مقابل المفتاح العام للمدير المسجّل على
ترميز JSON قانوني مستوحى من JCS بمفاتيح مرتبة للحمولة **قبل**
تخزين أي شيء. هذا الترميز القانوني يرتّب مفاتيح الكائنات تصاعديًا
بحسب وحدة تشفير UTF-16 ويُسقط المسافات غير الدالة، لكنه ليس تطبيقًا
كاملًا لـ RFC 8785 — وتحديدًا لا يطبّق قواعد تسلسل الأرقام المفروضة
في JCS. وقِّع الإيصالات بصيغة المفاتيح المرتبة نفسها التي يستخدمها
Orbit بدلًا من افتراض أن متحققًا مطابقًا للمواصفة RFC 8785 سينتج
بصمة مطابقة.

```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` مع `{ "id": …, "receipt_id": …, "verified": true }`.
التوقيع السيئ، أو المدير غير المسجّل/غير النشط، يُرجع `422
CONSENT_RECEIPT_INVALID` — وتشير التفاصيل إلى أن الحمولة ربما
تعرّضت للعبث أو أن المدير ربما بدّل مفاتيحه.

### إعادة التحقق من إيصال مخزّن

`POST /compliance/consent/receipts/{id}/verify` يعيد فحص
إيصال مخزّن سابقًا مقابل مفتاح المدير **الحالي** — استخدمه
أثناء التدقيق لتأكيد أن الإيصال ما زال صالحًا وما إذا كان
مديره ما زال نشطًا. يقبل `{id}` معرّف سجل الموافقة أو
`receipt_id`.

<Note>
  تتطلب إيصالات الموافقة ترحيل `consent_managers` للمستأجر. على
  المستأجرين السابقين له، تتدهور مسارات القراءة بشكل متدرج: يُرجع
  سرد المدراء قائمة فارغة ويُرجع نقطة إعادة التحقق `404`. إصدار
  الإيصال fail-closed، لذا تُرجع `POST
      /compliance/consent/receipts` الخطأ `422 CONSENT_RECEIPT_INVALID`
  على المستأجرين السابقين للترحيل بدلًا من التدهور — نفّذ الترحيل
  قبل إصدار الإيصالات.
</Note>

***

## مراجع ذات صلة

* [تجميع وضعية GDPR من البداية إلى النهاية](/compliance/gdpr-posture-guide) —
  التسلسل الذي تغذيه طبقة الموافقة هذه.
* [مصافحات الموافقة المؤكدة (الاشتراك المزدوج)](/compliance/double-opt-in) —
  تدفق البدء/التأكيد/الحالة فوق سجل الموافقة العادي.
* [وضعية الموافقة: سياسات الموافقة غير المعروفة](/compliance/consent-default-policy) —
  مقابض مستوى المؤسسة التي تقرر ما قد تتلقاه جهات الاتصال التي لا
  تملك صفًا في السجل (إرسالات التسويق مقابل نشر CDP).
* [قوائم الرفض والمنع](/compliance/opt-out-suppression) —
  استيراد الرفضات بالجملة وكيف تُغلَق الإرسالات بواسطة قائمة المنع.
* [DSAR](/compliance/dsar) — تلبية طلبات الوصول/الحذف على
  سجل الموافقة.
* [التسجيل في DLT الهند](/compliance/dlt-india) — طبقة التسجيل
  التي تُقرن بموافقة DPDP على الرسائل القصيرة الهندية.
* [مرجع API ← Compliance](/api-reference/endpoints/compliance) — مخططات
  الطلب/الاستجابة الكاملة (مُعاد توليدها من API الحي).
