API overview
The CapyDB control plane is a plain HTTP API documented by an OpenAPI spec. Everything the dashboard and CLI do, you can do.
Base URL and spec
https://capydb.dev/api/capydbAll endpoints are under /v1. The OpenAPI document is public:
GET https://capydb.dev/api/capydb/v1/openapi.jsonThe per-tag pages in this section are generated from that document, so they cannot drift from the implementation. The TypeScript SDK is generated from the same spec.
Authentication & API keys
Programmatic callers authenticate with an API key, either as a bearer token or a header:
curl -H "Authorization: Bearer capy_live_..." https://capydb.dev/api/capydb/v1/projects
curl -H "X-API-Key: capy_live_..." https://capydb.dev/api/capydb/v1/projectsKeys belong to an organization and are created in the dashboard (Settings → API keys) or via POST /v1/organizations/{orgID}/api-keys. The plaintext is shown once; only a SHA-256 hash is stored. Keys can carry an expiry and are revocable without touching anything else.
Scopes
Each key carries explicit scopes: projects:read, projects:write, credentials:read, backups:read, backups:write, jobs:read, organizations:read, organizations:write, api_keys:read, api_keys:write. Grant what the consumer needs, nothing else.
Project-scoped keys
A key created with a project_id is restricted to that single project:
- it can only act on that project (and its previews, backups, jobs)
- it cannot touch sibling projects
- org-management scopes (
organizations:write,api_keys:write, ...) are rejected on it
Use project-scoped keys for CI and integrations — the GitHub Action, deploy scripts, anything whose blast radius should be one project. A leaked project-scoped key is an incident; a leaked org key is a worse one.
Human sessions
Browser and CLI sessions are Clerk-authenticated; the active Clerk organization resolves which org you act in. Some actions are gated to the Clerk org admin role when called with a session: project create/delete, overwrite-restores, and API-key create/revoke.
Asynchronous jobs
Lifecycle actions (provision, backup, restore, import, preview create/reset/delete, credential rotation, deletion) return 202 Accepted with a job object instead of blocking. Poll GET /v1/jobs/{jobID} until completed or failed:
curl -s -H "X-API-Key: $CAPYDB_API_KEY" \
https://capydb.dev/api/capydb/v1/jobs/job_... | jq '.job.state'Or subscribe to webhooks (job.completed, job.failed, and the higher-level *.ready/*.completed events) instead of polling.
Conventions
- List endpoints always return JSON arrays — never
null. - Errors are
{"error": "message"}with an appropriate 4xx/5xx status. - Rate limiting is applied per IP (with a stricter bucket on the CLI-login endpoints). Back off on
429.
Quick tour
# Who am I?
curl -s -H "X-API-Key: $KEY" $BASE/v1/me
# Create a clone preview and wait for it
JOB=$(curl -s -X POST -H "X-API-Key: $KEY" -H "Content-Type: application/json" \
-d '{"name":"pr-42","mode":"clone","ttl_hours":72}' \
$BASE/v1/projects/$PROJECT/preview-databases | jq -r '.job.id')
curl -s -H "X-API-Key: $KEY" $BASE/v1/jobs/$JOB | jq '.job.state'
# Fetch its connection strings once ready
curl -s -H "X-API-Key: $KEY" $BASE/v1/preview-databases/$PREVIEW/connections