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

ما يتم تسليمه

لا يغادر أي شيء Dodo Payments — المنحة هي ما يتم تسليمه:
  • عند الشراء، تُنشأ المنحة وتنتقل مباشرة إلى delivered. لا يوجد مرحلة pending، ولا إجراء من العميل، ولا طريقة للفشل في التسليم.
  • تحمل المنحة حمولة بطابع feature: { "feature_type": "boolean", "feature_id": "advanced_reports" }. يقرأ تطبيقك feature_id لتحديد ما يجب فتحه.
  • الإلغاء أو الاسترداد أو الإلغاء اليدوي ينقل المنحة إلى revoked، ويختفي العلم من تطبيقك.
تشمل الاستخدامات الشائعة البوابة المستندة إلى الخطط (Pro يفتح التحليلات)، القدرات الإضافية (ترقية “API access”)، وبرامج الوصول المبكر المباعة كمشتريات مرة واحدة.
feature_id هو معرف يختاره التاجر، وليس فريداً عبر الأذونات. يمكن أن يمنح اثنان من الأذونات نفس feature_id — على سبيل المثال، خطة Pro الشهرية وخطة Pro السنوية كلاهما يمنح advanced_reports.

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

1

Open Entitlements

في لوحة التحكم Dodo Payments، اذهب إلى الأذونات وانقر على + لبدء إذن جديد، ثم اختر الرايات المميزة.
2

Name the flag

أعط الراية اسم عرض للوحة التحكم الخاصة بك، ومعرف ميزة ستتحقق منه تطبيقك (تقترح لوحة التحكم واحدًا من الاسم)، ووصف حتى يعرف فريقك ماذا يتحكم.
نموذج راية مميزة جديدة مع اسم العرض ومعرف الميزة والوصف ومدخلات مفاتيح-قيم للبيانات الوصفية
3

Optionally add metadata

تبديل البيانات الوصفية لإرفاق تكوين المفاتيح والقيم — الحدود، أسماء المستويات، الحصص — التي يتم تسليمها إلى تطبيقك جنبًا إلى جنب مع الراية. انظر إرفاق الحدود بالبيانات الوصفية.
4

Confirm

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

إرفاق بمنتج

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

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

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

الإنشاء عبر API

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,
  },
});
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,
    },
)
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"),
    },
  ),
})

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

تجيب الراية البوليانية “هل لدى هذا العميل الميزة؟”. تجيب البيانات الوصفية “مع أي تكوين؟”. تقبل البيانات الوصفية للأذونات القيم النصية والعددية والرقمية والبولينيانية، وكل منحة تأخذ لقطة مجمدة من بيانات الإذن عند إنشائها. ذاك السلوك اللقطة هو ما يجعل البيانات الوصفية آمنة للاستخدام بالنسبة لحدود الخطط:
  • تحرير البيانات الوصفية للإذن لاحقًا يؤثر فقط على المنح المستقبلية. يحتفظ العملاء بالحدود التي اشتروا تحتها.
  • يتم إرجاع اللقطة على كل منحة كحقلها metadata، لذا يتيح لك اتصال API واحد الحصول على الراية وتكوينها.
على سبيل المثال، يتيح advanced_reports بتكوين { "tier": "pro", "monthly_report_limit": 100 } لتطبيقك فتح لوحة العدادات وتنفيذ حصة 100 تقرير بدون بحث ثانٍ. إذا قمت لاحقًا بزيادة الحد إلى 250، فإن العملاء الحاليين يبقون عند 100 حتى يحصلوا على منحة جديدة (على سبيل المثال، بعد تغيير الخطة).
استخدم البيانات الوصفية للحدود والتكوين؛ استخدم feature_id فقط للهوية. ترميز الحدود في المعرف (advanced_reports_100) يجبر على راية جديدة لكل تغيير في الحدود ويعطل تحقق تطبيقك.

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

سرد منح الرايات المميزة المسلمة للعميل وبناء مجموعة الميزات الممكنة. يعيد نقطة النهاية صفًا واحدًا لكل منحة عبر جميع الأذونات، يمكن تصفيتها بواسطة integration_type وstatus.
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
}
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")
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
  }
}
يتم تعبئة حمولة feature فقط على منح feature_flag؛ إنها null لكل نوع تكامل آخر. انظر إلى مرجع API قائمة منح العملاء للحصول على شكل الاستجابة الكامل.
التحقق من API في كل طلب يضيف تأخيرًا إلى مسار التطبيقات الحر. قم بتخزين مجموعة الميزات لكل عميل مع فترة صلاحية قصيرة الأمد (دقائق، وليست ساعات)، وقم بإبطال التخزين المؤقت من معالج الويب هوك الخاص بك عند تغيير حالة منحة - ذلك المزيج يحافظ على سرعة التحقق ويجعل الإلغاءات شبه فورية.

دورة الحياة

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

خدمات الويب

اشترك في entitlement_grant.* الأحداث لتعكس الرايات في قاعدة البيانات الخاصة بك بدلاً من الاستطلاع:
  • entitlement_grant.created — تصل بالفعل delivered مع حمولة feature. قم بتمكين الميزة.
  • entitlement_grant.delivered — يتم تشغيلها عندما يتم استعادة منحة ملغاة مسبقًا. قم بإعادة تمكين الميزة.
  • entitlement_grant.revoked — الوصول محظور. قم بتعطيل الميزة وتحقق من revocation_reason لتحديد رسائلك.
TypeScript
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.
آخر تعديل في ٩ يوليو ٢٠٢٦