Feature Flags API Reference

You can manage flags from the dashboard, or from your own code with the public REST API and a token. This page is a quick map: what each endpoint does, and which scope it needs. A scope is a named permission on your token that controls exactly what it can read or change. Two other pages carry the full detail, with a worked example in cURL, TypeScript, and Python for every operation:

Base URL and authentication

Every endpoint sits under a project and needs a bearer token: a service token or a personal access token. The token names your organization, so the path only carries a project id, never an org id.

Plain text
https://app.avsb.cloud/api/v1/projects/{projectId}/flags
Plain text1 line

The response shape

A successful call returns { "data": ... }. A list also returns a page object for pagination. A failed call returns an error object, not just a plain message string, so your code can branch on error.code:

Example error response
{  "error": {    "code": "validation_failed",    "message": "A flag with this key already exists in this project",    "docUrl": "https://docs.avsb.cloud/docs/developer-reference/public-api/conventions#validation-errors",    "requestId": "req_9f2c41ab7e0b4d1e8c35a6f0d2b91e77"  }}
JSON8 lines

Every error names a code you can match on, a human message, a docUrl pointing at the exact section that explains it, and a requestId for support. The full list of codes, status codes, and rate limits is on the conventions page.

Flags

A flag's variations are the values it can return, such as on/off, or three named colors. Every rule points at one of them.

ActionEndpointScope
List flagsGET /api/v1/projects/{projectId}/flagsflags:read
Create a flagPOST /api/v1/projects/{projectId}/flagsflags:write
Get one flagGET /api/v1/projects/{projectId}/flags/{flagId}flags:read
Update a flag's name, description, or keyPATCH /api/v1/projects/{projectId}/flags/{flagId}flags:write
Delete a flagDELETE /api/v1/projects/{projectId}/flags/{flagId}flags:write
Archive a flagPOST /api/v1/projects/{projectId}/flags/{flagId}/archiveflags:write
Restore an archived flagPOST /api/v1/projects/{projectId}/flags/{flagId}/unarchiveflags:write
Replace a flag's variationsPUT /api/v1/projects/{projectId}/flags/{flagId}/variationsflags:write

{flagId} accepts either the flag's id or its short numeric id, the same one shown in the dashboard.

A few limits worth knowing before you build against this:

  • Every flag needs 2 to 4 variations. A BOOLEAN flag needs exactly 2, with values "true" and "false".
  • You can only delete a flag while it is DRAFT or ARCHIVED.
  • Archiving is refused while any environment is still running. Pause every environment first, then archive.
  • Unarchiving returns the flag to PAUSED, never straight back to RUNNING. Resuming traffic is a separate, per-environment decision.
  • Once a flag has been enabled in any environment, its key can no longer change. Your code reads flags by key, so a silent rename would make every call fall back to the default value.

Create a flag: a worked example

The smallest request that works is a name, a key, a type, its variations, and which one is the default:

curl -X POST "https://app.avsb.cloud/api/v1/projects/<projectId>/flags" \  -H "Authorization: Bearer avsb_svc_..." \  -H "Content-Type: application/json" \  -d '{    "name": "New checkout",    "key": "new_checkout",    "type": "BOOLEAN",    "variations": [      { "name": "Off", "key": "off", "value": "false" },      { "name": "On", "key": "on", "value": "true" }    ],    "defaultVariationKey": "off"  }'
Shell13 lines

A fuller request uses the optional fields. description is free text shown in the dashboard, and a flag can hold up to 4 variations, not just 2:

A STRING flag with three variations
{  "name": "Checkout button color",  "key": "checkout_button_color",  "description": "Which color the primary checkout button renders",  "type": "STRING",  "variations": [    { "name": "Blue", "key": "blue", "value": "blue" },    { "name": "Green", "key": "green", "value": "green" },    { "name": "Orange", "key": "orange", "value": "orange" }  ],  "defaultVariationKey": "blue"}
JSON12 lines

Either call returns 201 with the new flag in DRAFT status, disabled in every environment:

Response
{  "data": {    "id": "flag_abc",    "shortId": 42,    "name": "New checkout",    "key": "new_checkout",    "type": "BOOLEAN",    "status": "DRAFT",    "stale": false  }}
JSON11 lines

A key that already exists in the project returns 409:

409: key already exists
{  "error": {    "code": "validation_failed",    "message": "A flag with this key already exists in this project",    "docUrl": "https://docs.avsb.cloud/docs/developer-reference/public-api/conventions#validation-errors",    "requestId": "req_9f2c41ab7e0b4d1e8c35a6f0d2b91e77"  }}
JSON8 lines

The Public API: Flags page shows every other flag, rule, and variation call the same way.

Turning flags on and off (the kill switches)

Two levels of switch stop traffic without deploying code. Both republish the flag's data file, the small JSON file your SDK reads, so the change is live on the next SDK fetch.

ActionEndpointScope
Stop every rule in one environmentPOST /api/v1/projects/{projectId}/flags/{flagId}/envs/{envId}/pauseflags:write
Resume every rule in one environmentPOST /api/v1/projects/{projectId}/flags/{flagId}/envs/{envId}/runflags:write
Pause one rule, leaving the rest of the environment servingPOST /api/v1/projects/{projectId}/flags/{flagId}/envs/{envId}/rules/{ruleId}/pauseflags:write
Resume one rulePOST /api/v1/projects/{projectId}/flags/{flagId}/envs/{envId}/rules/{ruleId}/runflags:write

