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

# منح الاستحقاق

> الحمولة المرسلة إلى نقطة نهاية الويب هوك الخاصة بك عند إنشاء أو تسليم أو فشل أو إلغاء منحة الاستحقاق.

## أحداث منح الاستحقاق عبر webhook

يتم إطلاق هذه الأحداث كلما تغيرت حالة منحة استحقاق العميل، على سبيل المثال عند إنشاء مفتاح ترخيص، أو تعيين دور Discord، أو توفير رابط تنزيل، أو سحب الوصول. اشترك في هذه الأحداث للحفاظ على توافق تطبيقك مع ما يمكن لكل عميل الوصول إليه.

| الحدث                         | الوصف                                                                                                                                          |
| ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| `entitlement_grant.created`   | تم إنشاء صف منح جديد. الحالة هي `delivered` مباشرة لمفاتيح الترخيص المفعلة تلقائيًا، و `pending` لمفاتيح الترخيص المفعلة يدويًا وكل تكامل آخر. |
| `entitlement_grant.delivered` | ينتقل المنح إلى الحالة المُسلمة. الآن يمكن للعميل الوصول إلى المنصة المستحقة أو الملف أو مفتاح الترخيص.                                        |
| `entitlement_grant.failed`    | فشلت عملية التسليم ولن تُعاد المحاولة. قم بفحص `error_code` و `error_message`.                                                                 |
| `entitlement_grant.revoked`   | تم سحب الوصول. قم بفحص `revocation_reason` لفهم السبب.                                                                                         |

تشترك جميع الأحداث الأربعة في نفس الحمولة `EntitlementGrantResponse` الموثقة في المخطط أدناه.

***

## محفزات الأحداث

### entitlement\_grant.created

تم إدخال صف المنحة للتو. يكون للمنحة دائمًا `id` ثابت من هذه النقطة فصاعدًا، حتى لو تغيرت حالتها. استخدم هذا الحدث لتسجيل أن الإنجاز قيد التقدم.

بالنسبة **لمفاتيح الترخيص المفعلة تلقائيًا** يتم إدراج الصف مباشرة مع تعبئة `status: "delivered"` و `delivered_at`، لذا يتبع حدث `created` واحد ذلك بدون تغييرات حالة أخرى ما لم يتم إلغاء المنح لاحقًا.

