Klor.

HTTP API

What the SDK actually calls. Useful if you need a client Klor does not ship.

GET /v1/config

Returns the published snapshot for the environment the key belongs to.

curl https://edge.klor.dev/v1/config \
-H "Authorization: Bearer klor_pub_…" \
-H "If-None-Match: \"a1b2c3…\""

A public key gets the payload with sensitive flags removed; a private key gets everything. Responses carry a strong ETag, send it back as If-None-Match and an unchanged snapshot answers 304 with no body.

200 OK
{
"v": 1,
"seq": 42,
"environment": { "id": "env_…", "key": "prod" },
"publishedAt": "2026-09-14T09:12:04.000Z",
"flags": {
"checkout_v2": {
"type": "bool",
"enabled": true,
"default": false,
"rules": [
{
"id": "r_ios",
"conditions": [{ "attribute": "platform", "op": "eq", "values": ["ios"] }],
"rollout": { "percentage": 25, "bucketBy": "userId", "salt": "" },
"value": true
}
]
}
},
"gates": { "ios": { "minSupportedVersion": "2.0.0", "latestVersion": "2.5.0" } },
"blockedBuilds": { "ios": ["2.3.1"] }
}

Evaluation is yours to do. The payload is the ruleset, not an answer; that is what keeps user context on the device.

POST /v1/events

Optional usage counters. Klor uses them to tell you which flags are still being read, so dead config can be found and deleted.

curl -X POST https://edge.klor.dev/v1/events \
-H "Authorization: Bearer klor_pub_…" \
-H "Content-Type: application/json" \
-d '{"events":[{"flagKey":"checkout_v2","variant":"true","reason":"rule","count":12}]}'

Counters only. No user or device identifier is accepted or stored, and sending nothing at all is a supported way to run.

The management API

Everything above is the read plane, served from edge.klor.dev and reachable with a public or private key. Changing configuration is a different surface, at klor.dev/api/v1, and needs a klor_adm_ management key created on your project’s API keys page.

A management key is scoped to one environment, is never published to the read plane, and is refused outright if the request carries an Origin header. It is for servers and CI, not for browsers.

curl https://klor.dev/api/v1/flags \
-H "Authorization: Bearer klor_adm_…"
GET /api/v1/meidentity

Which project and environment this token points at. Worth calling first; most confusion is a token aimed at staging.

GET /api/v1/flagslist

Every flag in this environment with its configuration.

GET /api/v1/flags/:keyflag

One flag, addressed by key rather than by id.

PATCH /api/v1/flags/:keyflag

Change enabled, defaultValue or rules. Values are checked against the flag’s declared type.

GET /api/v1/changesdiff

What publishing would change. Empty means the environment is up to date.

POST /api/v1/publishsnapshot

Compiles and publishes. Takes an optional note, returns the new seq.

POST /api/v1/rollbacksnapshot

Republishes an earlier seq under a new one. History moves forward, never backwards.

GET /api/v1/snapshotpayload

The live payload. Add ?visibility=public for the one clients receive; bundle it in a build so a first cold start serves real values.

GET /api/v1/snapshotslist

The last fifty publishes, newest first.

curl -X PATCH https://klor.dev/api/v1/flags/checkout_v2 \
-H "Authorization: Bearer klor_adm_…" \
-H "Content-Type: application/json" \
-d '{"enabled":true,"defaultValue":false}'

Editing does not change what your apps read. Publish is still a separate, deliberate act, which is what makes this safe to automate.

The most useful thing to automate first is the check, not the change: a job that fails when an environment has unpublished edits catches the one failure mode of a publish model, which is editing all day and never publishing.

# Fail the build if someone left edits unpublished.
changes=$(curl -sf https://klor.dev/api/v1/changes \
-H "Authorization: Bearer $KLOR_TOKEN" | jq '.changes | length')

if [ "$changes" -gt 0 ]; then
echo "prod has $changes unpublished change(s)" >&2
exit 1
fi

Errors carry a machine-readable code alongside the message: missing_token, invalid_token, wrong_key_type, browser_request, not_found, invalid_value, snapshot_gone.

Responses

304Not Modified

Your ETag matches the current snapshot. Keep using what you have.

401Unauthorized

Missing or unrecognised API key. Revoked keys stop working immediately.

404Not Found

The environment exists but has never been published.