Both pause endpoints are safe to call blind, from an alert or a CI job. Pausing something already paused answers 200 with changed: false, not an error, and pausing is never blocked by a pending schedule. Use the two rule-level endpoints for a single misbehaving A/B test. Use the environment-level pair to stop everything the flag serves in one environment at once.

A smaller endpoint changes two things about one environment. defaultVariationId, the variation served when no rule matches, is staged until the environment's next publish. enabled is a shorthand for the run and pause endpoints above: setting it to false stops the environment for real visitors the moment the call returns, and true starts it, with the same schedule guard as run. It is read back as the environment's current serving state.

ActionEndpointScope
Stage the fallback variation, or run and pause through enabledPATCH /api/v1/projects/{projectId}/flags/{flagId}/envs/{envId}flags:write
Replace the per-user overrides (the environment and rule allowlists), staged until the next publishPUT /api/v1/projects/{projectId}/flags/{flagId}/envs/{envId}/overridesflags:write

Rules

A rule decides who gets which variation. A targeted delivery rule serves one variation to an audience, a named group of visitors your targeting rules define. An A/B test rule splits traffic and measures the result instead. Rules belong to one environment, so the same flag can run a 50/50 test in development and a 5% rollout in production.

ActionEndpointScope
List rules in one environmentGET /api/v1/projects/{projectId}/flags/{flagId}/envs/{envId}/rulesflags:read
Create a rulePOST /api/v1/projects/{projectId}/flags/{flagId}/envs/{envId}/rulesflags:write
Get one ruleGET /api/v1/projects/{projectId}/flags/{flagId}/envs/{envId}/rules/{ruleId}flags:read
Update a rulePATCH /api/v1/projects/{projectId}/flags/{flagId}/envs/{envId}/rules/{ruleId}flags:write
Delete a ruleDELETE /api/v1/projects/{projectId}/flags/{flagId}/envs/{envId}/rules/{ruleId}flags:write
Duplicate a rule, disabled, in the same environmentPOST /api/v1/projects/{projectId}/flags/{flagId}/envs/{envId}/rules/{ruleId}/duplicateflags:write
Copy every rule from another environmentPOST /api/v1/projects/{projectId}/flags/{flagId}/envs/{envId}/rules/copyflags:write
Reorder every rule (evaluation order)PUT /api/v1/projects/{projectId}/flags/{flagId}/envs/{envId}/rules/reorderflags:write
Read one rule's resultsGET /api/v1/projects/{projectId}/flags/{flagId}/rules/{ruleId}/resultsresults:read

Rule order is evaluation order: the first matching rule wins. Reorder takes the full list of rule ids in the new order, { "ruleIds": ["rule_1", "rule_2", ...] }. A partial list would leave the rest ambiguous, so it is refused. Copy takes { "sourceEnvId": "..." } and appends every rule from that environment onto the end of this one. Nothing starts running as a side effect: run the copied rules yourself once you are ready.

Environments

An environment is a separate resource from flags. It is where one version of your flags runs, such as production or staging, and it has its own SDK key. Environments is its own item in the project sidebar, next to Settings, not inside it, and it only appears for feature-flag projects.

ActionEndpointScope
List environmentsGET /api/v1/projects/{projectId}/environmentsprojects:read
Create an environmentPOST /api/v1/projects/{projectId}/environmentsprojects:write
Get one environmentGET /api/v1/projects/{projectId}/environments/{envId}projects:read
Update an environment's name or colorPATCH /api/v1/projects/{projectId}/environments/{envId}projects:write
Delete an environmentDELETE /api/v1/projects/{projectId}/environments/{envId}projects:write
Publish the data file for an environmentPOST /api/v1/projects/{projectId}/environments/{envId}/publishprojects:write

Environments use projects:read and projects:write, not the flags:* scopes above. A token scoped only to flags:write cannot create or delete an environment. Deleting one is refused if it would leave the project with fewer than two active environments, and the built-in Production and Development environments can never be deleted. See Public API: Environments for full examples.

Event definitions stay in the dashboard

The event definitions a rule measures against are managed from the dashboard today, so a token cannot list, create, or change them. Per-user overrides are different: a token with flags:write can replace them with PUT /api/v1/projects/{projectId}/flags/{flagId}/envs/{envId}/overrides, described under Replace per-user overrides.

SDK heartbeat

The SDK sends a heartbeat after every successful data file fetch, automatically. You never call this yourself; it is what marks an environment "connected" in the dashboard.

POST /api/sdk/heartbeat

This one endpoint is public: no bearer token, because the SDK identifies itself with its environment's SDK key instead.

Request body
{  "sdkKey": "sdk_production_xxxxxxxxxxxxxxxx",  "sdkType": "@avsbhq/browser",  "sdkVersion": "1.5.0"}
JSON5 lines

A successful heartbeat returns { "success": true }. Note this endpoint predates the rest of the API and does not use the { "data": ... } / { "error": {...} } envelope described above:

Response
{ "success": true }
JSON1 line
404: unknown SDK key
{ "error": "Unknown SDK key" }
JSON1 line

Next steps

Was this helpful?