HTTP API
JSON in, JSON out, UTF-8. Every resource except health lives under /v1. Paths use public keys, not database ids. A write returns the new representation, including the new version when the resource has one.
Every route except GET /health requires Authorization: Bearer <token>. A missing or unknown token is 401. A valid token on a route it cannot call is 403.
Credentials
| Token | May call |
|---|---|
| Management token | Projects, environments, flags, targeting, SDK keys, and the audit log. It can also evaluate, and then must name the project and environment. |
| SDK key | Evaluation for one environment. The environment is implied by the key. A mismatched project or environment on the request is 403. |
Health
-
GET
/health200 {"status": "ok"}. No token. It reports that the process is up.
Projects
Management token. Creating a key that already exists is 409.
-
POST
/v1/projectsCreate {"key", "name"}. Response is 201 with the same two fields.
-
GET
/v1/projectsOne page, {"items", "next_cursor"}.
-
GET
/v1/projects/{projectKey}One project. An unknown key is 404.
Environments
-
POST
/v1/projects/{projectKey}/environmentsCreate {"key", "name"}. 201. Existing flags start disabled in the new environment. Targeting is not copied.
-
GET
/v1/projects/{projectKey}/environmentsKey and name only. SDK secrets are not in this list.
SDK keys
-
POST
/v1/projects/{projectKey}/environments/{environmentKey}/sdk-keysCreate a key. The plaintext secret is returned once, in this response.
-
GET
/v1/projects/{projectKey}/environments/{environmentKey}/sdk-keysIds, prefixes, and created timestamps. No secrets.
-
DELETE
/v1/projects/{projectKey}/environments/{environmentKey}/sdk-keys/{keyId}Revoke. Evaluation with that key becomes 401.
Flags
-
POST
/v1/projects/{projectKey}/flagskey, name, description, and at least two JSON variations. 201. A disabled configuration is created in every existing environment.
-
GET
/v1/projects/{projectKey}/flagsEach item has the variation list. The query environment adds that environment’s on/off summary. An unknown environment is 404.
-
GET
/v1/projects/{projectKey}/flags/{flagKey}The flag, its variations, and every environment configuration.
-
PATCH
/v1/projects/{projectKey}/flags/{flagKey}Update name and description. Variations may only be appended, and the key cannot change.
Targeting
One environment’s configuration is replaced as a whole document. The body carries the version the client read. A stale version is 409; the client reads again and retries.
-
GET
/v1/projects/{projectKey}/flags/{flagKey}/environments/{environmentKey}The configuration, including version.
-
PUT
/v1/projects/{projectKey}/flags/{flagKey}/environments/{environmentKey}Replace targeting. Success returns the stored document with version + 1.
Audit
-
GET
/v1/projects/{projectKey}/auditNewest first. Optional query: flag, environment, limit (default 50, maximum 200). The actor is a credential id and kind, never the secret.
Evaluation
SDK key or management token. An unknown flag still returns 200: value is the caller’s default, reason is flag_not_found.
-
POST
/v1/evaluateOne flag, one context. The decision includes value, variation_index, reason, and the config version.
-
POST
/v1/evaluate-allEvery flag in the environment for one context. Response is {"decisions": [...]}. It is not a dump of the rule trees.
-
GET
/v1/projects/{projectKey}/environments/{environmentKey}/evaluation-configVariation lists and targeting for that environment, so a caller can evaluate with the same rules. Salts are included. Secrets are not.
POST /v1/evaluate
{
"project_key": "shop",
"environment_key": "prod",
"flag_key": "checkout-v2",
"context": { "key": "user-123", "attributes": { "country": "IT" } },
"default": false
}
Errors
The body is {"error": {"code", "message", "details"}}. details lists {"field", "message"} for validation, and is empty otherwise.
| HTTP | code | When |
|---|---|---|
| 400 | validation_error | Malformed input, or a domain rule rejected the command. |
| 401 | unauthenticated | Missing or unknown credential. |
| 403 | forbidden | The credential is valid and not allowed to do this. |
| 404 | not_found | Unknown project, environment, or flag on a management route. |
| 409 | conflict | Duplicate key, or a stale config version. |
| 500 | storage_error | Database failure. The message is generic. |
Lists
List routes take limit and cursor. limit defaults to 50 and must be a whole number from 1 to 200. cursor is opaque; the client sends back the next_cursor it received. A null cursor means the page is the last one.