Download the GraphQL Postman collection
Eleven ready-to-run requests covering the whole API over GraphQL, 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 GraphQL Collection- Maxlona GraphQL Consumer — the collection.
- Maxlona GraphQL — 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.
Connect it to your account
- Unzip, then in Postman choose File → Import and import both JSON files.
- Pick Maxlona GraphQL in the environment dropdown, top right.
- Create a Management Key under Management Keys with CanRead, CanWrite and CanEvaluate, scoped to the application you want to work in. The key is shown once, so copy it straight away.
- Paste it into the
managementKeyvariable's 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. LeaverunGraphQLFlagNameempty; the collection sets it while it runs. - Run folder 01 first to confirm the key works, then 02 top to bottom.
Prefer plain REST? The Maxlona HTTP Consumer collection ↓ covers the same API over HTTP, and includes these GraphQL requests as folder 04.
The endpoint
Every operation is an HTTP POST to a single URL, with the same x-management-key header the REST API uses. Send Accept: application/json and the response is ordinary JSON.
POST /api/graphql
x-management-key: YOUR-MANAGEMENT-KEY
Content-Type: application/json
Accept: application/jsonCurl
curl -X POST $HOST/api/graphql \
-H "x-management-key: $FF_MANAGEMENT_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{"query":"{ flags { name project type isArchived } }"}'evaluate. Application and environment scope, the subscription check, and the per-key rate limit all apply exactly as they do over REST — GraphQL is a different way in, not a way around. What you can call
The field names mirror the REST endpoints one for one, so anything documented on HTTP & REST applies here too, including the request body shapes.
| Field | Does what | Permission |
|---|---|---|
| flags | Every flag the key can see. | CanRead |
| flag | One flag by name. | CanRead |
| flagConfigs | Stage configurations, optionally for one stage. | CanRead |
| flagEnvironments | Which environments a flag is enabled for. | CanRead |
| environments, applications | Your organization's stages and applications. | CanRead |
| killSwitch | Active kill-switch rules. | CanRead |
| evaluate | Resolve a flag for one user, with an optional reason. | CanEvaluate |
| createFlag, updateFlag | Create or edit a flag's metadata. | CanWrite |
| archiveFlag, restoreFlag, deleteFlag | Retire, bring back, or remove a flag. | CanWrite |
| upsertFlagConfig, setFlagConfigEnabled, deleteFlagConfig | Configure targeting and rollout for a stage, or switch it on and off. | CanWrite |
| updateFlagEnvironments | Choose which environments the flag applies to. | CanWrite |
| replaceEnvironments, renameEnvironment | Manage the organization's stages. | CanWrite |
| replaceApplications, renameApplication | Manage the organization's applications. | CanWrite |
| replaceKillSwitch | Set or clear kill-switch rules. | CanWrite |
Mutation fields run one after another in the order you write them, so a create followed by a configure in the same document behaves the way you'd expect.
Reading flags
Ask for the fields you need and nothing else.
query ListFlags {
flags {
name
project
type
isArchived
variants { key value valueType }
}
}One round trip can answer more than one question — here, a flag and its configurations together, where REST would need two calls:
query OneFlag($name: String!) {
flag(name: $name) {
name
project
description
tags
}
flagConfigs(name: $name) {
stage
clientId
enabled
defaultVariantKey
rolloutPercentage
}
}Creating and configuring
Mutation
mutation CreateFlag($input: CreateFlagInput!) {
createFlag(input: $input) {
name
project
type
createdAt
}
}Variables
{
"input": {
"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" }
]
}
}Targeting for one stage
mutation Configure($name: String!, $input: UpsertFlagConfigInput!) {
upsertFlagConfig(name: $name, input: $input) {
stage
enabled
rolloutPercentage
}
}{
"name": "checkout-redesign",
"input": {
"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 }
]
}
]
}
}field is a JSON property path into your evaluation context: letters, digits, underscores and dots. A name with a hyphen or a space is rejected, so use lenderId, not Lender-id. Evaluating
The same evaluator that answers the REST call, reached a different way. Ask for reason and you get the explanation back — there is no separate explain switch, because requesting the field is the switch.
query Evaluate($key: String!, $userId: String!, $stage: String!, $context: Any) {
evaluate(key: $key, userId: $userId, stage: $stage, context: $context) {
key
variant
reason { code message ruleId }
}
}{
"key": "checkout-redesign",
"userId": "user-42",
"stage": "production",
"context": { "plan": "pro", "country": "DE" }
}Response
{
"data": {
"evaluate": {
"key": "on",
"variant": true,
"reason": {
"code": "rule_matched",
"message": "Matched rule 'pro-users' (priority 10). Variant chosen by allocation.",
"ruleId": "pro-users"
}
}
}
}Several users in one request
Give each evaluation an alias and they come back side by side under those names — useful for rendering a whole screen's worth of flags, or for comparing what two audiences would see.
query EvaluateBoth($key: String!, $stage: String!, $pro: Any, $free: Any) {
proUser: evaluate(key: $key, userId: "user-42", stage: $stage, context: $pro) {
key
variant
}
freeUser: evaluate(key: $key, userId: "user-77", stage: $stage, context: $free) {
key
variant
}
}How failures come back
This is the one real difference from REST. A request that reached the API answers 200 even when the operation failed, and the failure is described in errors. So check errors, not the status code.
{
"errors": [
{
"message": "Flag not found.",
"path": ["flag"],
"extensions": { "code": "NOT_FOUND", "status": 404 }
}
],
"data": { "flag": null }
} Each entry carries an extensions.code and the status the REST call would have returned:
| Code | Status | Meaning |
|---|---|---|
| BAD_REQUEST | 400 | The input failed validation. |
| FORBIDDEN | 403 | The key lacks the permission or the application/environment scope. |
| NOT_FOUND | 404 | No such flag, configuration, or resource. |
| CONFLICT | 409 | The change clashes with existing state, such as a dependency. |
| AUTH_NOT_AUTHORIZED | — | The key is valid but cannot use that field. |
Three cases still answer with an HTTP status instead, before the query is ever read: a missing or unknown key returns 401, an inactive subscription returns 402, and going over your rate limit returns 429. See rate limits and errors.
GraphQL and REST are the same API with the same credentials, so you can mix them freely — evaluate over REST from a hot path, manage flags over GraphQL from a build script, using one key for both.