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

# إذن الراية المميزة

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

<Info>
  يحول إذن الراية المميزة Dodo Payments إلى متجر راية مميزة يعى بالفواتير. أرفق راية مثل `advanced_reports` بمنتج، وكل عميل مدفوع يحصل على منحة يمكن لتطبيقك التحقق منها عبر API أو الاحتفاظ بالتزامن مع webhooks. لا منصة خارجية، لا OAuth، لا خطوة تسليم - المنحة نفسها هي القدرة.
</Info>

## ما يتم تسليمه

لا يغادر أي شيء Dodo Payments — المنحة **هي** ما يتم تسليمه:

* عند الشراء، تُنشأ المنحة وتنتقل مباشرة إلى `delivered`. لا يوجد مرحلة `pending`، ولا إجراء من العميل، ولا طريقة للفشل في التسليم.
* تحمل المنحة حمولة بطابع `feature`: `{ "feature_type": "boolean", "feature_id": "advanced_reports" }`. يقرأ تطبيقك `feature_id` لتحديد ما يجب فتحه.
* الإلغاء أو الاسترداد أو الإلغاء اليدوي ينقل المنحة إلى `revoked`، ويختفي العلم من تطبيقك.

تشمل الاستخدامات الشائعة البوابة المستندة إلى الخطط (Pro يفتح التحليلات)، القدرات الإضافية (ترقية "API access")، وبرامج الوصول المبكر المباعة كمشتريات مرة واحدة.

<Note>
  `feature_id` هو معرف يختاره التاجر، وليس فريداً عبر الأذونات. يمكن أن يمنح اثنان من الأذونات نفس `feature_id` — على سبيل المثال، خطة Pro الشهرية وخطة Pro السنوية كلاهما يمنح `advanced_reports`.
</Note>

## إنشاء راية مميزة

