跳转到主要内容
一个功能标志权限将 Dodo Payments 转变为一个与账单相关的功能标志存储。将类似于 advanced_reports 的标志附加到产品上,每个支付客户都能通过 API 检查或使用 webhooks 保持同步来获得授权。无需外部平台,无需 OAuth,无需交付步骤 — 授权本身就是能力。

交付内容

没有任何东西离开 Dodo Payments — 授权就是交付物:
  • 购买时,创建授权,并直接移动到 delivered。没有 pending 阶段,无需客户操作,也没有交付失败的方式。
  • 授权携带一个类型 feature 负载: { "feature_type": "boolean", "feature_id": "advanced_reports" }。您的应用程序读取 feature_id 以决定解锁什么。
  • 取消、退款或手动撤销后,授权移动到 revoked,您的应用程序将看到标志消失。
常见用途包括基于计划的功能控制(Pro 解锁分析)、附加能力(“API 访问” 升级)和作为一次性购买出售的早期访问计划。
feature_id 是商家选择的标识符,不在所有权限中唯一。两个权限可以提供相同的 feature_id —— 例如,月度和年度 Pro 计划都授予 advanced_reports

创建功能标志

1

Open Entitlements

在您的 Dodo Payments 控制面板中,转到 权限 并点击 + 开始一个新权限,然后选择 功能标志
2

Name the flag

为您的控制面板提供一个标志的 显示名称,一个您的应用程序将检查的 功能 ID(控制面板从名称中建议一个),以及一个 描述 以便您的团队知道它控制什么。
新功能标志表单,具有显示名称、功能ID、描述和元数据键-值条目
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 调用可以同时提供标志及其配置。
例如,一个具有 { "tier": "pro", "monthly_report_limit": 100 }advanced_reports 标志让您的应用程序解锁仪表板执行 100 份报告配额,而无需第二次查找。如果您后来将限制提高到 250,现有客户仍为 100,直到他们收到新的授权(例如,计划更改后)。
使用元数据进行限制和配置;仅对身份使用 feature_id。在 id 中编码限制(advanced_reports_100)会在每次限制更改时强制创建新标志,并破坏应用程序的检查。

检查客户的功能

列出客户交付的功能标志授权,并构建已启用功能集。终端返回每个授权跨所有权限的一行,支持按 integration_typestatus 筛选。
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 会增加热路径的延迟。使用短 TTL(分钟而非小时)为每个客户缓存功能集,并在授权变更状态时从您的 webhook 处理程序中使缓存无效 —— 这种结合保持检查快速,并使撤销接近于即时。

生命周期

功能标志授权遵循标准的授权生命周期,但有一项简化:没有交付步骤,因此授权从未停留在 pending 或移动到 failed
触发器效果
一次性支付成功 / 订阅变为活动状态使用已设置的 status: delivereddelivered_at 创建授权。
订阅被搁置、取消或过期使用匹配的 revocation_reason 撤销授权。
一次性支付退款使用 revocation_reason: refund 撤销授权。
订阅恢复(例如,扣款成功)撤销的授权恢复到 delivered — 相同的授权 id,撤销字段清除。
手动 API 撤销使用 revocation_reason: manual 撤销授权。续订时不会自动恢复。
授权对于每个权限和客户是幂等的:当客户对一个标志拥有未撤销的授权时,重复购买和续订不会创建重复项。

Webhooks

订阅 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;您的 webhook 处理程序为客户启用 advanced_reports,限制为 100。
  4. 您的应用程序控制功能。 在加载仪表板时,检查缓存的功能集(或调用 listEntitlementGrants),并仅在存在 advanced_reports 时渲染报告选项卡。
  5. 客户取消。 Dodo Payments 撤销授权并触发 entitlement_grant.revoked;您的处理程序禁用功能。如果客户稍后通过扣款恢复,entitlement_grant.delivered 会恢复它 — 无需代码更改。

最佳实践

  • 使用稳定的 snake_case 功能 ID。 您的应用程序代码检查这些字符串;重命名其中一个是双方的重大更改。
  • 每个能力一个标志。 优先选择 advanced_reports + api_access 作为两个权限,而不是单一的 pro_bundle —— 撤销和计划混合保持整洁。
  • 从 webhook 驱动状态,通过 API 验证。 Webhook 保持您的数据库当前;列表终端是对账工作和缓存丢失的真相来源。
  • 立即将 revoked 视为有效。 撤销标志意味着客户不再为该功能付费。控制下一个请求,而不是下一次会话。
  • 将限制放在元数据中,而不是代码中。 更改配额然后只需编辑权限 — 新客户会自动获取,而现有授权保留他们购买的快照。
最后修改于 2026年7月9日