Management API
Everything the CLI and portal UI do goes through the portal's own HTTP API — there is no private back channel. Anything you can click, you can script.
This page is for your own tooling. If the caller is an AI client, use the MCP endpoint instead: it's these same operations exposed as MCP tools — with argument schemas, a project-scoped token you can rotate, and the docs served alongside them — rather than endpoints a model has to guess its way around.
This is the control plane, and it's a different axis from the project API your app talks to. /api/auth, /api/functions/v1, /api/storage/v1 and friends are what an app calls at runtime — none of them reach a table directly, a function has to sit in front; the management API instead creates and configures the projects themselves. Keep the two straight and the security model falls out naturally: app code holds a public project key and can never provision infrastructure, while a management token can provision anything and therefore never belongs in an app.
Both of a project's keys sit on the app axis, the service key included. It exists so your own server can call this project's API — enqueueing to a queue, say — and nothing more; it is not an admin credential, and no key of any kind reads a table. Anything administrative, reading rows with snoozestack data included, is this API with your login or a project token from snoozestack projects tokens create.
Reach for it whenever a human clicking the portal is the bottleneck — when project setup has to be reproducible, or when the thing that needs to act isn't a person.
- Provision a project per customer
- A B2B product that gives every tenant an isolated database: create the project, publish its schema, and read back the keys, all from your signup flow, instead of clicking through the portal for each new account.
- Ephemeral environments in CI
- Spin up a throwaway project for a pull request, run the test suite against a real database and real functions rather than mocks, and delete it when the branch merges. (For most CI,
snoozestack devagainst the checkout is even simpler — no hosted project needed at all.) - Infrastructure as code
- Keep secrets, scheduled functions, and DNS records in a script under version control, so a rebuilt project is identical to the one it replaced.
- Internal admin tooling
- Build your own support console — look up a user, ban an account, re-run a schedule — without giving support staff portal logins.
Authenticating#
Sign the CLI in once — snoozestack user login opens your browser, and works for an account that signs in with Google as well as one with a password — then snoozestack user token prints the bearer token it stored in ~/.snoozestack/config.json. Treat it like a root credential: it can read every key and delete every project in the organization.
snoozestack user login # approve the code in the browser tab it opensTOKEN=$(snoozestack user token) curl -s https://snoozestack.com/api/projects -H "Authorization: Bearer $TOKEN"A machine with no browser and no CLI can exchange an email and password for the same token at /api/auth/cli-token (POST {"email", "password"}) — for a password account only. For anything unattended, prefer a project token (snoozestack projects tokens create): it is scoped to one project and revocable from anywhere.
A worked example — provision a project, wait for it, apply a schema, and print the keys an app would need:
set -euo pipefailAPI=https://snoozestack.com/apiAUTH="Authorization: Bearer $TOKEN" # 1. Create the project — the response is the project row, incl. its keys.REF=$(curl -s -X POST "$API/projects" \ -H "$AUTH" -H 'Content-Type: application/json' \ -d '{"name": "tenant-acme"}' | jq -r .slug) # 2. Wait for the project's runtime to come up: runtime/state is 404 until# the starter publish that creation kicks off has a container answering.until curl -sf "$API/projects/$REF/runtime/state" -H "$AUTH" >/dev/nulldo sleep 3; done # 3. Apply the schema: the schema.json that "snoozestack schema build" writes# from schema.mjs, published as the project's new schema version.curl -s -X POST "$API/projects/$REF/schema" \ -H "$AUTH" -H 'Content-Type: application/json' \ -d "{"schemaJson": $(jq -Rs . < snoozestack/schema.json)}" # 4. Hand the app its credentials. There is no "url" field — a project is# always served at https://<slug>.snzzz.com.ANON=$(curl -s "$API/projects/$REF" -H "$AUTH" | jq -r .anon_key)echo "SNOOZESTACK_URL=https://$REF.snzzz.com/api"echo "SNOOZESTACK_ANON_KEY=$ANON"Projects & schema#
| Endpoint | Methods | Purpose |
|---|---|---|
/api/projects | GET, POST | List / create projects |
/api/projects/<ref> | GET, DELETE | Project detail (incl. keys) / delete |
/api/projects/<ref>/pause | POST | Stop the project: runtime removed, API and sites answer paused (owner only) |
/api/projects/<ref>/resume | POST | Start it again, if the plan has a free slot |
/api/projects/<ref>/schema | GET, POST | The project's current schema.json / upload a new one (what snoozestack publish sends) |
/api/projects/<ref>/runtime/state | GET | What the running runtime holds: tables, functions, queues, sites — the console's read path |
/api/projects/<ref>/runtime/table/<name> | GET | One runtime table's rows, paged |
/api/projects/<ref>/schema/live | GET | The schema production's database records as applied — what publish plans a release's drops against ({ schemaJson }, null before production has any) |
/api/projects/<ref>/schema/drop-impact | GET | ?drop=<table> / ?drop=<table>.<column>, repeated: rows per table and non-null values per column in production — what publish shows before a release drops data |
/api/projects/<ref>/schema/rebuild-impact | GET | ?checks=<json array>: rows each rebuilt table keeps, values under a changed type, and the rows that would stop a rebuild (NULLs under a new NOT NULL, duplicates under a new unique key, orphans under a new foreign key) — counted in production before publish uploads anything |
/api/projects/<ref>/releases | GET, POST | Releases / record one from a package manifest and deploy it to production (what snoozestack publish does last) |
/api/projects/<ref>/releases/<n> | GET | One release in full: manifest, checksums, schema plan, drops, diff, deployments |
/api/projects/<ref>/releases/<n>/deploy | POST | Deploy a recorded release again (publish --release) — a rollback when it is older than the live one |
/api/projects/<ref>/deployments | GET | Every publish and rollback, with actor, evidence and outcome |
/api/projects/<ref>/preview | GET, POST, DELETE | The signed-in account's own preview: its name and status / deploy a package manifest to it (what snoozestack preview does last) / clean it up |
/api/projects/<ref>/preview/outbox | GET | Mail your preview's runtime tried to send — captured, never delivered |
/api/projects/<ref>/previews | GET | Everyone's previews of the project, with owner, URL, state and expiry |
/api/projects/<ref>/previews/<name> | GET, DELETE | One preview's status (probing it if still building) / clean it up now |
/api/projects/<ref>/previews/<name>/outbox | GET | Mail the preview's runtime tried to send — captured, never delivered |
Functions, schedules & secrets#
| Endpoint | Methods | Purpose |
|---|---|---|
/api/projects/<ref>/runtime/publish | POST | Upload the whole snoozestack/ tree as a runtime version: dark for the live namespace (a release names it, its deploy activates it), live for a preview namespace |
/api/projects/<ref>/functions | GET | The per-function store's listing, kept for the console's MCP page; what is live is runtime/state |
/api/projects/<ref>/functions/<name> | GET, PUT, DELETE | Read source / redeploy (merges files, preserves auth + MCP flags) / delete |
/api/projects/<ref>/schedules | GET, POST, PATCH, DELETE | Cron schedules for functions — list / create / update / delete |
/api/projects/<ref>/schedules/run | POST | Run a schedule immediately |
/api/projects/<ref>/secrets | GET, POST, DELETE | Function secrets (applied live) |
Auth#
| Endpoint | Methods | Purpose |
|---|---|---|
/api/projects/<ref>/auth/users | GET, PATCH, DELETE | List users / ban-unban / delete — no POST: accounts exist only because someone signed up |
/api/projects/<ref>/auth/users/send | POST | Send the sign-in link to an existing user: { type: "recovery", email } — it doubles as password reset. "invite" and "confirmation" answer 409: application identity has no such flows |
/api/projects/<ref>/auth/config | GET, PUT | Site URL + additional redirect URLs |
/api/projects/<ref>/auth/providers | POST, DELETE | Enable / disable Google and Apple sign-in |
/api/projects/<ref>/auth/providers/apple-secret | POST | Sign an Apple client secret from the stored .p8 — returns it, saves nothing |
/api/projects/<ref>/auth/emails | GET, PUT | Email template subjects and HTML bodies |
/api/projects/<ref>/auth/reset-config | GET, PUT | Where the hosted password page hands off to instead of rendering its form |
/api/projects/<ref>/auth/reset-page | GET, PUT | Hosted password page HTML |
Storage & queues#
| Endpoint | Methods | Purpose |
|---|---|---|
/api/projects/<ref>/storage | GET, POST, DELETE | Browse / upload / delete objects |
/api/projects/<ref>/storage/buckets | GET, POST, PATCH, DELETE | List / create / toggle public-private / delete buckets |
/api/projects/<ref>/storage/sign | GET | Mint a signed URL for a private object |
/api/projects/<ref>/queues | GET, POST, DELETE | List (with message counts) / create / delete queues |
/api/projects/<ref>/queues/<name>/messages | POST | Enqueue a message |
/api/projects/<ref>/queues/triggers | GET, POST, PATCH, DELETE | Queue triggers — list / create / update (functions, enabled) / delete |
/api/projects/<ref>/queues/webhooks | GET, POST, DELETE | Queue webhooks (public inbound URL → queue) — list / create / delete |
Web & domains#
| Endpoint | Methods | Purpose |
|---|---|---|
/api/projects/<ref>/sites | GET | List published static sites |
/api/projects/<ref>/sites/<site> | GET, POST, DELETE | Site manifest (paths + ETags) / upload a file / prune paths or delete the site |
/api/projects/<ref>/sites/<site>/publish | POST | Turn staged uploads into a new, previewable version — not live until promoted |
/api/projects/<ref>/sites/<site>/promote | POST | Make a version live and flush the edge cache — also how to roll back |
/api/projects/<ref>/sites/<site>/versions | GET | Version history for a site |
/api/projects/<ref>/domains | GET, POST, DELETE | List / connect / disconnect a domain |
/api/projects/<ref>/domains/<domain>/records | GET, POST, DELETE | List / add / delete DNS records |
/api/projects/<ref>/distributions | GET, POST, DELETE | Attach / detach a custom domain to a site or the project API |
Monitoring#
| Endpoint | Methods | Purpose |
|---|---|---|
/api/projects/<ref>/services/logs?service=… | GET | The runtime's log (service=runtime; auth, storage and functions are aliases for it), or the portal-side queue and website activity (queues, sites) |
/api/projects/<ref>/audit | GET | The project's change history — console, CLI, MCP and service tokens — newest first, filterable by area and actor |
/api/projects/<ref>/observability[?section=…] | GET | Resources overview, or per-product detail (database, auth, storage, functions, queues, sites) |
/api/projects/<ref>/signals?range=… | GET | Signals overview aggregates |
/api/projects/<ref>/signals/events | GET | Raw event feed, newest first, paginated |
/api/projects/<ref>/signals/users | GET | User profiles derived from events |
/api/projects/<ref>/signals/meta | GET | Event names / property keys / top property values in a range |
Organization#
| Endpoint | Methods | Purpose |
|---|---|---|
/api/org | GET, PATCH | Organization detail / rename |
/api/org/members | GET, POST, DELETE | Admin accounts — list / invite / remove |
/api/org/audit | GET | The organization-wide change history |
/api/projects/<ref>/mcp-tokens | GET, POST | MCP access tokens — list / create (DELETE on /<id>, POST /<id>/rotate) |
/api/projects/<ref>/service-tokens | GET, POST | Project tokens for CI — list / create (DELETE on /<id>, POST /<id>/rotate) |
Responses are JSON; failures carry a non-2xx status and an { "error": "…" } body. See the CLI reference for the commands that wrap the most common of these calls.