Attaching a user
For server-key calls, passuser on the request (or as a client-level default):
id— your stable identifier for the end user (opaque to Roadie, up to 256 characters).plan— an optional asserted plan tag (e.g.free,pro) that selects a per-plan limit policy.
With a client token, the end-user id and plan are carried in the
token — the customer’s auth system is the source of truth. A
user in the request body must
match the token or be omitted.Per-user limits
You configure end-user limit policies, including per-plan presets (free vs pro). Because a
request is attributed to a user, the limits engine enforces
that user’s rate limits and quotas in addition to the key, environment, and project limits.
A user over their limit fails with a rate_limit_error
(e.g. end_user_rpm_exceeded) or a quota_error — without
affecting your other users.
Analytics
Usage and cost roll up per end user, so the dashboard can show your top users by spend or volume, and per-user usage over time. This is the same data your support team uses to answer “why is this user’s bill high?”.Blocking a user
If a user abuses your app, block them from the dashboard. A block is enforced instantly: it writes a Redis denylist entry keyed by(project, external id) — the same fast-propagation path
that revokes keys — so the gateway rejects that user’s requests within a second with
permission_error / end_user_blocked. Unblock to
restore access. The durable source of truth is the user’s blocked_at, which the denylist is
re-synced from.
Entitlements
An end user has two independent plan axes:- Asserted plan — the
planin the request body or client token. It reflects what the client claims and is convenient for selecting per-plan limits. - Authoritative entitlement — a tier your backend grants and 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 hot-path change. An explicit entitlement of free is an authoritative downgrade that
overrides an asserted pro; an expired or unset entitlement falls back to the asserted plan.
Granting an entitlement
Grant or change an entitlement with a secret key only — this is the anti-self-upgrade gate, so a client token or publishable key is rejected with apermission_error and a device can
never raise its own tier:
tier— the authoritative tier (e.g.free,pro). Last-write-wins per user.expires_at— optional; past it, the effective tier falls back to the asserted plan.source— optional provenance (e.g.storekit,manual).
Entitlement is read-only in the dashboard — there is no entitlement editor. A grant is
always an authenticated
PUT from your backend (typically your App Store Server Notification
or webhook handler), which keeps your server the sole authority over who is a paying user.The reserved free_exhausted tier
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. It is used by the mobile free-tier guard 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.
For the full flow — from a free device to a paying customer — see the
free-to-pro entitlements guide and the
StoreKit tutorial.