Feature flags
Module: flags. See README.md for authentication.
| Endpoint | Scope | Permission | What it does |
|---|---|---|---|
GET /apps/{app}/flags |
read | flags.read |
List feature flags |
PUT /apps/{app}/flags/{key} |
write | flags.write |
Create or replace a flag |
DELETE /apps/{app}/flags/{key} |
write | flags.write |
Archive a flag |
Flags are evaluated by the SDKs through POST /api/v1/flags/evaluate, which
takes an ingest key, not an access token. This page is the management side.
List
?includeArchived=true&env=production
A row carries the key, name, kind (boolean or multivariate), variants,
rules, per-environment settings, and a seven-day sparkline of evaluations.
Upsert
PUT /apps/{app}/flags/new-checkout
{
"name": "New checkout",
"description": "Rolling out the rewritten checkout",
"kind": "multivariate",
"variants": [{ "key": "control", "weight": 50 }, { "key": "treatment", "weight": 50 }],
"rules": [
{ "id": "beta-users", "conditions": [{ "field": "trait.plan", "op": "eq", "value": "pro" }], "variant": "treatment" }
],
"environments": {
"production": { "enabled": true, "rolloutPercent": 25 },
"staging": { "enabled": true, "rolloutPercent": 100 }
}
}
The body replaces the whole definition — send the complete set of variants, rules and environments, not a patch. An environment you omit defaults to disabled at 100%, so a production-only rollout does not have to spell out the other two.
The key comes from the path and must match ^[a-z0-9_-]{1,64}$. A multivariate
flag needs at least two variants whose weights total 100. new is reserved.
Bucketing is deterministic: the same distinct id always lands in the same bucket, and the browser and the server agree because both use the same hash.
Archive
DELETE is soft. Evaluation stops, history is kept, and saving the flag again
restores it — which is why the history entry says restored rather than
created. Archiving an already-archived flag is a 409; an unknown key is a
404.