> ## Documentation Index
> Fetch the complete documentation index at: https://feather.mupeni.dev/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# API Overview

> Base URLs, versioning, authentication, and response conventions.

Feather Flag exposes two separate APIs:

| API                | Base URL                          | Purpose                                                  |
| ------------------ | --------------------------------- | -------------------------------------------------------- |
| **Management API** | `https://nest.feather.mupeni.dev` | CRUD for flags, environments, keys, proposals, analytics |
| **Delivery API**   | `https://fly.feather.mupeni.dev`  | Flag evaluation at the edge (used by SDKs)               |

This reference covers the **Management API**. See [Evaluation](/docs/concepts/evaluation) for the Delivery API.

## Versioning

All Management API endpoints are prefixed with `/v1`.

## Authentication

Programmatic API requests require an `Authorization` header:

```
Authorization: Bearer <api_key>
```

Dashboard requests may also be authenticated with a session cookie. Session auth is intended for
browser-based dashboard usage, not external API clients.

See [Authentication](/docs/authentication) for full details on API keys and session auth.

## Request format

Request bodies must be JSON with `Content-Type: application/json`.

## Response format

All responses are JSON. Successful responses return the resource directly (not wrapped in a `data` key).

### Error shape

```json theme={null}
{
  "error": {
    "code": "RESOURCE_NOT_FOUND",
    "message": "Flag 'my-flag' not found in project.",
    "details": {}
  }
}
```

### Common error codes

| Code                       | Status | Description                                         |
| -------------------------- | ------ | --------------------------------------------------- |
| `UNAUTHORIZED`             | 401    | Missing `Authorization` header                      |
| `INVALID_API_KEY`          | 401    | API key is invalid or has been revoked              |
| `CSRF_MISSING_ORIGIN`      | 403    | CSRF header absent on session request               |
| `CSRF_ORIGIN_MISMATCH`     | 403    | CSRF origin header doesn't match                    |
| `UPGRADE_REQUIRED`         | 403    | Feature requires a higher plan                      |
| `LIMIT_EXCEEDED`           | 403    | Monthly evaluation limit reached                    |
| `PROTECTED_ENVIRONMENT`    | 403    | Environment requires a change proposal              |
| `SELF_APPROVAL_FORBIDDEN`  | 403    | Proposer cannot approve their own proposal          |
| `RESOURCE_NOT_FOUND`       | 404    | Resource does not exist or is not in your org       |
| `CONFLICT`                 | 409    | Duplicate slug/key, or proposal state conflict      |
| `PROPOSAL_ALREADY_PENDING` | 409    | A pending proposal already exists for this flag+env |
| `PROPOSAL_NOT_PENDING`     | 409    | Proposal is not in pending state                    |
| `IMMUTABLE_FIELD`          | 422    | Attempted to update an immutable field              |
| `VALIDATION_ERROR`         | 422    | Request body failed validation                      |

## Pagination

Endpoints that return lists use **cursor-based pagination**:

* Pass `cursor` (an opaque timestamp) to fetch the next page.
* Pass `limit` (1–100, default 50) to control page size.
* The response includes `nextCursor` (null when no more pages) and `hasMore`.

```json theme={null}
{
  "items": [...],
  "nextCursor": 1718000000000,
  "hasMore": true
}
```

## Partial success (207)

Some write endpoints return `207 Multi-Status` when the primary operation succeeded but an edge cache sync failed. The response body includes a `syncWarning` field describing the failure.

```json theme={null}
{
  "id": "flag_abc",
  "syncWarning": "Edge cache sync failed: timeout. Config saved but evaluations may serve stale data."
}
```

Always handle `207` as a success for the primary resource, but alert on `syncWarning` — evaluations may serve stale data until the next sync. Use [Trigger Sync](/docs/api-reference/sync/trigger-sync) to force a retry.
