Download the HTTP Postman collection
Twenty-seven ready-to-run requests covering the whole API over HTTP, each with response tests, plus an environment template whose values are left blank for you to fill in. Connecting to Maxlona takes one paste of your Management Key.
Download Maxlona HTTP Collection- Maxlona HTTP Consumer — the collection.
- Maxlona Production — the environment template, with empty values.
- 01 — read and evaluate an existing flag. Changes nothing.
- 02 — create, configure, toggle, evaluate, delete a temporary flag.
- 03 — security checks that are meant to fail.
- 04 — the same API over GraphQL.
Connect it to your account
- Unzip, then in Postman choose File → Import and import both JSON files.
- Pick Maxlona Production in the environment dropdown, top right.
- Create your keys under Management Keys: one with CanEvaluate scoped to an application for
productionKey, and one with CanRead and CanWrite formanagementKey. Each key is shown once, so copy it straight away. - Paste them into the Current Value column, not Initial Value — current values stay on your machine and never travel with an export or a shared workspace.
- Fill in
application,environment,flagNameanduserIdwith your own values. LeaverunFlagNameempty; the collection sets it while it runs. - Run folder 01 first to confirm the keys work, then 02 top to bottom.
Prefer GraphQL? The Maxlona GraphQL Consumer collection ↓ covers the same API from a single endpoint — see the GraphQL page.
Authentication
Every integration request to /api/flags* or /flags/* must include an x-management-key header. The key carries its own org and permission scope.
x-management-key: YOUR-MANAGEMENT-KEY403. Key lifecycle
A key is 64 lowercase hex characters. The plaintext is returned once — in the create response and again on rotate — and is never retrievable afterwards, so store it in your secret manager immediately. The list view shows only the first 8 characters so you can tell keys apart. Only admin and globaladmin can create, rotate, disable, or delete keys.
Endpoints
| Method | Path | Purpose | Permission |
|---|---|---|---|
| Flags | |||
| GET | /api/flags | List visible flag definitions | CanRead |
| GET | /api/flags/:name | Read one flag definition | CanRead |
| POST | /api/flags | Create a flag | CanWrite |
| PUT | /api/flags/:name | Partially update metadata or archive state | CanWrite |
| POST | /api/flags/:name/archive | Archive a flag | CanWrite |
| POST | /api/flags/:name/restore | Restore an archived flag | CanWrite |
| DELETE | /api/flags/:name | Delete the flag and all configs | CanWrite |
| Per-environment configuration | |||
| GET | /api/flags/:name/configs | List stage configs, optionally filtered by stage | CanRead |
| POST | /api/flags/:name/configs | Upsert a stage config | CanWrite |
| PATCH | /api/flags/:name/configs/:stage/enabled | Turn one stage on or off without resending the config | CanWrite |
| DELETE | /api/flags/:name/configs/:stage | Remove one stage's configuration | CanWrite |
| GET | /api/flags/:name/environments | List the environments the flag uses | CanRead |
| PUT | /api/flags/:name/environments | Replace the flag's environment list | CanWrite |
| Organization settings | |||
| GET | /api/environments | List the org's environments | CanRead |
| PUT | /api/environments | Replace the environment list | CanWrite |
| PATCH | /api/environments/:name | Rename one environment | CanWrite |
| GET | /api/applications | List the org's applications | CanRead |
| PUT | /api/applications | Replace the application list | CanWrite |
| PATCH | /api/applications/:name | Rename one application | CanWrite |
| GET | /api/kill-switch | Read the current kill-switch state | CanRead |
| PUT | /api/kill-switch | Replace the kill-switch state | CanWrite |
| Evaluation | |||
| POST | /flags/:name | Evaluate a flag for a user | CanEvaluate |
/api/flags
Creates a new flag in the org owning the key. Returns 409 if a flag with the same name already exists.
Request headers
x-management-key: <your-key>
Content-Type: application/jsonRequest body fields
| Field | Type | Required | Notes |
|---|---|---|---|
| name | string | yes | Unique within the org. |
| project | string | yes | Must match the key's application scope when one is set. |
| type | string | no | release, experiment, or ops. Default release. |
| owner | string | no | Free-text. Default api. |
| description | string | no | Plain text. |
| tags | string[] | no | Searchable in the SPA. |
| variants | Variant[] | no | Default is on/off booleans. |
| dependsOn | string[] | no | Other flag names this flag is gated by. |
Request body (JSON — paste this into Postman)
{
"name": "checkout-redesign",
"project": "Main App",
"type": "release",
"description": "Q3 checkout flow rewrite",
"tags": ["checkout", "q3"],
"variants": [
{ "key": "on", "value": true, "valueType": "boolean" },
{ "key": "off", "value": false, "valueType": "boolean" }
],
"dependsOn": []
}Curl
curl -X POST $HOST/api/flags \
-H "x-management-key: $FF_MANAGEMENT_KEY" \
-H "Content-Type: application/json" \
--data @create-flag.jsonResponse (201 Created)
{
"name": "checkout-redesign",
"type": "release",
"project": "Main App",
"owner": "api",
"description": "Q3 checkout flow rewrite",
"tags": ["checkout", "q3"],
"variants": [{ "key": "on", "value": true, "valueType": "boolean" }, { "key": "off", "value": false, "valueType": "boolean" }],
"dependsOn": [],
"isArchived": false,
"activatesAt": null,
"expiresAt": null,
"createdAt": "2026-05-17T18:30:00Z"
}/api/flags
Returns flag definitions newest first. An application-scoped key only receives flags in that application.
Curl
curl $HOST/api/flags \
-H "x-management-key: $FF_MANAGEMENT_KEY"/api/flags/:name
Returns one flag definition or 404. It does not embed per-stage configs. An out-of-scope flag returns 403.
/api/flags/:name
Partial update — every body field is optional, only the fields you send are changed. Variants, archive state, tags, dependencies, owner, project, description are all updatable here. Per-stage toggle/rollout/rules are on the configs endpoint below.
Request body (edit description + tags)
{
"description": "Approved by Eng leadership",
"tags": ["checkout", "q3", "approved"]
}Archive a flag (one-field body)
{ "isArchived": true }Curl
curl -X PUT $HOST/api/flags/checkout-redesign \
-H "x-management-key: $FF_MANAGEMENT_KEY" \
-H "Content-Type: application/json" \
--data @update-flag.json/api/flags/:name
Permanently removes the flag and every per-stage config row that references it in one transaction. Cache is purged immediately. Subsequent eval requests for this flag return 404.
Curl
curl -X DELETE $HOST/api/flags/checkout-redesign \
-H "x-management-key: $FF_MANAGEMENT_KEY"/api/flags/:name/configs
Creates or updates the per-stage configuration for one (flag, stage) pair. This is what you call to enable / disable a flag in a specific environment, set its rollout percentage, or install targeting rules. Only the cache entry for that exact (flag, stage) is invalidated — other envs keep their warm cache.
If a running automation plan still controls that environment, writing its configuration here — or through the enabled and DELETE config endpoints — suspends the plan in the same save, so its next step can't overwrite your change. The plan's reason says a Management API key made the change; resume it from the flag's Automation tab.
Request body fields
| Field | Type | Required | Notes |
|---|---|---|---|
| stage | string | yes | dev, uat, production, etc. Stored as sent and matched exactly at evaluation time, so a stage that doesn't match what your SDK evaluates with creates a config nothing ever reads. Must equal the key's environment scope when one is set. Creating a config returns 409 if the flag doesn't use that environment (it was removed from the flag, or is opt-in and not added); updating an existing config is always allowed. |
| enabled | boolean | no | Master switch; omitted JSON binds to false. |
| clientId | string? | no | Optional client-scoped override. Most callers leave null. |
| defaultVariantKey | string | no | Returned when no rule matches. Defaults to "off". |
| rolloutPercentage | number | no | 0–100. Users outside the window get off. Defaults to 100. |
| rules | Rule[] | no | Evaluated highest priority first; the first rule whose conditions all match wins. Each condition's field is looked up as a top-level key of the evaluation context — matched exactly, with no attributes. prefix. Defaults to empty. |
| enrollmentEndsAt | ISO 8601? | no | Optional cutoff for new experiment enrollment. |
Enable at 25% in production
{
"stage": "production",
"enabled": true,
"defaultVariantKey": "off",
"rolloutPercentage": 25,
"rules": []
}Targeted rule — Pro users only
{
"stage": "production",
"enabled": true,
"defaultVariantKey": "off",
"rolloutPercentage": 100,
"rules": [
{
"id": "pro-users",
"priority": 10,
"conditions": [
{ "field": "plan", "operator": "==", "value": "pro" }
],
"allocations": [
{ "variantKey": "on", "percentage": 100 }
]
}
]
}Curl
curl -X POST $HOST/api/flags/checkout-redesign/configs \
-H "x-management-key: $FF_MANAGEMENT_KEY" \
-H "Content-Type: application/json" \
--data @config.jsonResponse (200 OK)
{
"id": "0d5b9b04-9b6e-4d1d-bc11-a3a73e6e0001",
"flagId": "checkout-redesign",
"stage": "production",
"clientId": null,
"enabled": true,
"defaultVariantKey": "off",
"rolloutPercentage": 25,
"rules": []
}Querying flag values (Evaluation API)
The hot read path is served by the Management API on the same host as the rest of the platform, under POST /flags/{key}. It uses its own per-key rate-limit policy so evaluation traffic stays isolated from flag reads and writes. It authenticates through the same x-management-key header used by the rest of this page. Create the key under Management Keys with CanEvaluate permission and an application scope; environment scope is optional.
Two things reject an evaluation before any flag is read:
- An org-wide key (no application scope) always returns
403— “Evaluation requires a management key scoped to one application.” Read and write keys may be org-wide; evaluation keys may not. - An environment-scoped key whose scope doesn't equal the request's
stagereturns403— “Invalid management key for this environment.” The comparison is case-insensitive, and the key's spelling of the stage is what config lookup then uses, so"Production"in the body resolves against a key scoped toproduction. One key per environment means one key per stage you test.
| Field | Required | Notes |
|---|---|---|
| userId | yes | Stable identifier used by targeting and rollout bucketing. |
| stage | yes | Must match the key's environment scope when set. |
| clientId | no | Optional client configuration selector. |
| context | no | Free-form targeting values. |
| explain | no | Boolean query parameter; adds the reason object. |
Curl
curl -X POST "$HOST/flags/checkout-redesign?explain=true" \
-H "x-management-key: $FF_MANAGEMENT_KEY" \
-H "Content-Type: application/json" \
-d '{
"userId": "user-42",
"stage": "production",
"context": { "plan": "pro", "country": "DE" }
}'Response
{
"variant": true,
"key": "on",
"reason": {
"code": "rule_matched",
"message": "Matched rule 'pro-users' (priority 10). Variant chosen by allocation.",
"ruleId": "pro-users"
}
}Calling it from your language
The same requests documented above, written with each language's own HTTP client — no dependency to add. Swap in your host, Management Key, flag name, and stage. If you are on .NET, prefer the official SDK package over hand-rolled HTTP.
Setup
// No install needed — Node 18+ ships a built-in fetchRequest code
const BASE_URL = 'https://maxlona.com';
const MANAGEMENT_KEY = 'YOUR_MANAGEMENT_KEY';
const STAGE = 'production';
async function evaluateFlag(flagKey, userId, context = {}) {
const response = await fetch(BASE_URL + '/flags/' + flagKey, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-management-key': MANAGEMENT_KEY
},
body: JSON.stringify({
userId, stage: STAGE, clientId: '', context
})
});
if (!response.ok) throw new Error('Evaluation failed: ' + response.status);
return await response.json(); // { key: "control", variant: ... }
}
function isEnabled(result) {
return result.key !== 'off' && result.key !== '';
}
// Usage
async function main() {
const context = { lenderId: '100' };
const result = await evaluateFlag('my-feature-flag', 'user-123', context);
console.log('Enabled:', isEnabled(result));
console.log('Key:', result.key); // "control", "treatment", etc.
console.log('Variant:', result.variant); // true, "classic", 42, "#3b82f6"
}
main().catch(console.error);Error responses
| Status | When |
|---|---|
| 400 | Required data is missing or the request body is malformed. |
| 401 | x-management-key is missing, unknown, or disabled. |
| 402 | The organization does not have an active subscription. |
| 403 | The key lacks the permission the endpoint requires, or the request violates the key's scope: evaluating with an org-wide key, evaluating or writing a config for a stage outside the key's environment scope, or touching a flag outside its application scope. The response message names which. |
| 404 | Flag or evaluation configuration not found. |
| 409 | Tried to create a flag whose name already exists in the org, or a stage config in an environment the flag doesn't use. Add the environment on the flag's Manage environments dialog first. Also returned when a flag is created or updated with a dependency on a parent that is missing one of the flag's environments; add that environment to the parent first. |
| 429 | Rate limit exceeded. |
| 500 | Unexpected server-side error. |
Prefer a typed client to raw HTTP? The official Maxlona.FeatureFlags.Offline NuGet package wraps every endpoint on this page — offline evaluation from an encrypted local cache kept current over a realtime SignalR connection, evaluation with typed variants, and the full Management API — for .NET 8 and later.