# Control API

## Introduction

The Control API manages Capacity budgets, the pools on them, pool keys,
and pool Metrics from your tools. It lives on your nthbouncer host (for
example `https://nthbouncer.com`), not on `api.nthpool.cloud`.

The API token is **not** a pool key. It never admits traffic on the proxy.

It is also not how AI assistants connect. Those use the MCP server at
`https://nthbouncer.com/mcp`. See [Agents](/docs/agents) for how to add that URL
in Claude or Cursor. There is no token to paste. Use an API token for CI,
scripts, and infrastructure code, where a value in an environment variable is
the right shape.

## Authentication

1. Open **Organization settings → API tokens**.
2. Create a token. Choose when it expires: 1 month, 6 months, or 1 year.
3. Copy the plain token once. Send it as `Authorization: Bearer …`.

Only owners and admins can create or revoke tokens. A token authenticates as
the person who created it in that organization. It can call the Control API
for every budget and pool on the org. Verb abilities still apply
(`budgets:read`, `pools:read`, `pools:write`, `keys:write`, `metrics:read`).

```bash
curl -sS "https://nthbouncer.com/api/v1/me" \
  -H "Authorization: Bearer $NTHBOUNCER_CONTROL_TOKEN" \
  -H "Accept: application/json"
```

## Endpoints

Pool path segments use the pool **subdomain** (the `*.nthpool.cloud` label).

| Method | Path | Ability | Purpose |
|--------|------|---------|---------|
| `GET` | `/api/v1/me` | (any valid token) | Current user, team, abilities |
| `GET` | `/api/v1/budgets` | `budgets:read` | List granted budgets |
| `GET` | `/api/v1/budgets/{id}` | `budgets:read` | Budget detail |
| `GET` | `/api/v1/budgets/{id}/pools` | `pools:read` | Pools under that budget |
| `GET` | `/api/v1/pools` | `pools:read` | List granted pools |
| `GET` | `/api/v1/pools/{subdomain}` | `pools:read` | Pool detail |
| `POST` | `/api/v1/pools/{subdomain}/keys` | `keys:write` | Mint a pool key |
| `DELETE` | `/api/v1/pools/{subdomain}/keys/{id}` | `keys:write` | Revoke a pool key |
| `GET` | `/api/v1/pools/{subdomain}/metrics` | `metrics:read` | Admit / queue / reject series |

Create pools and attach them to Capacity budgets in the dashboard. The Control
API lists budgets and their member pools; it does not create pools under a
budget.

### Mint a pool key (optional TTL)

```bash
curl -sS -X POST "https://nthbouncer.com/api/v1/pools/$POOL_SUBDOMAIN/keys" \
  -H "Authorization: Bearer $NTHBOUNCER_CONTROL_TOKEN" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{"label":"session","expires_preset":"1h"}'
```

`expires_preset` accepts `none`, `1h`, `24h`, or `7d`. You may send `expires_at`
(ISO-8601) instead. The raw key is returned once.

Session runs should prefer a TTL. Project keys in a repo skill may omit expiry.

## Key access

`POST /v1/pools/{pool}/keys` accepts `access`:

| Value | Methods admitted |
|-------|------------------|
| `write` (default) | Every method |
| `read` | `GET`, `HEAD`, `OPTIONS`, plus any methods the pool treats as reads |

A read-only key is refused with `403` on any other method, before the request
reaches your origin and before it takes a concurrency slot. The response
includes `access` and `allowed_methods` so a caller can check what it holds.
When the pool scopes extra read methods to path prefixes, the response also
includes `read_paths`, keyed by method (`{ "POST": ["/services/rest/query/"] }`).

Omitting `access` keeps the previous behavior, so keys minted before this
existed are unchanged.

On a [database pool](/docs/pools/database), `access: read` and `access: write`
both connect as the read role. Method scope is not applied: every query is
`POST`. Writes are refused by Postgres, not by the key.

## MCP

AI assistants use `https://nthbouncer.com/mcp`, not this token. Connection
steps are on [Agents](/docs/agents). Tools and session keys are on
[MCP server](/docs/mcp).

## Related

- [OpenAPI 3.1 spec](/docs/api/openapi.json)
- [Agents](/docs/agents)
- [MCP server](/docs/mcp)
- [Reuse one pool across agent runs](/docs/knowledge-base/agent-pools)
- [Access](/docs/pools/access)
- [Concurrency locks](/docs/api/locks) (lock API on `api.nthpool.cloud`)
