Control API
Introduction
The Control API manages Capacity budgets, the pools on them, pool keys,
webhook destinations, 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 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
- Open Organization settings → API tokens.
- Create a token. Choose when it expires: 1 month, 6 months, or 1 year.
- 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).
Webhook create and attach use pools:write. Listing destinations uses
pools:read.
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 |
POST |
/api/v1/pools |
pools:write |
Admit an https origin (same as MCP create_pool) |
POST |
/api/v1/pools/database |
pools:write |
Admit a public Postgres host |
POST |
/api/v1/pools/{subdomain}/auth-handoff |
pools:write |
Flip to managed auth and mint a one-shot intake |
PUT |
/api/v1/pools/{subdomain}/credential |
pools:write |
Attach a stored credential (secret allowed on this plane) |
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 |
GET |
/api/v1/webhooks |
pools:read |
List webhook destinations |
POST |
/api/v1/webhooks |
pools:write |
Create a destination (signing secret once). Optional pool_ids attaches and enables async |
PUT |
/api/v1/pools/{subdomain}/webhooks |
pools:write |
Replace destinations on a pool. Enables async when the list is not empty |
POST /api/v1/pools takes origin (required) and name (optional). It
reuses a live HTTP pool that already fronts that host, or creates a
pass-through pool with dashboard defaults. It does not attach a Capacity
budget or an origin credential. 201 on create, 200 on reuse.
Attach budgets and managed credentials in the dashboard.
POST /api/v1/webhooks takes name, url, optional description, and
optional pool_ids. The URL must be https and cannot be loopback, private,
or nthbouncer itself. 201 returns signing_secret once (whsec_…).
PUT /api/v1/pools/{subdomain}/webhooks takes webhook_endpoint_ids (may
be empty). Owners and admins only, same as the dashboard.
Mint a pool key (optional TTL)
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, 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. Tools and session keys are on
MCP server.
Related
- OpenAPI 3.1 spec
- Agents
- MCP server
- Reuse one pool across agent runs
- Access
- Concurrency locks (lock API on
api.nthpool.cloud)