一个功能标志权限将 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。
创建功能标志
Open Entitlements
在您的 Dodo Payments 控制面板中,转到 权限 并点击 + 开始一个新权限,然后选择 功能标志。
Name the flag
为您的控制面板提供一个标志的 显示名称,一个您的应用程序将检查的 功能 ID(控制面板从名称中建议一个),以及一个 描述 以便您的团队知道它控制什么。 Optionally add metadata
切换 元数据 以附加键-值配置 — 限制、层级名称、配额 — 这些将与标志一起交付到您的应用程序。参见 用元数据附加限制。 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_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 会增加热路径的延迟。使用短 TTL(分钟而非小时)为每个客户缓存功能集,并在授权变更状态时从您的 webhook 处理程序中使缓存无效 —— 这种结合保持检查快速,并使撤销接近于即时。
生命周期
功能标志授权遵循标准的授权生命周期,但有一项简化:没有交付步骤,因此授权从未停留在 pending 或移动到 failed。
| 触发器 | 效果 |
|---|
| 一次性支付成功 / 订阅变为活动状态 | 使用已设置的 status: delivered 和 delivered_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 以决定您的消息传递。
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 计划解锁高级报告
- 创建标志。
feature_id: advanced_reports,带有元数据 { "tier": "pro", "monthly_report_limit": 100 }。
- 将其附加到您的 Pro 计划订购产品。
- 客户进行订购。 Dodo Payments 创建一个
delivered 授权并触发 entitlement_grant.created;您的 webhook 处理程序为客户启用 advanced_reports,限制为 100。
- 您的应用程序控制功能。 在加载仪表板时,检查缓存的功能集(或调用
listEntitlementGrants),并仅在存在 advanced_reports 时渲染报告选项卡。
- 客户取消。 Dodo Payments 撤销授权并触发
entitlement_grant.revoked;您的处理程序禁用功能。如果客户稍后通过扣款恢复,entitlement_grant.delivered 会恢复它 — 无需代码更改。
最佳实践
- 使用稳定的 snake_case 功能 ID。 您的应用程序代码检查这些字符串;重命名其中一个是双方的重大更改。
- 每个能力一个标志。 优先选择
advanced_reports + api_access 作为两个权限,而不是单一的 pro_bundle —— 撤销和计划混合保持整洁。
- 从 webhook 驱动状态,通过 API 验证。 Webhook 保持您的数据库当前;列表终端是对账工作和缓存丢失的真相来源。
- 立即将
revoked 视为有效。 撤销标志意味着客户不再为该功能付费。控制下一个请求,而不是下一次会话。
- 将限制放在元数据中,而不是代码中。 更改配额然后只需编辑权限 — 新客户会自动获取,而现有授权保留他们购买的快照。