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

FieldDescription
keyImmutable runtime key. Lowercase, starts with a letter or digit, and may contain - or _. Maximum 200 characters.
activeWhether the flag can enable for any identity.
variantsUp to 10 variants. Non-empty variant rollout percentages must sum to 100.
rulesUp to 10 ordered rules. The first matching rule wins.
rules[].cohortIdCohort in the same project.
rules[].distinctIdsExact override list, up to 50 IDs, each up to 255 characters.
rules[].rolloutPctPercentage of matching identities that enter the rule.
rules[].variantOptional 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/*:

bash
curl https://cohorly-service.velloalabs.com/api/flags?projectId=1 \
-H "Authorization: Bearer $API_KEY"

Send a project token on /flags/evaluate:

bash
curl -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

GET/api/flags

List the flags accessible to the authenticated account.

NameTypeRequiredDefaultDescription
projectIdintegerOptional-

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

POST/api/flags

Create a flag in a project.

NameTypeRequiredDefaultDescription
projectIdintegerOptional-

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.

keystringRequired-

Lowercase runtime key matching ^[a-z0-9][a-z0-9_-]{0,199}$.

namestringRequired-

Human-readable name.

descriptionstring | nullOptional-

Optional description.

activebooleanOptionaltrue

Whether evaluations can enable the flag.

variantsFlagVariant[]Optional-

Optional list of up to 10 variants. Percentages must total 100 when non-empty.

rulesFlagRule[]Optional-

Optional ordered list of up to 10 rules. An omitted list is empty and matches nobody.

bash
curl -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/api/flags/{id}

Get one flag by numeric id.

NameTypeRequiredDefaultDescription
idintegerRequired-

Flag id from the list or create response.

PUT/api/flags/{id}

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.

bash
curl -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/api/flags/{id}

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.

bash
curl "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

POST/flags/evaluate

Evaluate all or selected flags for one distinct_id.

NameTypeRequiredDefaultDescription
distinct_idstringRequired-

Identity for targeting and deterministic rollout bucketing.

flag_keysstring[]Optional-

Optional filter. When omitted, returns every flag in the project.

tokenstringOptional-

Project token alternative to the X-Cohorly-Token header.

bash
curl -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

GET/flags/local-evaluation

Fetch definitions that server SDKs can evaluate in-process.

Authenticate with the project flag secret, not the project token:

bash
curl 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.

POST/api/projects/{id}/flag-secret

Mint or rotate a project's flag secret.

bash
curl -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.

DELETE/api/projects/{id}/flag-secret

Revoke a project's flag secret without creating a replacement.

bash
curl -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

LimitValue
Flags per project100
Variants per flag10
Rules per flag10
Override IDs per rule50
Override ID length255 characters
Request body1 MB
Shared per-IP rate limit100 requests per 10 seconds
Flags endpoint rate limit1,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" }.

PreviousRate limits
NextAdmin API