<Steps>
  <Step title="Open Entitlements">
    في لوحة التحكم Dodo Payments، اذهب إلى **الأذونات** وانقر على **+** لبدء إذن جديد، ثم اختر **الرايات المميزة**.
  </Step>

  <Step title="Name the flag">
    أعط الراية **اسم عرض** للوحة التحكم الخاصة بك، و**معرف ميزة** ستتحقق منه تطبيقك (تقترح لوحة التحكم واحدًا من الاسم)، و**وصف** حتى يعرف فريقك ماذا يتحكم.

    <Frame caption="Creating a feature flag. The Feature ID is what your application checks; Meta Data attaches limits alongside the flag.">
      <img src="https://mintcdn.com/dodopayments/oS2MTbJuY6MeBjjs/images/entitlements/feature-flags/create.png?fit=max&auto=format&n=oS2MTbJuY6MeBjjs&q=85&s=08d8fc2cfee102ff08fd150c76b5fcf9" alt="نموذج راية مميزة جديدة مع اسم العرض ومعرف الميزة والوصف ومدخلات مفاتيح-قيم للبيانات الوصفية" style={{ maxHeight: '500px', width: 'auto' }} width="1196" height="776" data-path="images/entitlements/feature-flags/create.png" />
    </Frame>
  </Step>

  <Step title="Optionally add metadata">
    تبديل **البيانات الوصفية** لإرفاق تكوين المفاتيح والقيم — الحدود، أسماء المستويات، الحصص — التي يتم تسليمها إلى تطبيقك جنبًا إلى جنب مع الراية. انظر [إرفاق الحدود بالبيانات الوصفية](#attach-limits-with-metadata).
  </Step>

  <Step title="Confirm">
    انقر **تأكيد**. تظهر الراية في قائمة الأذونات الخاصة بك، جاهزة للإرفاق بالمنتجات.

    <Frame caption="The created feature flag. The right pane tracks every customer grant issued from it.">
      <img src="https://mintcdn.com/dodopayments/oS2MTbJuY6MeBjjs/images/entitlements/feature-flags/list.png?fit=max&auto=format&n=oS2MTbJuY6MeBjjs&q=85&s=02eedcbbf7ece9f67d375c984c5515b9" alt="لوحة التحكم في الأذونات تظهر راية الميزة المتقدمة مع لوحة نشاط المنح الخاصة بها" style={{ maxHeight: '500px', width: 'auto' }} width="1316" height="898" data-path="images/entitlements/feature-flags/list.png" />
    </Frame>
  </Step>
</Steps>

## إرفاق بمنتج

افتح منتجًا (أو قم بإنشائه)، وابحث عن بطاقة **الأذونات**، وانقر على **+** لإرفاق الأذونات الموجودة. حدد راية الميزة الخاصة بك وانقر على **تم**.

<Frame caption="Attaching the feature flag to a product. One product can deliver multiple entitlements.">
  <img src="https://mintcdn.com/dodopayments/oS2MTbJuY6MeBjjs/images/entitlements/feature-flags/attach-picker.png?fit=max&auto=format&n=oS2MTbJuY6MeBjjs&q=85&s=da2137873e285cc6ce0ce234fe899ed3" alt="لوحة إرفاق الأذونات مع راية الميزة المتقدمة المحددة" style={{ maxHeight: '500px', width: 'auto' }} width="1316" height="898" data-path="images/entitlements/feature-flags/attach-picker.png" />
</Frame>

تظهر الراية المرفقة في نموذج المنتج، وقائمة المعاينة تتضمنها تحت **التضمينات**.

<Frame caption="The product now includes the feature flag. Every successful purchase or active subscription grants it.">
  <img src="https://mintcdn.com/dodopayments/oS2MTbJuY6MeBjjs/images/entitlements/feature-flags/attach-to-product.png?fit=max&auto=format&n=oS2MTbJuY6MeBjjs&q=85&s=3556181389997edddde9c396d0ce408d" alt="نموذج المنتج مع راية الميزة المتقدمة مرفقة في بطاقة الأذونات" style={{ maxHeight: '500px', width: 'auto' }} width="1316" height="898" data-path="images/entitlements/feature-flags/attach-to-product.png" />
</Frame>

## التكوين المطلوب

| الحقل          | مطلوب | الوصف                                                                   |
| -------------- | ----- | ----------------------------------------------------------------------- |
| `feature_id`   | نعم   | معرف تتحقق منه تطبيقك، مثل `advanced_reports`. ليس فريداً عبر الأذونات. |
| `feature_type` | نعم   | نوع القدرة الممنوحة. يدعم اليوم فقط `boolean`.                          |

### الإنشاء عبر API

<CodeGroup>
  ```typescript TypeScript theme={null} theme={null}
  import DodoPayments from 'dodopayments';

  const client = new DodoPayments({
    bearerToken: process.env['DODO_PAYMENTS_API_KEY'],
    environment: 'test_mode',
  });

  const entitlement = await client.entitlements.create({
    name: 'Advanced Reports',
    integration_type: 'feature_flag',
    integration_config: {
      feature_type: 'boolean',
      feature_id: 'advanced_reports',
    },
    metadata: {
      tier: 'pro',
      monthly_report_limit: 100,
    },
  });
  ```

  ```python Python theme={null} theme={null}
  client.entitlements.create(
      name="Advanced Reports",
      integration_type="feature_flag",
      integration_config={
          "feature_type": "boolean",
          "feature_id": "advanced_reports",
      },
      metadata={
          "tier": "pro",
          "monthly_report_limit": 100,
      },
  )
  ```

  ```go Go theme={null} theme={null}
  client.Entitlements.New(ctx, dodopayments.EntitlementNewParams{
    Name:            dodopayments.F("Advanced Reports"),
    IntegrationType: dodopayments.F(dodopayments.EntitlementIntegrationTypeFeatureFlag),
    IntegrationConfig: dodopayments.F[dodopayments.IntegrationConfigUnionParam](
      dodopayments.IntegrationConfigFeatureFlagConfigParam{
        FeatureType: dodopayments.F(dodopayments.FeatureTypeBoolean),
        FeatureID:   dodopayments.F("advanced_reports"),
      },
    ),
  })
  ```
</CodeGroup>

***

## إرفاق الحدود بالبيانات الوصفية

تجيب الراية البوليانية "هل لدى هذا العميل الميزة؟". تجيب البيانات الوصفية "مع أي تكوين؟". تقبل البيانات الوصفية للأذونات القيم النصية والعددية والرقمية والبولينيانية، وكل منحة تأخذ **لقطة مجمدة** من بيانات الإذن عند إنشائها.

ذاك السلوك اللقطة هو ما يجعل البيانات الوصفية آمنة للاستخدام بالنسبة لحدود الخطط:

* تحرير البيانات الوصفية للإذن لاحقًا يؤثر فقط على **المنح المستقبلية**. يحتفظ العملاء بالحدود التي اشتروا تحتها.
* يتم إرجاع اللقطة على كل منحة كحقلها `metadata`، لذا يتيح لك اتصال API واحد الحصول على الراية وتكوينها.

على سبيل المثال، يتيح `advanced_reports` بتكوين `{ "tier": "pro", "monthly_report_limit": 100 }` لتطبيقك فتح لوحة العدادات *وتنفيذ* حصة 100 تقرير بدون بحث ثانٍ. إذا قمت لاحقًا بزيادة الحد إلى 250، فإن العملاء الحاليين يبقون عند 100 حتى يحصلوا على منحة جديدة (على سبيل المثال، بعد تغيير الخطة).

<Tip>
  استخدم البيانات الوصفية للحدود والتكوين؛ استخدم `feature_id` فقط للهوية. ترميز الحدود في المعرف (`advanced_reports_100`) يجبر على راية جديدة لكل تغيير في الحدود ويعطل تحقق تطبيقك.
</Tip>

***

## تحقق من ميزات العميل

سرد منح الرايات المميزة المسلمة للعميل وبناء مجموعة الميزات الممكنة. يعيد نقطة النهاية صفًا واحدًا لكل منحة عبر جميع الأذونات، يمكن تصفيتها بواسطة `integration_type` و`status`.

<CodeGroup>
  ```typescript TypeScript theme={null} theme={null}
  const features = new Map<string, Record<string, unknown>>();

  for await (const grant of client.customers.listEntitlementGrants('cus_abc123', {
    integration_type: 'feature_flag',
    status: 'Delivered',
  })) {
    if (grant.feature) {
      features.set(grant.feature.feature_id, grant.metadata ?? {});
    }
  }

  if (features.has('advanced_reports')) {
    const limit = features.get('advanced_reports')?.monthly_report_limit;
    // unlock the dashboard, enforce the limit
  }
  ```

  ```python Python theme={null} theme={null}
  page = client.customers.list_entitlement_grants(
      customer_id="cus_abc123",
      integration_type="feature_flag",
      status="Delivered",
  )

  features = {
      grant.feature.feature_id: grant.metadata
      for grant in page.items
      if grant.feature
  }

  if "advanced_reports" in features:
      limit = features["advanced_reports"].get("monthly_report_limit")
  ```

  ```go Go theme={null} theme={null}
  page, _ := client.Customers.ListEntitlementGrants(
    ctx, "cus_abc123",
    dodopayments.CustomerListEntitlementGrantsParams{
      IntegrationType: dodopayments.F("feature_flag"),
      Status:          dodopayments.F("Delivered"),
    },
  )

  features := map[string]bool{}
  for _, grant := range page.Items {
    if grant.Feature.FeatureID != "" {
      features[grant.Feature.FeatureID] = true
    }
  }
  ```
</CodeGroup>

<Note>
  يتم تعبئة حمولة `feature` فقط على منح `feature_flag`؛ إنها `null` لكل نوع تكامل آخر. انظر إلى [مرجع API قائمة منح العملاء](/api-reference/entitlements/list-customer-grants) للحصول على شكل الاستجابة الكامل.
</Note>

التحقق من API في كل طلب يضيف تأخيرًا إلى مسار التطبيقات الحر. قم بتخزين مجموعة الميزات لكل عميل مع فترة صلاحية قصيرة الأمد (دقائق، وليست ساعات)، وقم بإبطال التخزين المؤقت من معالج الويب هوك الخاص بك عند تغيير حالة منحة - ذلك المزيج يحافظ على سرعة التحقق ويجعل الإلغاءات شبه فورية.

***

## دورة الحياة

تتبع منح الراية المميزة دورة [الحياة القياسية للمنح](/features/entitlements/introduction#how-grants-work) مع تبسيط واحد: لا توجد خطوة تسليم، لذا لا تجلس المنح في `pending` ولا تنتقل إلى `failed`.

| الزناد                                                  | التأثير                                                                               |
| ------------------------------------------------------- | ------------------------------------------------------------------------------------- |
| نجح الدفع لمرة واحدة / أصبحت الاشتراك نشطًا             | تم إنشاء المنحة مع `status: delivered` و`delivered_at` مضبوطة.                        |
| وضعت الاشتراك على الانتظار، أو ألغيت، أو انتهت صلاحيتها | تم إلغاء المنحة مع `revocation_reason` المطابقة.                                      |
| رد الأموال عن دفع لمرة واحدة                            | تم إلغاء المنحة مع `revocation_reason: refund`.                                       |
| تعافت الاشتراك (على سبيل المثال، نجحت عملية dunning)    | تم استعادة المنحة الملغاة إلى `delivered` - نفس `id` للمنحة، مساحات الإلغاء مفرغة.    |
| إلغاء API يدوي                                          | تم إلغاء المنحة مع `revocation_reason: manual`. لا يتم استعادته تلقائيًا عند التجديد. |

المنح غير قابلة للتكرار لكل إذن وعميل: بينما لدى العميل منحة غير ملغاة لراية، لا تؤدي المشتريات المتكررة والتجديدات إلى إنشاء نسخ مكررة.

***

## خدمات الويب

اشترك في [ `entitlement_grant.*` الأحداث ](/developer-resources/webhooks/intents/entitlement-grant) لتعكس الرايات في قاعدة البيانات الخاصة بك بدلاً من الاستطلاع:

* `entitlement_grant.created` — تصل بالفعل `delivered` مع حمولة `feature`. قم بتمكين الميزة.
* `entitlement_grant.delivered` — يتم تشغيلها عندما يتم استعادة منحة ملغاة مسبقًا. قم بإعادة تمكين الميزة.
* `entitlement_grant.revoked` — الوصول محظور. قم بتعطيل الميزة وتحقق من `revocation_reason` لتحديد رسائلك.

```typescript TypeScript theme={null} theme={null}
app.post('/webhooks/dodo', async (req, res) => {
  const event = req.body;

  if (event.type.startsWith('entitlement_grant.') && event.data.feature) {
    const { customer_id, feature } = event.data;
    const enabled = event.type !== 'entitlement_grant.revoked';

    await db.customerFeatures.upsert({
      customerId: customer_id,
      featureId: feature.feature_id,
      enabled,
      config: event.data.metadata ?? {},
    });
  }

  res.sendStatus(200);
});
```

لا توجد `entitlement_grant.failed` للرايات المميزة — يحدث التسليم بالكامل داخل Dodo Payments ولا يمكن أن يفشل.

***

## مثال: خطة Pro تفتح التقارير المتقدمة

1. **أنشئ الراية.** `feature_id: advanced_reports` مع البيانات الوصفية `{ "tier": "pro", "monthly_report_limit": 100 }`.
2. **قم بإرفاقها** بمنتج الاشتراك في خطة Pro الخاصة بك.
3. **اشتراك العميل.** ينشئ Dodo Payments منحة `delivered` ويطلق `entitlement_grant.created`؛ يقوم معالج الويب هوك الخاص بك بتمكين `advanced_reports` للعميل بحد 100.
4. **تطبيقك يبوّب الميزة.** عند تحميل لوحة العدادات، تحقق من مجموعة الميزات المخبأة (أو اتصل بـ `listEntitlementGrants`) وعرض علامة التبويب للتقارير فقط عند توفر `advanced_reports`.
5. **قام العميل بالإلغاء.** يقوم Dodo Payments بإلغاء المنحة ويطلق `entitlement_grant.revoked`؛ يقوم معالجك بتعطيل الميزة. إذا تعافى العميل لاحقًا عبر عملية dunning، `entitlement_grant.delivered` تستعيدها - لا حاجة لتغيير التعليمات البرمجية.

***

## أفضل الممارسات

* **استخدم معرفات السمات الثابتة، الsnake\_case.** تتحقق تطبيقك من هذه السلاسل؛ تغيير الاسم يعد تغييرًا كسرًا على كلا الجانبين.

* **علم واحد لكل قدرة.** فضل `advanced_reports` + `api_access` كأذونات اثنين على راية واحدة `pro_bundle` — تظل المخالفة وخليط الخطط نظيفة.

* **ادفع الحالة من خلال خدمات الويب، وتحقق من خلال API.** تجعل الخدمات المعطاة قاعدة بياناتك محدثة؛ قائمة النقاط تكون مصدر الحقيقة لأعمال التوفيق والأخطاء في التخزين المؤقت.

* **تعامل مع `revoked` على أنها فورية.** يعني العلم الذي تم إلغاؤه أن العميل لم يعد يدفع مقابل الميزة. اعتمد على الطلب التالي، وليس الجلسة التالية.

* **ضع الحدود في البيانات الوصفية، وليس في الكود.** يؤدي تغيير الحصة بعد ذلك فقط إلى تحرير الإذن - يلتقط العملاء الجدد تلقائيًا بينما تحتفظ المنح الحالية بلقطة الشراء الخاصة بهم.

* **Use stable, snake\_case feature ids.** Your application code checks these strings; renaming one is a breaking change on both sides.

* **One flag per capability.** Prefer `advanced_reports` + `api_access` as two entitlements over a single `pro_bundle` — revocation and plan mixes stay clean.

* **Drive state from webhooks, verify with the API.** Webhooks keep your database current; the list endpoint is the source of truth for reconciliation jobs and cache misses.

* **Treat `revoked` as immediate.** A revoked flag means the customer is no longer paying for the feature. Gate on the next request, not the next session.

* **Put limits in metadata, not in code.** Changing a quota then only requires editing the entitlement — new customers pick it up automatically while existing grants keep their purchased snapshot.
