A feature flag entitlement turns Dodo Payments into a billing-aware feature-flag store. Attach a flag like
advanced_reports to a product, and every paying customer gets a grant your application can check via API or keep in sync with webhooks. No external platform, no OAuth, no delivery step — the grant itself is the capability.What gets delivered
Nothing leaves Dodo Payments — the grant is the deliverable:- On purchase, the grant is created and moves straight to
delivered. There is nopendingphase, no customer action, and no way for delivery to fail. - The grant carries a typed
featurepayload:{ "feature_type": "boolean", "feature_id": "advanced_reports" }. Your application readsfeature_idto decide what to unlock. - Cancellation, refund, or manual revoke moves the grant to
revoked, and your application sees the flag disappear.
feature_id is a merchant-chosen identifier, not unique across entitlements. Two entitlements can confer the same feature_id — for example, a monthly and a yearly Pro plan both granting advanced_reports.Create a feature flag
Open Entitlements
In your Dodo Payments dashboard, go to Entitlements and click + to start a new entitlement, then choose Feature Flags.
Name the flag
Give the flag a Display Name for your dashboard, a Feature ID your application will check (the dashboard suggests one from the name), and a Description so your team knows what it controls.

Optionally add metadata
Toggle Meta Data to attach key-value configuration — limits, tier names, quotas — that is delivered to your application alongside the flag. See Attach limits with metadata.
Attach to a product
Open a product (or create one), find the Entitlements card, and click + to attach existing entitlements. Select your feature flag and click Done.

Required configuration
| Field | Required | Description |
|---|---|---|
feature_id | Yes | Identifier your application checks, e.g. advanced_reports. Not unique across entitlements. |
feature_type | Yes | Type of capability conferred. Only boolean is supported today. |
Create via API
Attach limits with metadata
A boolean flag answers “does this customer have the feature?”. Metadata answers “with what configuration?”. Entitlement metadata accepts string, integer, number, and boolean values, and every grant takes a frozen snapshot of the entitlement’s metadata at the moment it is created. That snapshot behavior is what makes metadata safe to use for plan limits:- Editing the entitlement’s metadata later only affects future grants. Customers keep the limits they purchased under.
- The snapshot is returned on each grant as its
metadatafield, so one API call gives you both the flag and its configuration.
advanced_reports flag with { "tier": "pro", "monthly_report_limit": 100 } lets your application unlock the dashboard and enforce the 100-report quota without a second lookup. If you later raise the limit to 250, existing customers stay at 100 until they receive a new grant (for example, after a plan change).
Check a customer’s features
List a customer’s delivered feature-flag grants and build the set of enabled features. The endpoint returns one row per grant across all entitlements, filterable byintegration_type and status.
The
feature payload is populated only on feature_flag grants; it is null for every other integration type. See the List Customer Grants API reference for the full response shape.Lifecycle
Feature flag grants follow the standard grant lifecycle with one simplification: there is no delivery step, so grants never sit inpending and never move to failed.
| Trigger | Effect |
|---|---|
| One-time payment succeeds / subscription becomes active | Grant created with status: delivered and delivered_at set. |
| Subscription put on hold, cancelled, or expired | Grant revoked with the matching revocation_reason. |
| Refund on a one-time payment | Grant revoked with revocation_reason: refund. |
| Subscription recovers (for example, dunning succeeds) | The revoked grant is restored to delivered — same grant id, revocation fields cleared. |
| Manual API revoke | Grant revoked with revocation_reason: manual. Not auto-restored on renewal. |
Webhooks
Subscribe to theentitlement_grant.* events to mirror flags into your own database instead of polling:
entitlement_grant.created— arrives alreadydeliveredwith thefeaturepayload. Enable the feature.entitlement_grant.delivered— fires when a previously revoked grant is restored. Re-enable the feature.entitlement_grant.revoked— access withdrawn. Disable the feature and checkrevocation_reasonto decide your messaging.
TypeScript
entitlement_grant.failed for feature flags — delivery happens entirely inside Dodo Payments and cannot fail.
Example: Pro plan unlocks advanced reports
- Create the flag.
feature_id: advanced_reportswith metadata{ "tier": "pro", "monthly_report_limit": 100 }. - Attach it to your Pro Plan subscription product.
- A customer subscribes. Dodo Payments creates a
deliveredgrant and firesentitlement_grant.created; your webhook handler enablesadvanced_reportsfor the customer with a limit of 100. - Your app gates the feature. On dashboard load, check the cached feature set (or call
listEntitlementGrants) and render the reports tab only whenadvanced_reportsis present. - The customer cancels. Dodo Payments revokes the grant and fires
entitlement_grant.revoked; your handler disables the feature. If the customer later recovers via dunning,entitlement_grant.deliveredrestores it — no code changes needed.
Best practices
- 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_accessas two entitlements over a singlepro_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
revokedas 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.
