الانتقال إلى المحتوى الرئيسي

أحداث منح الاستحقاق عبر 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، الذي بعده يطلق entitlement_grant.delivered. راجع التفعيل اليدوي. بالنسبة لكل تكامل آخر يصل الصف مع 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).
اعتبر entitlement_grant.failed قابلا للتنفيذ. دفع العميل ولكن لم يحصل على الوصول. أظهر الفشل لفريق الدعم الخاص بك أو قم بإعادة المنح بمجرد حل المشكلة الأساسية.

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)

{
  "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 بعد — يتوجب على التاجر توفير المفتاح.
{
  "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)

{
  "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)

{
  "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)

{
  "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)

{
  "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. أرسلها عبر البريد الإلكتروني للعميل أو اعرضها في تطبيقك لإزالة عوائق التسليم.

Detailed view of a single entitlement grant: who it's for, its lifecycle state, and any integration-specific delivery payload.

brand_id
string
مطلوب

Brand id this grant belongs to.

business_id
string
مطلوب

Identifier of the business that owns the grant.

created_at
string<date-time>
مطلوب

Timestamp when the grant was created.

customer_id
string
مطلوب

Identifier of the customer the grant was issued to.

entitlement_id
string
مطلوب

Identifier of the entitlement this grant was issued from.

id
string
مطلوب

Unique identifier of the grant.

integration_type
enum<string>
مطلوب

The integration type of the grant's entitlement (e.g. license_key).

الخيارات المتاحة:
discord,
telegram,
github,
figma,
framer,
notion,
digital_files,
license_key
metadata
object
مطلوب

Arbitrary key-value metadata recorded on the grant.

status
enum<string>
مطلوب

Lifecycle status of the grant.

الخيارات المتاحة:
Pending,
Delivered,
Failed,
Revoked
updated_at
string<date-time>
مطلوب

Timestamp when the grant was last modified.

delivered_at
string<date-time> | null

Timestamp when the grant transitioned to delivered, when applicable.

digital_product_delivery
Digital Product Delivery · object

Digital-product-delivery payload, present when the entitlement integration is digital_files.

error_code
string | null

Machine-readable code reported when delivery failed, when applicable.

error_message
string | null

Human-readable message reported when delivery failed, when applicable.

license_key
object

License-key delivery payload, present when the entitlement integration is license_key.

oauth_expires_at
string<date-time> | null

Timestamp when oauth_url stops being valid, when applicable.

oauth_url
string | null

Customer-facing OAuth URL for OAuth-style integrations. Populated during the customer-portal accept flow; null until the customer completes that step, and on grants for non-OAuth integrations.

payment_id
string | null

Identifier of the payment that triggered this grant, when applicable.

revocation_reason
string | null

Reason recorded when the grant was revoked, when applicable.

revoked_at
string<date-time> | null

Timestamp when the grant transitioned to revoked, when applicable.

subscription_id
string | null

Identifier of the subscription that triggered this grant, when applicable.

آخر تعديل في ٩ يونيو ٢٠٢٦