The two plan axes
An end user has two independent plan axes (full detail):- Asserted plan — the
plana client or client token claims. Convenient for selecting per-plan limits, but a client controls it, so it can never be the source of truth for paid access. - Authoritative entitlement — a tier your backend grants that a client can never set itself. This is what you gate paid features on.
plan claim at the next mint, so the existing per-plan policy engine enforces it with no gateway change.
1. Define per-plan limits
Gating is enforced through usage controls keyed on the plan. Configureend_user_plan policies — a generous pro tier and a tighter free one — so the plan a user resolves to actually changes what they can do:
pro with the higher allowance. Gating premium models is just an allowed_models difference expressed through the plan’s policies.
2. Grant the entitlement after a purchase
When a user buys, your purchase handler — typically an App Store Server Notification or Play RTDN handler — calls the entitlement setter with your secret key:tier— the authoritative tier (pro,free, or your own names). Last-write-wins per user.expires_at— optional; past it, the effective tier falls back to the asserted plan on the next mint.source— optional provenance (storekit,manual, …).
3. Let the client pick up its new tier
The entitlement takes effect on the next client-token mint. A returning client re-mints when its short-lived token expires (RoadieKit does this automatically), and the new token carries thepro plan claim — at which point the pro limits apply. No app deploy, no gateway change.
4. Downgrades and refunds
To downgrade — a cancellation, refund, or lapse — granttier: "free". An explicit free entitlement is an authoritative downgrade that overrides an asserted pro, so a client that keeps claiming pro still resolves to free. The “customer since” marker is preserved for your records.
The reserved free_exhausted tier (mobile guard)
free_exhausted is a reserved tier that resolves to an intrinsic hard requests = 0 / month deny — request #1 is refused with a quota_error the instant it is stamped, without any configured policy. The mobile free-tier guard uses it to paywall a device that has burned its monthly free allotment. The deny self-heals when the UTC month rolls over, and a pro grant overrides it at any time — so a device that pays flips straight to pro on its next mint.
Entitlement is read-only in the dashboard — there is no entitlement editor. A grant is always
an authenticated
PUT from your backend, which keeps your server the sole authority over who is a
paying user.Related
End users & entitlements
The entitlement model in depth.
Free-to-Pro with StoreKit
The end-user monetization flow end to end.
Mobile device auth
Anonymous free devices that can upgrade.
Set usage controls
Define the per-plan limits you gate on.