Feature flags

Feature flags
that know who paid

Most flag tools answer 'is this on?'. Paywall answers 'is this on for this customer, on this plan, after this payment?', and delivers the answer as a token your backend verifies without a network call.

Three shapes

Every flag is a boolean, a number or a text value

One field in the dashboard, one type. The type decides how the flag compiles into config, the entitlement token and the per-user snapshot.

On or off

boolean

The classic flag. Granted by a plan or comped for one customer, it compiles to true in the token.

"priority_support": true

A limit

number

Seats, exports per month, projects. Each plan sets its own number; an empty limit means unlimited.

"exports": 500

A value

text

A tier name, a model id, a region. Whatever string your app should read for this customer.

"model": "large"
Resolution

Plan first, then the customer's overrides

A flag's value comes from the customer's plan. A per-customer override wins over the plan and survives refunds, so a comp you granted by hand is never revoked by a payment event.

entitlement token (decoded)
{
  "iss": "paywall",
  "sub": "user_8f2a",
  "plan": "pro",
  "status": "active",
  "features": {
    "priority_support": true,
    "exports": 500,          // from the plan
    "model": "large",       // per-customer override
    "beta_editor": true      // comped by hand
  },
  "exp": 1757165400
}

Granted by plan

Each plan is a grant matrix over the app's flags. Publishing compiles every plan into one config blob at the edge.

Overridden per customer

Grant, comp or restrict a flag for one customer from the dashboard or the admin API. The snapshot is rewritten immediately.

Delivered as a token

identify returns a 15-minute HS256 token signed with the app's secret. Your backend verifies it locally, so gating costs nothing per request.

Read from the edge

Per-user snapshots live in KV next to the config. A fresh read endpoint exists for the seconds right after a payment lands.

In your app

One hook in the UI, one verify on the server

The React SDK keeps the customer token fresh and exposes each flag with its value. The server SDK verifies the entitlement token with the secret it already holds.

Exports.jsx
const exports = useFeature("exports");
const model   = useFeature("model");

if (!exports.enabled) return <Upsell plan="pro" />;
return <Exporter quota={exports.value} model={model.value} />;
api/export.js
const claims = await hub.verifyToken(req.headers.authorization);
// signed by Paywall, verified here — no network call
const quota = claims.features.exports;
if (quota === undefined) return forbidden();
if (quota !== true && used >= quota) return limitReached();

Granted-by view

Every flag page lists the plans and customers that grant it, so you can see who gets what before you publish.

Draft and live

The dashboard compares the draft catalogue with the published blob and shows exactly what a publish would change.

Validated writes

A number flag rejects a non-numeric limit at write time, in the UI and the admin API alike, so agents can't publish garbage.

Flags, plans and prices from one publish

Define the flags, group them into plans, add prices, publish. Or hand the whole job to your coding agent with one prompt.