Feature Flags API
Manage project feature flags, evaluate them for an identity, and fetch definitions for server-side local evaluation.
The Feature Flags API has two credential scopes:
/api/*management endpoints use an account credential: a Firebase ID token or the superadmin API key./flags/*runtime endpoints use a project token for remote evaluation or a project flag secret for local-evaluation definitions.
The project token is suitable for client applications. A flag secret exposes targeting definitions and must remain server-side.
Flag model
| Field | Description |
|---|---|
key | Immutable runtime key. Lowercase, starts with a letter or digit, and may contain - or _. Maximum 200 characters. |
active | Whether the flag can enable for any identity. |
variants | Up to 10 variants. Non-empty variant rollout percentages must sum to 100. |
rules | Up to 10 ordered rules. The first matching rule wins. |
rules[].cohortId | Cohort in the same project. |
rules[].distinctIds | Exact override list, up to 50 IDs, each up to 255 characters. |
rules[].rolloutPct | Percentage of matching identities that enter the rule. |
rules[].variant | Optional variant key to serve when the rule matches. |
With no variants, a matching rule returns a simple enabled result. With
variants, a matching rule returns the selected variant and its payload. With no
rules, evaluation is disabled with reason no_match.
Authentication
Send an account credential on /api/*:
bashcurl https://cohorly-service.velloalabs.com/api/flags?projectId=1 \-H "Authorization: Bearer $API_KEY"
Send a project token on /flags/evaluate:
bashcurl -X POST https://cohorly-service.velloalabs.com/flags/evaluate \-H "Content-Type: application/json" \-H "X-Cohorly-Token: YOUR_PROJECT_TOKEN" \-d '{ "distinct_id": "user-123" }'
The token can also be supplied as the request body's token field. The
X-Cohorly-Token header applies to the whole request.
Manage flags
List flags
List the flags accessible to the authenticated account.
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
projectId | integer | Optional | - | Project to list. For a Firebase user token, omission resolves to that organization's oldest project. For a superadmin key, omission uses the legacy default project when one exists and otherwise returns 400; pass it explicitly for predictable behavior. |
Create a flag
Create a flag in a project.
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
projectId | integer | Optional | - | Project that owns the flag. For a Firebase user token, omission resolves to that organization's oldest project. For a superadmin key, omission uses the legacy default project when one exists and otherwise returns 400; pass it explicitly for predictable behavior. |
key | string | Required | - | Lowercase runtime key matching ^[a-z0-9][a-z0-9_-]{0,199}$. |
name | string | Required | - | Human-readable name. |
description | string | null | Optional | - | Optional description. |
active | boolean | Optional | true | Whether evaluations can enable the flag. |
variants | FlagVariant[] | Optional | - | Optional list of up to 10 variants. Percentages must total 100 when non-empty. |
rules | FlagRule[] | Optional | - | Optional ordered list of up to 10 rules. An omitted list is empty and matches nobody. |
bashcurl -X POST https://cohorly-service.velloalabs.com/api/flags \-H "Authorization: Bearer $API_KEY" \-H "Content-Type: application/json" \-d '{"projectId": 1,"key": "checkout-redesign","name": "Checkout redesign","description": "Gradual rollout of the new checkout","active": true,"variants": [{ "key": "control", "rolloutPct": 50 },{ "key": "new", "rolloutPct": 50, "payload": { "layout": "compact" } }],"rules": [{ "distinctIds": ["user-123"], "rolloutPct": 100, "variant": "new" },{ "cohortId": 42, "rolloutPct": 25 }]}'
The response is the complete created flag. The key is unique within the project and cannot be changed later.
Read, update, and delete a flag
Get one flag by numeric id.
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
id | integer | Required | - | Flag id from the list or create response. |
Partially update a flag. The key is immutable.
The request can include name, description, active, variants, and
rules. If variants change, existing rules are checked against the new
variant keys. Send rules: [] to make an active flag explicitly disabled by
configuration.
bashcurl -X PUT https://cohorly-service.velloalabs.com/api/flags/4 \-H "Authorization: Bearer $API_KEY" \-H "Content-Type: application/json" \-d '{"active": true,"rules": [{ "rolloutPct": 50, "variant": "new" }]}'
Delete a flag.
Deletion removes the flag definition. Remove or retire the corresponding application code separately.
Cross-organization flag ids return 404, so the API does not disclose the
existence of another organization's flags.
bashcurl "https://cohorly-service.velloalabs.com/api/flags?projectId=1" \-H "Authorization: Bearer $API_KEY"
json[{"id": 3,"project_id": 1,"created_by": 7,"key": "new-checkout","name": "New checkout","description": null,"active": true,"variants": [],"rules": [{ "rolloutPct": 100 }],"created_at": 1753900800000,"updated_at": 1753900800000}]
json{"id": 4,"project_id": 1,"created_by": 7,"key": "checkout-redesign","name": "Checkout redesign","description": "Gradual rollout of the new checkout","active": true,"variants": [{ "key": "control", "rolloutPct": 50 },{ "key": "new", "rolloutPct": 50, "payload": { "layout": "compact" } }],"rules": [{ "distinctIds": ["user-123"], "rolloutPct": 100, "variant": "new" },{ "cohortId": 42, "rolloutPct": 25 }],"created_at": 1753900800000,"updated_at": 1753900800000}
json{ "ok": true }
Remote evaluation
Evaluate all or selected flags for one distinct_id.
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
distinct_id | string | Required | - | Identity for targeting and deterministic rollout bucketing. |
flag_keys | string[] | Optional | - | Optional filter. When omitted, returns every flag in the project. |
token | string | Optional | - | Project token alternative to the X-Cohorly-Token header. |
bashcurl -X POST https://cohorly-service.velloalabs.com/flags/evaluate \-H "Content-Type: application/json" \-H "X-Cohorly-Token: YOUR_PROJECT_TOKEN" \-d '{"distinct_id": "user-123","flag_keys": ["checkout-redesign"]}'
Remote evaluation uses the identity cluster's canonical id for cohort checks and rollout bucketing. An anonymous id linked to a user id therefore evaluates as the same identity. Exact overrides also match the raw submitted id.
json{"flags": {"checkout-redesign": {"enabled": true,"variant": "new","payload": { "layout": "compact" },"reason": "rule:0"}}}
Local-evaluation definitions
Fetch definitions that server SDKs can evaluate in-process.
Authenticate with the project flag secret, not the project token:
bashcurl https://cohorly-service.velloalabs.com/flags/local-evaluation \-H "Authorization: Bearer $COHORLY_FLAG_SECRET"
The response contains only the fields required for local evaluation:
json{"flags": [{"key": "checkout-redesign","name": "Checkout redesign","active": true,"variants": [{ "key": "control", "rolloutPct": 50 },{ "key": "new", "rolloutPct": 50, "payload": { "layout": "compact" } }],"rules": [{ "rolloutPct": 100, "variant": "new" }],"localEvaluable": true}]}
localEvaluable is false when a rule references a cohort. Cohort membership
depends on server-side event and profile data, so SDKs must use remote
evaluation for that flag. Local evaluation hashes the raw distinct_id, while
remote evaluation hashes the canonical identity id. Pass the identified user id
to local server evaluation when identity linking matters.
json{ "flags": [] }
Flag secrets
The project flag secret is generated through the account API. Only the organization owner or superadmin can mint, rotate, or revoke it.
Mint or rotate a project's flag secret.
bashcurl -X POST https://cohorly-service.velloalabs.com/api/projects/1/flag-secret \-H "Authorization: Bearer $API_KEY"
The response contains { "secret": "..." } once. A rotation invalidates the
old value immediately. GET /api/projects reports only has_flag_secret, not
the secret itself.
Revoke a project's flag secret without creating a replacement.
bashcurl -X DELETE https://cohorly-service.velloalabs.com/api/projects/1/flag-secret \-H "Authorization: Bearer $API_KEY"
The response is { "ok": true }. Revocation is idempotent. New local
definition requests return 401; running server SDKs retain their last
successful definitions by design. Restart them or remove the flag secret from
their configuration to force remote evaluation immediately.
Limits and errors
| Limit | Value |
|---|---|
| Flags per project | 100 |
| Variants per flag | 10 |
| Rules per flag | 10 |
| Override IDs per rule | 50 |
| Override ID length | 255 characters |
| Request body | 1 MB |
| Shared per-IP rate limit | 100 requests per 10 seconds |
| Flags endpoint rate limit | 1,000 requests per 10 seconds per project, plus the shared per-IP limit |
Rate-limited responses are 429 and include a Retry-After header. SDKs
should honor that header and retry with backoff. Invalid JSON, missing fields,
invalid rollout totals, unknown variants, and foreign cohorts return 400.
Creating a flag with a duplicate key returns 409 with key taken; creating
one after the 100-flag project limit returns 409 with flag limit reached.
Requests larger than 1 MB return 413 with
{ "status": 0, "error": "payload too large" }.