بالنسبة **لمفاتيح الترخيص المفعلة يدويًا** (الاستحقاقات مع `fulfillment_mode: manual`) يصل الصف مع `status: "pending"` وبدون كائن `license_key` — لا يوجد مفتاح بعد. هذا الحدث هو إشارة لك بأن هناك مفتاحًا ينتظر التفعيل؛ قم بتوفيره عبر [`POST /grants/{grant_id}/license-key`](/api-reference/entitlements/fulfill-license-key)، الذي بعده يطلق `entitlement_grant.delivered`. راجع [التفعيل اليدوي](/features/license-keys#manual-fulfillment).

بالنسبة **لكل تكامل آخر** يصل الصف مع `status: "pending"`. يحدث حدث `delivered` أو `failed` بعد اكتمال التسليم:

* تشمل **التكاملات القائمة على OAuth** (Discord, GitHub, Notion) `oauth_url` يجب على العميل زيارته لإكمال الموافقة. يبقى المنح `pending` حتى يقوم العميل بالترخيص.
* **التكاملات المباشرة مع المنصة** (Telegram, Framer, Digital Files) تكون في `pending` لفترة وجيزة فقط أثناء تشغيل المكالمة المنصة، ثم تنتقل إلى `delivered`.

### entitlement\_grant.delivered

انتقل المنح من `pending` إلى `delivered`. العميل لديه الآن الوصول كما هو موصوف في الاستحقاق. استخدم هذا الحدث لفتح ميزات تعتمد عليها في نظمتك الخاصة، على سبيل المثال لتوفير مساحة عمل أو إرسال بريد ترحيبي مخصص أو وضع علامة "متحقق".

يسجل حقل `delivered_at` في الحمولة عندما اكتمل التسليم. بالنسبة للمنح التي وصلت `delivered` عند الإنشاء، ستحصل على `created` و`delivered` أحداث واحدة تلو الأخرى.

### entitlement\_grant.failed

تمت محاولة التسليم وفشلت مع خطأ غير ممكن إعادة المحاولة. يوضح الحقل `error_code` و`error_message` الفشل. تشمل الأسباب الشائعة إلغاء رمز OAuth، أو رفض إذن منصة، أو هدف مفقود (مثل، تم حذف خادم Discord).

<Tip>
  اعتبر `entitlement_grant.failed` قابلا للتنفيذ. دفع العميل ولكن لم يحصل على الوصول. أظهر الفشل لفريق الدعم الخاص بك أو قم بإعادة المنح بمجرد حل المشكلة الأساسية.
</Tip>

### entitlement\_grant.revoked

تم سحب الوصول على مستوى المنصة: تم إزالة دور Discord، تم إزالة المتعاون في GitHub، تم تعطيل مفتاح الترخيص، لم يعد يتم إصدار روابط تحميل الملفات. يسجل حقل `revocation_reason` المُحرك.

| `revocation_reason`      | المُحرك                                                                                                                                                                                                                                                               |
| ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `subscription_cancelled` | تم إلغاء اشتراك العميل (حدث `subscription.cancelled`).                                                                                                                                                                                                                |
| `subscription_on_hold`   | الاشتراك في وضع الإيقاف المؤقت بسبب فشل التجديد (`subscription.on_hold`). يمكن استرداده: تنجح محاولة إعادة التجديد بإعادة منح جديدة.                                                                                                                                  |
| `subscription_expired`   | وصل الاشتراك إلى نهاية فترة صلاحيته (`subscription.expired`).                                                                                                                                                                                                         |
| `plan_changed`           | تغيرت الخطة؛ تم إلغاء المنح القديمة قبل إصدار المنح الجديدة (`subscription.plan_changed`).                                                                                                                                                                            |
| `refund`                 | تمت معالجة استرداد للدفعة الأصلية لمرة واحدة (`refund.succeeded`).                                                                                                                                                                                                    |
| `manual`                 | قام التاجر بإلغاء المنح عبر API أو لوحة التحكم. لا يتم إعادة منح الإلغاءات اليدوية تلقائيًا عند تجديد الاشتراك.                                                                                                                                                       |
| `license_key_disabled`   | تم تعطيل مفتاح الترخيص وراء منح مفتاح الترخيص. يتم إعادة تنشيط المنح تلقائيًا إذا أُعيد تمكين المفتاح.                                                                                                                                                                |
| `platform_external`      | انحرف جانب المنصة للتكامل عن المزامنة (على سبيل المثال، تم إزالة دور Discord يدويًا، فقدت تطبيق GitHub حق الوصول إلى المستودع، أو اكتشفت عملية المراجعة هدفًا مفقودًا). لا يتم إعادة منح الإلغاءات تلقائيًا عند تجديد الاشتراك حتى يتم حل المشكلة الأساسية في المنصة. |

***

## أنواع الحمولة

الحقل `data` يكون دائمًا كائن `EntitlementGrantResponse`. تحمل الحمولة حقل `integration_type` (على سبيل المثال `license_key`, `digital_files`, `discord`) حتى تتمكن من التعرف على نوع المنح مباشرة. نوعان من التكاملات يرفقان كائنات إضافية متداخلة:

* **`license_key`** يتم تضمينه عندما يكون `integration_type` هو `license_key` **وقد تم إصدار مفتاح**. يحتوى على المفتاح المُولد والانتهاء والاستخدام النشط. بالنسبة لمنح مفعّل يدويًا ما زال في `pending`، هذا الكائن هو `null` حتى تقوم بتفعيل المنح.
* **`digital_product_delivery`** يتم تضمينه عندما يكون `integration_type` هو `digital_files`. يحتوى على روابط تحميل موقعة مسبقاً، و `instructions` اختياري، و `external_url` اختياري.

بالنسبة لجميع أنواع التكامل الأخرى (Discord, GitHub, Telegram, Framer, Notion) تكون الحقول المتداخلة `null`؛ يتم التقاط الإعدادات ذات الصلة في الاستحقاق نفسه، وليس في المنح.

***

## عينات الحمولة

### مفتاح الترخيص المسُلم (`entitlement_grant.delivered`)

```json theme={null} theme={null}
{
  "business_id": "bus_H4ekzPSlcg",
  "type": "entitlement_grant.delivered",
  "timestamp": "2026-05-01T10:25:33.000000Z",
  "data": {
    "id": "grant_8VbC6JDZzPEqfBPUdpj0K",
    "business_id": "bus_H4ekzPSlcg",
    "entitlement_id": "ent_9xY2bKwQn5MjRpL8d",
    "customer_id": "cus_abc123",
    "external_id": "lk_AAA111BBB222",
    "payment_id": "pay_a1b2c3d4",
    "subscription_id": null,
    "status": "delivered",
    "integration_type": "license_key",
    "license_key": {
      "key": "PRO-AAAA-BBBB-CCCC-DDDD",
      "expires_at": "2027-05-01T00:00:00Z",
      "activations_used": 0,
      "activations_limit": 5
    },
    "digital_product_delivery": null,
    "delivered_at": "2026-05-01T10:25:33Z",
    "revoked_at": null,
    "revocation_reason": null,
    "error_code": null,
    "error_message": null,
    "oauth_url": null,
    "oauth_expires_at": null,
    "metadata": null,
    "created_at": "2026-05-01T10:25:33Z",
    "updated_at": "2026-05-01T10:25:33Z"
  }
}
```

### مفتاح الترخيص قيد التفعيل اليدوي (`entitlement_grant.created`)

يتم إطلاقه عندما يشتري العميل منتجًا يستحق مفتاح ترخيص يستخدم `fulfillment_mode: manual`. يبقى المنح في `pending` بدون كائن `license_key` بعد — يتوجب على التاجر توفير المفتاح.

```json theme={null} theme={null}
{
  "business_id": "bus_H4ekzPSlcg",
  "type": "entitlement_grant.created",
  "timestamp": "2026-05-01T10:24:00.000000Z",
  "data": {
    "id": "grant_8VbC6JDZzPEqfBPUdpj0K",
    "business_id": "bus_H4ekzPSlcg",
    "entitlement_id": "ent_9xY2bKwQn5MjRpL8d",
    "customer_id": "cus_abc123",
    "external_id": null,
    "payment_id": "pay_a1b2c3d4",
    "subscription_id": null,
    "status": "pending",
    "integration_type": "license_key",
    "license_key": null,
    "digital_product_delivery": null,
    "delivered_at": null,
    "revoked_at": null,
    "revocation_reason": null,
    "error_code": null,
    "error_message": null,
    "oauth_url": null,
    "oauth_expires_at": null,
    "metadata": null,
    "created_at": "2026-05-01T10:24:00Z",
    "updated_at": "2026-05-01T10:24:00Z"
  }
}
```

### الملفات الرقمية المسلمة (`entitlement_grant.delivered`)

```json theme={null} theme={null}
{
  "business_id": "bus_H4ekzPSlcg",
  "type": "entitlement_grant.delivered",
  "timestamp": "2026-05-01T10:30:12.000000Z",
  "data": {
    "id": "grant_2P9rQwYvMxTnKoCb4",
    "business_id": "bus_H4ekzPSlcg",
    "entitlement_id": "ent_files_J3kLmN4oP5",
    "customer_id": "cus_abc123",
    "external_id": "pay_a1b2c3d4",
    "payment_id": "pay_a1b2c3d4",
    "subscription_id": null,
    "status": "delivered",
    "integration_type": "digital_files",
    "license_key": null,
    "digital_product_delivery": {
      "files": [
        {
          "file_id": "df_a4f6c1de",
          "download_url": "https://files.dodopayments.com/.../pro-bundle.zip?Signature=...",
          "filename": "pro-bundle.zip",
          "content_type": "application/zip",
          "file_size": 18742390,
          "expires_in": 900
        }
      ],
      "instructions": "Unzip and run setup.sh from the project root.",
      "external_url": null
    },
    "delivered_at": "2026-05-01T10:30:12Z",
    "revoked_at": null,
    "revocation_reason": null,
    "error_code": null,
    "error_message": null,
    "oauth_url": null,
    "oauth_expires_at": null,
    "metadata": null,
    "created_at": "2026-05-01T10:30:12Z",
    "updated_at": "2026-05-01T10:30:12Z"
  }
}
```

### تم إنشاء دور Discord وعالق (`entitlement_grant.created`)

```json theme={null} theme={null}
{
  "business_id": "bus_H4ekzPSlcg",
  "type": "entitlement_grant.created",
  "timestamp": "2026-05-01T10:31:00.000000Z",
  "data": {
    "id": "grant_DiscordPending5L",
    "business_id": "bus_H4ekzPSlcg",
    "entitlement_id": "ent_discord_patrons",
    "customer_id": "cus_abc123",
    "external_id": "sub_pro_monthly_001",
    "payment_id": null,
    "subscription_id": "sub_pro_monthly_001",
    "status": "pending",
    "integration_type": "discord",
    "license_key": null,
    "digital_product_delivery": null,
    "delivered_at": null,
    "revoked_at": null,
    "revocation_reason": null,
    "error_code": null,
    "error_message": null,
    "oauth_url": "https://discord.com/oauth2/authorize?...",
    "oauth_expires_at": "2026-05-08T10:31:00Z",
    "metadata": null,
    "created_at": "2026-05-01T10:31:00Z",
    "updated_at": "2026-05-01T10:31:00Z"
  }
}
```

### منح مُلغى بسبب إلغاء اشتراك (`entitlement_grant.revoked`)

```json theme={null} theme={null}
{
  "business_id": "bus_H4ekzPSlcg",
  "type": "entitlement_grant.revoked",
  "timestamp": "2026-06-15T08:12:44.000000Z",
  "data": {
    "id": "grant_8VbC6JDZzPEqfBPUdpj0K",
    "business_id": "bus_H4ekzPSlcg",
    "entitlement_id": "ent_9xY2bKwQn5MjRpL8d",
    "customer_id": "cus_abc123",
    "external_id": "sub_pro_monthly_001",
    "payment_id": null,
    "subscription_id": "sub_pro_monthly_001",
    "status": "revoked",
    "integration_type": "license_key",
    "revocation_reason": "subscription_cancelled",
    "license_key": {
      "key": "PRO-AAAA-BBBB-CCCC-DDDD",
      "expires_at": null,
      "activations_used": 1,
      "activations_limit": 5
    },
    "digital_product_delivery": null,
    "delivered_at": "2026-05-01T10:25:33Z",
    "revoked_at": "2026-06-15T08:12:44Z",
    "error_code": null,
    "error_message": null,
    "oauth_url": null,
    "oauth_expires_at": null,
    "metadata": null,
    "created_at": "2026-05-01T10:25:33Z",
    "updated_at": "2026-06-15T08:12:44Z"
  }
}
```

### فشلت عملية التسليم (`entitlement_grant.failed`)

```json theme={null} theme={null}
{
  "business_id": "bus_H4ekzPSlcg",
  "type": "entitlement_grant.failed",
  "timestamp": "2026-05-01T10:36:21.000000Z",
  "data": {
    "id": "grant_GhFailed7Z",
    "business_id": "bus_H4ekzPSlcg",
    "entitlement_id": "ent_github_repo",
    "customer_id": "cus_abc123",
    "external_id": "pay_a1b2c3d4",
    "payment_id": "pay_a1b2c3d4",
    "subscription_id": null,
    "status": "failed",
    "integration_type": "github",
    "license_key": null,
    "digital_product_delivery": null,
    "delivered_at": null,
    "revoked_at": null,
    "revocation_reason": null,
    "error_code": "github_permission_denied",
    "error_message": "Repository access could not be granted: the GitHub App installation no longer has permission on this repository.",
    "oauth_url": null,
    "oauth_expires_at": null,
    "metadata": null,
    "created_at": "2026-05-01T10:36:00Z",
    "updated_at": "2026-05-01T10:36:21Z"
  }
}
```

***

## نصائح للتكامل

* **انتظر `entitlement_grant.delivered` قبل فتح الميزات التابعة.** يخبرك حدث `payment.succeeded` بأن المال تم مسحه؛ لا يخبرك أن العميل حصل على المستودع في GitHub أو دور Discord بعد. يعتبر حدث `delivered` مصدر الحقيقة للتفعيل.
* **قم بتعيين `revocation_reason` على تدفقات الاحتفاظ.** يشير إلغاء `subscription_on_hold` عادةً إلى فشل بطاقة العميل وأن التجديد التالي سيتعين عليه إعادة منح الوصول. يعتبر إلغاء `manual` أو `subscription_cancelled` مقصودًا. تعامل معها بشكل مختلف في رسائل العملاء.
* **استخدم منح `id` كمفتاح عدم التكرار.** ينبعث عن المنح الواحد حدث `created` واحد وحدث نهائي واحد على الأكثر (`delivered` أو `failed`)، وحوالي حدث واحد `revoked`. يمكن أن تكرر إعادة التسليم من نظام الويب هوك الأحداث؛ يتم الاستبعاد من خلال منح `id` بالإضافة إلى `type`.
* **اقرأ `integration_type` للتعرف على نوع المنح.** تحمل الحمولة `integration_type` مباشرة (مثل `license_key`، `digital_files`، `discord`). يتم تعبئة الكائنات المتداخلة `license_key` و`digital_product_delivery` بمجرد تسليم منحها الخاصة؛ يبقى منح مفتاح الترخيص المفعّل يدويًا `pending` بداخله `integration_type: "license_key"` وكائن `null` `license_key` حتى تقوم بتفعيله.
* **بالنسبة للمنح المستندة إلى OAuth، أظهر `oauth_url` للعميل.** الحدث `entitlement_grant.created` لتدفقات مشترك Discord، GitHub، أو Notion يتضمن `oauth_url` و`oauth_expires_at`. أرسلها عبر البريد الإلكتروني للعميل أو اعرضها في تطبيقك لإزالة عوائق التسليم.
