{"openapi":"3.1.0","info":{"title":"nthbouncer Control API","version":"1.0.0","description":"Give agents access to your data sources so they work from real tables and columns for more accurate results, without sharing the database password. Manage pools, keys, Capacity budgets, webhooks, and metrics. AI assistants normally use the MCP server at https:\/\/nthbouncer.com\/mcp instead."},"servers":[{"url":"https:\/\/nthbouncer.com"}],"tags":[{"name":"identity","description":"Token identity and granted abilities"},{"name":"budgets","description":"Capacity budgets shared across pools"},{"name":"pools","description":"Concurrency pools and keys"},{"name":"metrics","description":"Pool admit, queue, and reject series"},{"name":"webhooks","description":"Team webhook destinations for async job callbacks"}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"Organization Control API token from Settings \u2192 API tokens."}},"schemas":{"User":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"},"email":{"type":"string","format":"email"}},"required":["id","name","email"]},"Team":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"},"slug":{"type":"string"}},"required":["id","name","slug"]},"Budget":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"},"pool_ids":{"type":"array","items":{"type":"integer"}},"origin_max_concurrent":{"type":"integer","nullable":true},"unallocated":{"type":"integer"}},"required":["id","name","pool_ids","origin_max_concurrent","unallocated"]},"PoolBudget":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"},"reserved_concurrent":{"type":"integer"}},"required":["id","name","reserved_concurrent"]},"Pool":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"},"description":{"type":"string","nullable":true},"subdomain":{"type":"string","description":"Pool label used in *.nthpool.cloud URLs and API paths."},"backend":{"type":"string","enum":["http","postgres","mysql"]},"max_concurrent":{"type":"integer"},"require_key":{"type":"boolean"},"has_credential":{"type":"boolean"},"budget":{"oneOf":[{"$ref":"#\/components\/schemas\/PoolBudget"},{"type":"null"}]}},"required":["id","name","subdomain","backend","max_concurrent","require_key","has_credential"]},"EnsureDatabasePoolRequest":{"type":"object","additionalProperties":false,"properties":{"db_host":{"type":"string","description":"Public hostname. Not localhost."},"db_port":{"type":"integer","nullable":true},"db_name":{"type":"string"},"db_sslmode":{"type":"string","enum":["verify-full","require"],"nullable":true},"name":{"type":"string","nullable":true}},"required":["db_host","db_name"]},"AuthHandoffRequest":{"type":"object","additionalProperties":false,"properties":{"auth_method":{"type":"string","enum":["bearer_static","api_key","basic","postgres_role"]},"credential_id":{"type":"integer","nullable":true},"credential_name":{"type":"string","nullable":true}}},"AuthHandoff":{"type":"object","properties":{"pool":{"type":"object"},"pool_created":{"type":"boolean"},"custody_flipped":{"type":"boolean"},"already_attached":{"type":"boolean"},"auth_method":{"type":"string"},"intake_url":{"type":"string","nullable":true},"intake_token":{"type":"string","nullable":true},"dashboard_url":{"type":"string"},"expires_at":{"type":"string","format":"date-time","nullable":true},"required_fields":{"type":"array","items":{"type":"string"}},"auth_posture":{"type":"string"},"next":{"type":"string"}},"required":["pool","already_attached","auth_method","dashboard_url"]},"EnsureHttpPoolRequest":{"type":"object","additionalProperties":false,"properties":{"origin":{"type":"string","description":"The https origin your client already calls."},"name":{"type":"string","nullable":true,"description":"Pool name. Omit to derive it from the host."}},"required":["origin"]},"PoolKey":{"type":"object","properties":{"id":{"type":"integer"},"label":{"type":"string"},"last_four":{"type":"string"},"access":{"type":"string","enum":["read","write"]},"allowed_methods":{"type":"array","items":{"type":"string"}},"read_paths":{"type":"array","items":{"type":"string"}},"expires_at":{"type":"string","format":"date-time","nullable":true},"revoked_at":{"type":"string","format":"date-time","nullable":true},"created_at":{"type":"string","format":"date-time","nullable":true},"key":{"type":"string","description":"Plaintext pool key returned once at creation."},"signing_secret":{"type":"string","description":"Signing secret returned once at creation when origin signing is enabled."}},"required":["id","label","last_four","access","allowed_methods"]},"PoolKeyCreateRequest":{"type":"object","properties":{"label":{"type":"string","maxLength":60},"expires_preset":{"type":"string","enum":["none","1h","24h","7d"],"description":"Key lifetime preset. Omit for no expiry."},"access":{"type":"string","enum":["read","write"],"description":"Omit for full write access (default)."}}},"MetricsRange":{"type":"object","properties":{"from":{"type":"string","format":"date-time","nullable":true},"to":{"type":"string","format":"date-time","nullable":true},"retention_days":{"type":"integer"},"clamped":{"type":"boolean"}},"required":["from","to","retention_days","clamped"]},"PoolMetricsSummary":{"type":"object","properties":{"pool_id":{"type":"integer"},"requests":{"type":"integer"},"admitted":{"type":"integer"},"admit_rate":{"type":"number"},"queued_count":{"type":"integer"},"queued_pct":{"type":"number"},"range":{"$ref":"#\/components\/schemas\/MetricsRange"}},"required":["pool_id","requests","admitted","admit_rate","queued_count","queued_pct","range"]},"WebhookEndpoint":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"},"description":{"type":"string","nullable":true},"url":{"type":"string"},"disabled":{"type":"boolean"},"pool_ids":{"type":"array","items":{"type":"integer"}},"signing_secret":{"type":"string","description":"Plaintext signing secret returned once at creation."},"async_enabled_on_pool_ids":{"type":"array","items":{"type":"integer"},"description":"Pools that were switched to async on this create."}},"required":["id","name","url","disabled","pool_ids"]},"StoreWebhookEndpointRequest":{"type":"object","additionalProperties":false,"properties":{"name":{"type":"string","maxLength":60},"url":{"type":"string","maxLength":500,"description":"https callback URL. No loopback or private hosts."},"description":{"type":"string","maxLength":200,"nullable":true},"pool_ids":{"type":"array","items":{"type":"integer"}},"credential_id":{"type":"integer","nullable":true,"description":"Existing bearer_static credential for outbound Authorization on webhook POSTs."},"auth_header":{"type":"string","maxLength":64,"nullable":true,"description":"Lowercase header name for outbound auth when credential_id is set."},"new_credential":{"type":"object","nullable":true,"description":"Mint and attach a bearer_static credential inline instead of credential_id.","properties":{"name":{"type":"string","maxLength":60},"bearer_token":{"type":"string","maxLength":4000}},"required":["name","bearer_token"]}},"required":["name","url"]},"SyncPoolWebhooksRequest":{"type":"object","additionalProperties":false,"properties":{"webhook_endpoint_ids":{"type":"array","items":{"type":"integer"},"description":"Destination ids to attach. Replaces the current set. Empty detaches all."}},"required":["webhook_endpoint_ids"]},"PoolWebhooks":{"type":"object","properties":{"pool_id":{"type":"integer"},"subdomain":{"type":"string"},"webhook_endpoint_ids":{"type":"array","items":{"type":"integer"}},"async_enabled":{"type":"boolean"},"async_on_queue":{"type":"boolean"}},"required":["pool_id","subdomain","webhook_endpoint_ids","async_enabled","async_on_queue"]},"Error":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"]}}},"security":[{"bearerAuth":[]}],"paths":{"\/api\/v1\/me":{"get":{"operationId":"getCurrentIdentity","summary":"Current user, team, and token abilities","description":"Returns the authenticated user, their organization, and Sanctum token abilities.","tags":["identity"],"responses":{"200":{"description":"Identity payload","content":{"application\/json":{"schema":{"type":"object","properties":{"user":{"$ref":"#\/components\/schemas\/User"},"team":{"$ref":"#\/components\/schemas\/Team"},"abilities":{"type":"array","items":{"type":"string"}}},"required":["user","team","abilities"]}}}},"401":{"description":"Missing or invalid token","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/Error"}}}}}}},"\/api\/v1\/budgets":{"get":{"operationId":"listBudgets","summary":"List Capacity budgets","tags":["budgets"],"security":[{"bearerAuth":["budgets:read"]}],"responses":{"200":{"description":"Budget collection","content":{"application\/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#\/components\/schemas\/Budget"}}},"required":["data"]}}}}}}},"\/api\/v1\/budgets\/{budget}":{"get":{"operationId":"getBudget","summary":"Show a Capacity budget","tags":["budgets"],"parameters":[{"name":"budget","in":"path","required":true,"schema":{"type":"integer"}}],"security":[{"bearerAuth":["budgets:read"]}],"responses":{"200":{"description":"Budget","content":{"application\/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#\/components\/schemas\/Budget"}},"required":["data"]}}}},"404":{"description":"Budget not found"}}}},"\/api\/v1\/budgets\/{budget}\/pools":{"get":{"operationId":"listBudgetPools","summary":"List pools on a budget","tags":["budgets","pools"],"parameters":[{"name":"budget","in":"path","required":true,"schema":{"type":"integer"}}],"security":[{"bearerAuth":["pools:read"]}],"responses":{"200":{"description":"Pool collection","content":{"application\/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#\/components\/schemas\/Pool"}}},"required":["data"]}}}}}}},"\/api\/v1\/pools":{"get":{"operationId":"listPools","summary":"List pools granted to this token","tags":["pools"],"security":[{"bearerAuth":["pools:read"]}],"responses":{"200":{"description":"Pool collection","content":{"application\/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#\/components\/schemas\/Pool"}}},"required":["data"]}}}}}},"post":{"operationId":"createPool","summary":"Admit an https origin through a durable pool","tags":["pools"],"security":[{"bearerAuth":["pools:write"]}],"requestBody":{"required":true,"content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/EnsureHttpPoolRequest"}}}},"responses":{"201":{"description":"Created pool","content":{"application\/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#\/components\/schemas\/Pool"}},"required":["data"]}}}},"200":{"description":"Existing pool reused","content":{"application\/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#\/components\/schemas\/Pool"}},"required":["data"]}}}},"403":{"description":"Token or actor cannot create pools"},"422":{"description":"Invalid origin or name taken"}}}},"\/api\/v1\/pools\/database":{"post":{"operationId":"createDatabasePool","summary":"Admit a public Postgres host through a durable pool","tags":["pools"],"security":[{"bearerAuth":["pools:write"]}],"requestBody":{"required":true,"content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/EnsureDatabasePoolRequest"}}}},"responses":{"201":{"description":"Created database pool"},"200":{"description":"Existing database pool reused"},"422":{"description":"Host refused or invalid"}}}},"\/api\/v1\/pools\/{pool}\/auth-handoff":{"post":{"operationId":"createPoolAuthHandoff","summary":"Flip a pool to managed auth and mint a one-shot intake","tags":["pools"],"parameters":[{"name":"pool","in":"path","required":true,"schema":{"type":"string"}}],"security":[{"bearerAuth":["pools:write"]}],"requestBody":{"required":true,"content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/AuthHandoffRequest"}}}},"responses":{"200":{"description":"Auth handoff","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/AuthHandoff"}}}}}}},"\/api\/v1\/pools\/{pool}\/credential":{"put":{"operationId":"putPoolCredential","summary":"Attach a vault credential from an existing row or inline secret","tags":["pools"],"parameters":[{"name":"pool","in":"path","required":true,"schema":{"type":"string"}}],"security":[{"bearerAuth":["pools:write"]}],"requestBody":{"required":true,"content":{"application\/json":{"schema":{"type":"object"}}}},"responses":{"200":{"description":"Credential attached"},"422":{"description":"No secret fields or method mismatch"}}}},"\/api\/v1\/pools\/{pool}":{"get":{"operationId":"getPool","summary":"Show a pool by subdomain","tags":["pools"],"parameters":[{"name":"pool","in":"path","required":true,"schema":{"type":"string"},"description":"Pool subdomain label."}],"security":[{"bearerAuth":["pools:read"]}],"responses":{"200":{"description":"Pool","content":{"application\/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#\/components\/schemas\/Pool"}},"required":["data"]}}}},"404":{"description":"Pool not found"}}}},"\/api\/v1\/pools\/{pool}\/keys":{"post":{"operationId":"createPoolKey","summary":"Mint a pool key","tags":["pools"],"parameters":[{"name":"pool","in":"path","required":true,"schema":{"type":"string"},"description":"Pool subdomain label."}],"security":[{"bearerAuth":["keys:write"]}],"requestBody":{"required":false,"content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/PoolKeyCreateRequest"}}}},"responses":{"201":{"description":"Created pool key","content":{"application\/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#\/components\/schemas\/PoolKey"}},"required":["data"]}}}}}}},"\/api\/v1\/pools\/{pool}\/keys\/{apiKey}":{"delete":{"operationId":"revokePoolKey","summary":"Revoke a pool key","tags":["pools"],"parameters":[{"name":"pool","in":"path","required":true,"schema":{"type":"string"},"description":"Pool subdomain label."},{"name":"apiKey","in":"path","required":true,"schema":{"type":"integer"}}],"security":[{"bearerAuth":["keys:write"]}],"responses":{"200":{"description":"Revoked pool key","content":{"application\/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#\/components\/schemas\/PoolKey"}},"required":["data"]}}}},"404":{"description":"Key not found"}}}},"\/api\/v1\/pools\/{pool}\/metrics":{"get":{"operationId":"getPoolMetrics","summary":"Pool admit, queue, and reject metrics","tags":["metrics"],"parameters":[{"name":"pool","in":"path","required":true,"schema":{"type":"string"},"description":"Pool subdomain label."},{"name":"from","in":"query","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"to","in":"query","required":false,"schema":{"type":"string","format":"date-time"}}],"security":[{"bearerAuth":["metrics:read"]}],"responses":{"200":{"description":"Metrics summary","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/PoolMetricsSummary"}}}},"404":{"description":"Pool not found"}}}},"\/api\/v1\/webhooks":{"get":{"operationId":"listWebhooks","summary":"List webhook destinations","tags":["webhooks"],"security":[{"bearerAuth":["pools:read"]}],"responses":{"200":{"description":"Webhook collection","content":{"application\/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#\/components\/schemas\/WebhookEndpoint"}}},"required":["data"]}}}}}},"post":{"operationId":"createWebhook","summary":"Create a webhook destination","tags":["webhooks"],"security":[{"bearerAuth":["pools:write"]}],"requestBody":{"required":true,"content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/StoreWebhookEndpointRequest"}}}},"responses":{"201":{"description":"Created webhook. signing_secret is returned once.","content":{"application\/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#\/components\/schemas\/WebhookEndpoint"}},"required":["data"]}}}},"403":{"description":"Token or actor cannot manage webhooks"},"422":{"description":"Invalid URL, name taken, plan gate, or cap"}}}},"\/api\/v1\/webhooks\/{webhookEndpoint}\/rotate":{"post":{"operationId":"rotateWebhook","summary":"Rotate a webhook signing key","tags":["webhooks"],"parameters":[{"name":"webhookEndpoint","in":"path","required":true,"schema":{"type":"integer"},"description":"Webhook destination id."}],"security":[{"bearerAuth":["pools:write"]}],"responses":{"200":{"description":"Rotated webhook. signing_secret is returned once.","content":{"application\/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#\/components\/schemas\/WebhookEndpoint"}},"required":["data"]}}}},"403":{"description":"Token or actor cannot manage webhooks"},"404":{"description":"Webhook not found in this organization"},"503":{"description":"Edge projection failed; signing key unchanged"}}}},"\/api\/v1\/pools\/{pool}\/webhooks":{"put":{"operationId":"setPoolWebhooks","summary":"Replace webhook destinations on a pool","tags":["webhooks","pools"],"parameters":[{"name":"pool","in":"path","required":true,"schema":{"type":"string"},"description":"Pool subdomain label."}],"security":[{"bearerAuth":["pools:write"]}],"requestBody":{"required":true,"content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/SyncPoolWebhooksRequest"}}}},"responses":{"200":{"description":"Updated attachments","content":{"application\/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#\/components\/schemas\/PoolWebhooks"}},"required":["data"]}}}},"403":{"description":"Token or actor cannot manage webhooks"},"404":{"description":"Pool not found"},"422":{"description":"Unknown destination, plan gate, or cap"}}}}}}