The REST API behind the CLI: projects, settings, keys, SQL, types, migrations, branches, functions, members, the audit log, and every dashboard feature (backups, compute, replicas, flags, queues, cron, push, links, metering, monitors and more), with an access token.
Base URL https://stitchdb.com/platform/v1. Authenticate with an access token (Authorization: Bearer sdb_pat_…). Read-only tokens can read everything their projects allow and run read-only SQL; changes need a read-write token. Tokens limited to some projects only see those. Requests are limited to about 5 per second per token (bursts of 120); over it you get 429 with Retry-After.
curl https://stitchdb.com/platform/v1/projects \
-H "Authorization: Bearer $STITCHDB_TOKEN"
#Projects
| Method and path | Does |
|---|
GET /projects | Projects you can access (yours and your organizations'), with your role |
GET /projects/<ref> | Status, region, API URL, anon key and connection details; the service role key and database password only for owners and admins with a read-write token |
GET /projects/<ref>/api-keys | [{ name, api_key }] |
POST /projects, PATCH /projects/<ref>, DELETE /projects/<ref> | Create, rename / label, delete a project; also /pause, /restore, /api-keys/rotate (see Provisioning) |
GET /projects/<ref>/usage | Daily usage (?from&to) |
GET|PATCH /projects/<ref>/config/auth | Auth settings (sign-up, providers, URLs, e-mail) |
#Project settings
| Method and path | Does |
|---|
GET|PUT /projects/<ref>/network-restrictions | { allowlist: ["203.0.113.7", "198.51.100.0/24"] }: who may connect to Postgres from outside; null or [] allows every address (owners and admins) |
GET|PUT /projects/<ref>/graphql | { enabled: true } turns on GraphQL at /graphql/v1; the answer has its url |
GET|POST|DELETE /projects/<ref>/region-move | Regions it can move to, allowance and the current move; { region, when: "now" | "quiet" | ISO time } moves or schedules it (owners and admins); DELETE cancels a scheduled move. See Projects and regions |
GET|DELETE /projects/<ref>/database/query-performance | Slowest and most frequent statements (?sort=total|mean|calls|rows|io&limit=50, database:read); DELETE resets the statistics. See Query performance |
GET|PATCH /projects/<ref>/limits | Per-project caps below the plan (see Limits) |
#Organization: members and audit log
These need a dashboard session or a personal access token (not an organization or project token), and the Administrator or Owner role. <org> is the organization id from GET /organizations.
| Method and path | Does |
|---|
GET /organizations/<org>/members | [{ user_id, email, role, project_refs, created_at, last_sign_in_at }] (every member can read it) |
PATCH /organizations/<org>/members/<user_id> | { role?, project_refs? }: change a role (admin, developer, read_only) or limit to some projects |
DELETE /organizations/<org>/members/<user_id> | Remove a member |
GET|POST /organizations/<org>/invitations | Pending invitations; { email, role, project_refs? } sends one by e-mail |
DELETE /organizations/<org>/invitations/<id> | Revoke an invitation (the link stops working) |
GET /organizations/<org>/audit-log | The audit log, newest first; filters ?action&actor&project&since&until, paging with ?before= the X-Next-Cursor header, ?format=csv to download |
#Database
| Method and path | Does |
|---|
POST /projects/<ref>/database/query | { query, read_only? } → { rows, results }. Runs as the project's database role; read-only tokens always run read-only. |
GET /projects/<ref>/types/typescript?schemas=public | { types }: the TypeScript Database type |
GET /projects/<ref>/types/dart|swift|kotlin?schemas=public | { types }: Dart, Swift or Kotlin models (&package= sets the Kotlin package) |
GET /projects/<ref>/database/dump | SQL dump of your schemas (?schemas=, ?data_only=1 for rows, admins only) |
curl -X POST https://stitchdb.com/platform/v1/projects/<ref>/database/query \
-H "Authorization: Bearer $STITCHDB_TOKEN" -H 'Content-Type: application/json' \
-d '{"query":"select count(*) from public.todos","read_only":true}'
#Migrations
| Method and path | Does |
|---|
GET /projects/<ref>/migrations | Applied migrations (?include_sql=1 for their SQL) |
POST /projects/<ref>/migrations | { migrations: [{ version, name, sql }], dry_run? } → { applied, skipped, failed? }. In version order, one transaction each, stops at the first failure; 409 if an applied version has different SQL. |
POST /projects/<ref>/migrations/repair | { version, status: "applied" | "reverted", name?, sql? }: fix the history without running SQL |
#Branches, functions and secrets
See Preview branches and Deploy functions with the API.
#Dashboard features
Everything below runs the same code as the dashboard, under /projects/<ref>. The rules of the dashboard apply: your role in the project (some changes need Administrator or Owner), the plan, and turning a feature on before you use it. Read-only tokens can call the GET routes (and the ones marked changes nothing) and see what a Developer sees. Organization tokens need the scopes in the last column. Answers never contain stored keys or signing secrets. The same routes are in the management client and the CLI.
#Backups
Restores and point-in-time recovery need the Administrator or Owner role. Download links are signed and expire; they need a read-write token.
| Method and path | Does | Scopes |
|---|
GET /projects/<ref>/backups | Backups of the project, the retention of the plan and the point-in-time window | projects:read |
POST /projects/<ref>/backups | Start a manual backup now (one per hour) | projects:write |
POST /projects/<ref>/backups/<id>/restore | Restore a backup (the current state is backed up first, so the restore can be undone) | projects:write |
POST /projects/<ref>/backups/export | A signed link that streams a fresh dump of the current data | projects:write |
GET /projects/<ref>/backups/<id>/download | A signed download link of a backup (?files=1: its Storage files) | projects:write |
GET /projects/<ref>/backups/pitr | Point-in-time recovery: the window you can restore to | projects:read |
POST /projects/<ref>/backups/pitr | Restore to a point in time: { target_time, branch? }; with branch, into a new preview branch instead | projects:write |
GET /projects/<ref>/backups/jobs | Restore and backup jobs with their progress | projects:read |
GET /projects/<ref>/backups/jobs/<id> | One restore or backup job | projects:read |
POST /projects/<ref>/backups/table-restore | Restore one table or some rows to a point in time: { schema, table, mode, where?, target_time } | projects:write |
#Compute
Changing the size and restarting need the Administrator or Owner role. A larger size is billed from the prepaid balance, like in the dashboard; POST /compute/estimate shows the price first.
| Method and path | Does | Scopes |
|---|
GET /projects/<ref>/compute | Compute: whether the plan allows a dedicated size, the current server, recent servers and the locations | projects:read |
GET /projects/<ref>/compute/catalog | Compute sizes with their size_key and price (?location&kind=cloud|auction|large&need_gb) | projects:read |
POST /projects/<ref>/compute/estimate | What a compute size costs: { size_key }; changes nothing | projects:read |
POST /projects/<ref>/compute | Change the compute size: { size_key, idempotency_key? }; billed from the prepaid balance | projects:write |
POST /projects/<ref>/restart | Restart the project's Auth and REST services | projects:write |
#Replicas
Adding replicas needs the Administrator or Owner role and is billed hourly from the prepaid balance.
| Method and path | Does | Scopes |
|---|
GET /projects/<ref>/replicas | Read replicas with their connection details, price and failover state | projects:read |
POST /projects/<ref>/replicas | Add a read replica (billed hourly from the prepaid balance) | projects:write |
DELETE /projects/<ref>/replicas/<node> | Remove a read replica | projects:write |
GET /projects/<ref>/auto-replicas | Automatic read replicas: settings, running replicas and cost | projects:read |
PUT /projects/<ref>/auto-replicas | Change the automatic read replica settings | projects:write |
#Budget
Reading the budget needs billing:read as well (organization tokens). Changes need the Administrator or Owner role. The account-wide spend cap stays in the dashboard.
| Method and path | Does | Scopes |
|---|
GET /projects/<ref>/budget | Budget of the project: limits per resource, alerts and what stops at the limit | projects:read, billing:read |
PUT /projects/<ref>/budget | Set the budget | projects:write |
DELETE /projects/<ref>/budget | Remove the budget | projects:write |
POST /projects/<ref>/budget/test | Send a test budget alert | projects:write |
#Export
The list holds download links of the whole database, so it needs a read-write token. Restoring an archive into a project needs the organization owner.
| Method and path | Does | Scopes |
|---|
GET /projects/<ref>/export | Full exports and imports with their download / upload links | projects:write |
POST /projects/<ref>/export | Start a full export (database and files) | projects:write |
POST /projects/<ref>/export/import | Start a full import: returns the upload link for an export archive | projects:write |
POST /projects/<ref>/export/import/<job>/restore | Restore an uploaded export archive into this project (organization owner) | projects:write |
DELETE /projects/<ref>/export/<job> | Delete an export or import | projects:write |
#Feature flags
| Method and path | Does | Scopes |
|---|
GET /projects/<ref>/flags | Feature flags: state, flags, segments | projects:read |
POST /projects/<ref>/flags | Turn feature flags on | projects:write |
DELETE /projects/<ref>/flags | Turn feature flags off | projects:write |
POST /projects/<ref>/flags/flags | Create a flag | projects:write |
PATCH /projects/<ref>/flags/flags/<key> | Change a flag (rules, rollout, variants, enabled) | projects:write |
DELETE /projects/<ref>/flags/flags/<key> | Delete a flag | projects:write |
GET /projects/<ref>/flags/flags/<key>/stats | How often a flag was evaluated, per variant | projects:read |
POST /projects/<ref>/flags/segments | Create a segment | projects:write |
PATCH /projects/<ref>/flags/segments/<key> | Change a segment | projects:write |
DELETE /projects/<ref>/flags/segments/<key> | Delete a segment | projects:write |
GET /projects/<ref>/flags/history | Change history of flags and segments | projects:read |
POST /projects/<ref>/flags/history/<id>/restore | Restore a flag or segment from its history: { side?: "before" | "after" } | projects:write |
POST /projects/<ref>/flags/test | Evaluate the flags for a test context (changes nothing) | projects:read |
#Rate limits
| Method and path | Does | Scopes |
|---|
GET /projects/<ref>/rate-limits | Rate limit rules and recent blocks | projects:read |
PATCH /projects/<ref>/rate-limits | Change the rate limit rules | projects:write |
POST /projects/<ref>/rate-limits/sql | Install the SQL rate-limit function in the database | projects:write |
DELETE /projects/<ref>/rate-limits/sql | Remove the SQL rate-limit function | projects:write |
#Inbound webhooks
Signing secrets are write-only: you set them, but they are never returned.
| Method and path | Does | Scopes |
|---|
GET /projects/<ref>/inbound | Inbound webhooks: state and endpoints | projects:read |
POST /projects/<ref>/inbound | Turn inbound webhooks on | projects:write |
DELETE /projects/<ref>/inbound | Turn inbound webhooks off | projects:write |
POST /projects/<ref>/inbound/endpoints | Add an endpoint (provider, signing secret, target table) | projects:write |
PATCH /projects/<ref>/inbound/endpoints/<endpoint> | Change an endpoint | projects:write |
DELETE /projects/<ref>/inbound/endpoints/<endpoint> | Delete an endpoint (?events=1 also deletes its events) | projects:write |
POST /projects/<ref>/inbound/endpoints/<endpoint>/test | Send a test event to an endpoint | projects:write |
GET /projects/<ref>/inbound/events | Received events (?endpoint&status&limit&before) | projects:read |
GET /projects/<ref>/inbound/events/<id> | One event with its payload | projects:read |
POST /projects/<ref>/inbound/events/<id>/redeliver | Process an event again | projects:write |
DELETE /projects/<ref>/inbound/events/<id> | Delete an event | projects:write |
#Status page
| Method and path | Does | Scopes |
|---|
GET /projects/<ref>/status-page | Status page: state, settings, components and incidents | projects:read |
POST /projects/<ref>/status-page | Turn the status page on | projects:write |
DELETE /projects/<ref>/status-page | Turn the status page off | projects:write |
PUT /projects/<ref>/status-page/settings | Change the page (title, components, checks, notifications) | projects:write |
POST /projects/<ref>/status-page/incidents | Post an incident or scheduled maintenance | projects:write |
PATCH /projects/<ref>/status-page/incidents/<incident> | Add an update to an incident or change it | projects:write |
PATCH /projects/<ref>/status-page/incidents/<incident>/updates/<update> | Edit an incident update | projects:write |
DELETE /projects/<ref>/status-page/incidents/<incident> | Delete an incident | projects:write |
GET /projects/<ref>/status-page/subscribers | E-mail subscribers | projects:write |
DELETE /projects/<ref>/status-page/subscribers/<id> | Remove a subscriber | projects:write |
#Cron
Needs pg_cron in the project (409 otherwise).
| Method and path | Does | Scopes |
|---|
GET /projects/<ref>/cron/jobs | Scheduled jobs (pg_cron) | database:read |
GET /projects/<ref>/cron/runs | Recent runs (?jobid&limit) | database:read |
POST /projects/<ref>/cron/jobs | Schedule a job: { jobname, schedule, command, active? } | database:write |
PATCH /projects/<ref>/cron/jobs/<id> | Change a job (schedule, command, active) | database:write |
DELETE /projects/<ref>/cron/jobs/<id> | Unschedule a job | database:write |
#Queues
Needs pgmq in the project (409 otherwise).
| Method and path | Does | Scopes |
|---|
GET /projects/<ref>/queues | Queues (pgmq) with their length and age | database:read |
POST /projects/<ref>/queues | Create a queue: { name, unlogged? } | database:write |
DELETE /projects/<ref>/queues/<queue> | Delete a queue and its messages | database:write |
GET /projects/<ref>/queues/<queue>/messages | Messages of a queue, newest 100 (?archived=true for the archive) | database:read |
POST /projects/<ref>/queues/<queue>/messages | Send a message: { message, delay? } | database:write |
POST /projects/<ref>/queues/<queue>/read | Read messages (they stay invisible for vt seconds) | database:write |
POST /projects/<ref>/queues/<queue>/messages/<id>/<action> | Archive or delete a message | database:write |
#Push notifications
Answers say which credentials are on file, never the keys themselves.
| Method and path | Does | Scopes |
|---|
GET /projects/<ref>/push | Push notifications: credentials on file (never the keys), devices, recent messages | projects:read |
PATCH /projects/<ref>/push | Set the APNs (.p8) or FCM credentials: { ios: { p8, key_id, team_id, bundle_id, production } | null, android: { service_account } | null } | projects:write |
POST /projects/<ref>/push/test | Send a test notification to a user: { user_id, title?, body? } | projects:write |
DELETE /projects/<ref>/push | Turn push notifications off and remove the credentials | projects:write |
#In-app purchases
Answers say which store credentials are on file, never the keys. Webhook signing secrets are only shown in the dashboard.
| Method and path | Does | Scopes |
|---|
GET /projects/<ref>/purchases | In-app purchases: store credentials on file (never the keys), products, webhooks, deliveries | projects:read |
PATCH /projects/<ref>/purchases | Set the App Store / Google Play credentials, products and webhooks | projects:write |
POST /projects/<ref>/purchases/webhooks/<webhook>/test | Send a test event to a purchase webhook | projects:write |
POST /projects/<ref>/purchases/deliveries/<id>/retry | Deliver a failed purchase webhook again | projects:write |
DELETE /projects/<ref>/purchases | Turn in-app purchases off and remove the credentials | projects:write |
#Deep links
| Method and path | Does | Scopes |
|---|
GET /projects/<ref>/links | Deep links and short links: state and settings | projects:read |
POST /projects/<ref>/links | Turn links on | projects:write |
DELETE /projects/<ref>/links | Turn links off | projects:write |
PUT /projects/<ref>/links/settings | Change the settings (apps, app stores, fallback, domain) | projects:write |
GET /projects/<ref>/links/items | Short links (?q&limit&offset) | projects:read |
POST /projects/<ref>/links/items | Create a short link | projects:write |
GET /projects/<ref>/links/items/<code> | One link with its click statistics (?days) | projects:read |
PATCH /projects/<ref>/links/items/<code> | Change a link | projects:write |
DELETE /projects/<ref>/links/items/<code> | Delete a link | projects:write |
#Metering
| Method and path | Does | Scopes |
|---|
GET /projects/<ref>/metering | Usage metering: state, meters, alerts and the Stripe push (the Stripe key masked) | projects:read, usage:read |
POST /projects/<ref>/metering | Turn usage metering on | projects:write |
DELETE /projects/<ref>/metering | Turn usage metering off | projects:write |
PUT /projects/<ref>/metering/settings | Change meters, plans and alerts | projects:write |
PUT /projects/<ref>/metering/stripe | Set the Stripe push (secret key, meters) | projects:write |
GET /projects/<ref>/metering/stripe/customers | End customers and their Stripe customer ids | projects:read, usage:read |
PUT /projects/<ref>/metering/stripe/customers | Set Stripe customer ids of end customers | projects:write |
POST /projects/<ref>/metering/stripe/retry | Push failed usage to Stripe again | projects:write |
GET /projects/<ref>/metering/customers | Usage per end customer (?from&to&meter&q&limit) | projects:read, usage:read |
GET /projects/<ref>/metering/customers/<customer> | Daily usage of one end customer | projects:read, usage:read |
GET /projects/<ref>/metering/export | Usage as CSV (?from&to&meter) | projects:read, usage:read |
#Job monitoring
| Method and path | Does | Scopes |
|---|
GET /projects/<ref>/heartbeat | Job monitoring: state, alert settings and monitors | projects:read |
POST /projects/<ref>/heartbeat | Turn job monitoring on | projects:write |
DELETE /projects/<ref>/heartbeat | Turn job monitoring off | projects:write |
PUT /projects/<ref>/heartbeat/settings | Change the alert settings (e-mail, webhook, Slack) | projects:write |
POST /projects/<ref>/heartbeat/monitors | Add a monitor: { name, kind: "ping" | "cron" | "job", schedule | period_s, grace_s, target? } | projects:write |
GET /projects/<ref>/heartbeat/monitors/<monitor> | One monitor with its recent pings (?limit) | projects:read |
PATCH /projects/<ref>/heartbeat/monitors/<monitor> | Change a monitor | projects:write |
DELETE /projects/<ref>/heartbeat/monitors/<monitor> | Delete a monitor | projects:write |
POST /projects/<ref>/heartbeat/monitors/<monitor>/token | A new ping URL for a monitor (the old one stops working) | projects:write |
POST /projects/<ref>/heartbeat/test | Send a test alert | projects:write |
#Crash reporting
| Method and path | Does | Scopes |
|---|
GET /projects/<ref>/crashes | Crash reporting: state and alert settings | projects:read |
POST /projects/<ref>/crashes | Turn crash reporting on | projects:write |
DELETE /projects/<ref>/crashes | Turn crash reporting off | projects:write |
PUT /projects/<ref>/crashes/settings | Change the alert settings (new issue, regression, spike; e-mail, webhook, Slack) | projects:write |
POST /projects/<ref>/crashes/test | Send a test alert | projects:write |
GET /projects/<ref>/crashes/issues | Issues (?status&release&q&limit&offset) | projects:read |
GET /projects/<ref>/crashes/issues/<issue> | One issue with its latest events | projects:read |
PATCH /projects/<ref>/crashes/issues/<issue> | Resolve, ignore or reopen an issue: { status: "open" | "resolved" | "ignored" } | projects:write |
#Auth
Also see GET|PATCH /config/auth above. SSO providers need the Administrator or Owner role and auth:write.
| Method and path | Does | Scopes |
|---|
GET /projects/<ref>/config/auth/sso/providers | SAML SSO providers | auth:write |
POST /projects/<ref>/config/auth/sso/providers | Add a SAML SSO provider: { metadata_url | metadata_xml, domains, attribute_mapping? } | auth:write |
PUT /projects/<ref>/config/auth/sso/providers/<uuid> | Change a SAML SSO provider | auth:write |
DELETE /projects/<ref>/config/auth/sso/providers/<uuid> | Remove a SAML SSO provider | auth:write |
#Recycle bin
| Method and path | Does | Scopes |
|---|
GET /projects/<ref>/recycle-bin | Deleted rows kept by the recycle bin (?table&limit) and the tables it covers | database:read |
PUT /projects/<ref>/recycle-bin/tables | Turn the recycle bin on or off for a table: { schema?, table, enabled } | database:write |
POST /projects/<ref>/recycle-bin/restore | Restore deleted rows: { ids } | database:write |
POST /projects/<ref>/recycle-bin/purge | Delete rows from the bin for good: { ids } | database:write |
#Change history
| Method and path | Does | Scopes |
|---|
GET /projects/<ref>/history | Row changes (?table&pk&limit&before) and the tables that keep a history | database:read |
PUT /projects/<ref>/history/tables | Turn the change history on or off for a table: { schema?, table, enabled } | database:write |
POST /projects/<ref>/history/revert | Revert one change: { id } | database:write |
#Shared views
| Method and path | Does | Scopes |
|---|
GET /projects/<ref>/shared-views | Shared table views (read-only links for people without dashboard access) | projects:read |
POST /projects/<ref>/shared-views | Create a shared view: { name, schema, table, columns, filters } | projects:write |
GET /projects/<ref>/shared-views/<view> | One shared view with its members | projects:read |
PATCH /projects/<ref>/shared-views/<view> | Change a shared view | projects:write |
DELETE /projects/<ref>/shared-views/<view> | Delete a shared view | projects:write |
POST /projects/<ref>/shared-views/<view>/members | Give people access by e-mail: { emails } | projects:write |
DELETE /projects/<ref>/shared-views/<view>/members | Remove a person (?email) | projects:write |
GET /projects/<ref>/shared-views/<view>/audit | Who opened the view and when | projects:read |
#Errors
Errors are JSON: { "error": "message" } with the HTTP status (400 invalid input or SQL error with code/detail/hint, 401 missing or invalid token, 403 not allowed, 404 not found or no access, 409 conflict, 429 rate limited).