---
title: Flagpole API reference
description: Endpoints, parameters, and error codes for the Flagpole feature-flag REST API.
url: https://pr-9-c0fdf0ef9f59.thally.app/guides/flagpole-api
---

# Flagpole API reference

Endpoints, parameters, and error codes for the Flagpole feature-flag REST API.

## Base URL and authentication

All request and response bodies are JSON. `GET /health` is always public; every `/v1` route requires `Authorization: Bearer <token>` when the server is started with an API token.

## Endpoints

| Method | Path | Description | Body / params | Success |
| ------ | ---- | ----------- | ------------- | ------- |
| `GET` | `/health` | Liveness check. | — | `200` `{ "status": "ok" }` |
| `GET` | `/v1/flags` | List all flags. | `?tag=<t>` (optional) returns only flags carrying that tag | `200` `{ "flags": [Flag] }` |
| `POST` | `/v1/flags` | Create a flag. | `key` (string, required), `enabled` (boolean, required), `description` (string, optional), `rolloutPercentage` (integer 0–100, optional), `tags` (array of strings, optional) | `201` `Flag` |
| `GET` | `/v1/flags/:key` | Fetch one flag. | `:key` path param | `200` `Flag` |
| `PATCH` | `/v1/flags/:key` | Update a flag. | `enabled` (boolean), `description` (string), `rolloutPercentage` (integer 0–100), and/or `tags` (array of strings) — at least one | `200` `Flag` |
| `POST` | `/v1/flags/:key/toggle` | Flip a flag's `enabled` state without a body. | `:key` path param | `200` `Flag` |
| `PUT` | `/v1/flags/:key/tags/:tag` | Attach one tag to a flag (idempotent). | `:key` and `:tag` path params; the same tag rules as `tags` apply | `200` `Flag` |
| `DELETE` | `/v1/flags/:key` | Delete a flag. | `:key` path param | `204` (no body) |
| `GET` | `/v1/flags/:key/evaluate` | Evaluate a flag (hot path for pollers). | `:key` path param; `?unit=<string>` (optional) buckets the unit for percentage rollouts | `200` `{ "key", "enabled", "rolloutPercentage"? }` |
| `GET` | `/v1/flags/:key/history` | Change history for a flag. | `:key` path param; `?limit=<n>` (optional) returns only the most recent `n` events (integer 1–500) | `200` `{ "key", "events": [FlagEvent] }` |
| `GET` | `/v1/tags` | List distinct tags across all flags with usage counts. | — | `200` `{ "tags": [{ "tag", "count" }] }` |
| `DELETE` | `/v1/tags/:tag` | Retire a tag: remove it from every flag carrying it. | `:tag` path param | `200` `{ "tag", "removedFrom" }` |

## Error codes

| Status | Code | When |
| ------ | ---- | ---- |
| `400` | `invalid_json` | Body is not valid JSON. |
| `400` | `invalid_key` | Missing or malformed `key` on create. |
| `400` | `invalid_enabled` | `enabled` is not a boolean. |
| `400` | `invalid_description` | `description` is not a string. |
| `400` | `invalid_rollout_percentage` | `rolloutPercentage` is not an integer between 0 and 100. |
| `400` | `invalid_tags` | `tags` is not an array of up to 10 unique lowercase kebab-case strings (1–50 chars each). |
| `400` | `empty_update` | PATCH body has none of `enabled`, `description`, `rolloutPercentage`, or `tags`. |
| `400` | `invalid_limit` | History `limit` is not an integer between 1 and 500. |
| `401` | `unauthorized` | Missing or wrong bearer token. |
| `404` | `flag_not_found` | No flag with that key. |
| `404` | `tag_not_found` | `DELETE /v1/tags/:tag` named a tag that no live flag carries. |
| `404` | `not_found` | Unknown route. |
| `409` | `flag_exists` | Create with a key that already exists. |