snoozestackdocs

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.

Why use it

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 dev against 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.

terminal
snoozestack user login # approve the code in the browser tab it opens
TOKEN=$(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:

provision.sh
set -euo pipefail
API=https://snoozestack.com/api
AUTH="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/null
do 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#

EndpointMethodsPurpose
/api/projectsGET, POSTList / create projects
/api/projects/<ref>GET, DELETEProject detail (incl. keys) / delete
/api/projects/<ref>/pausePOSTStop the project: runtime removed, API and sites answer paused (owner only)
/api/projects/<ref>/resumePOSTStart it again, if the plan has a free slot
/api/projects/<ref>/schemaGET, POSTThe project's current schema.json / upload a new one (what snoozestack publish sends)
/api/projects/<ref>/runtime/stateGETWhat the running runtime holds: tables, functions, queues, sites — the console's read path
/api/projects/<ref>/runtime/table/<name>GETOne runtime table's rows, paged
/api/projects/<ref>/schema/liveGETThe 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-impactGET?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-impactGET?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>/releasesGET, POSTReleases / record one from a package manifest and deploy it to production (what snoozestack publish does last)
/api/projects/<ref>/releases/<n>GETOne release in full: manifest, checksums, schema plan, drops, diff, deployments
/api/projects/<ref>/releases/<n>/deployPOSTDeploy a recorded release again (publish --release) — a rollback when it is older than the live one
/api/projects/<ref>/deploymentsGETEvery publish and rollback, with actor, evidence and outcome
/api/projects/<ref>/previewGET, POST, DELETEThe 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/outboxGETMail your preview's runtime tried to send — captured, never delivered
/api/projects/<ref>/previewsGETEveryone's previews of the project, with owner, URL, state and expiry
/api/projects/<ref>/previews/<name>GET, DELETEOne preview's status (probing it if still building) / clean it up now
/api/projects/<ref>/previews/<name>/outboxGETMail the preview's runtime tried to send — captured, never delivered

Functions, schedules & secrets#

EndpointMethodsPurpose
/api/projects/<ref>/runtime/publishPOSTUpload 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>/functionsGETThe 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, DELETERead source / redeploy (merges files, preserves auth + MCP flags) / delete
/api/projects/<ref>/schedulesGET, POST, PATCH, DELETECron schedules for functions — list / create / update / delete
/api/projects/<ref>/schedules/runPOSTRun a schedule immediately
/api/projects/<ref>/secretsGET, POST, DELETEFunction secrets (applied live)

Auth#

EndpointMethodsPurpose
/api/projects/<ref>/auth/usersGET, PATCH, DELETEList users / ban-unban / delete — no POST: accounts exist only because someone signed up
/api/projects/<ref>/auth/users/sendPOSTSend 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/configGET, PUTSite URL + additional redirect URLs
/api/projects/<ref>/auth/providersPOST, DELETEEnable / disable Google and Apple sign-in
/api/projects/<ref>/auth/providers/apple-secretPOSTSign an Apple client secret from the stored .p8 — returns it, saves nothing
/api/projects/<ref>/auth/emailsGET, PUTEmail template subjects and HTML bodies
/api/projects/<ref>/auth/reset-configGET, PUTWhere the hosted password page hands off to instead of rendering its form
/api/projects/<ref>/auth/reset-pageGET, PUTHosted password page HTML

Storage & queues#

EndpointMethodsPurpose
/api/projects/<ref>/storageGET, POST, DELETEBrowse / upload / delete objects
/api/projects/<ref>/storage/bucketsGET, POST, PATCH, DELETEList / create / toggle public-private / delete buckets
/api/projects/<ref>/storage/signGETMint a signed URL for a private object
/api/projects/<ref>/queuesGET, POST, DELETEList (with message counts) / create / delete queues
/api/projects/<ref>/queues/<name>/messagesPOSTEnqueue a message
/api/projects/<ref>/queues/triggersGET, POST, PATCH, DELETEQueue triggers — list / create / update (functions, enabled) / delete
/api/projects/<ref>/queues/webhooksGET, POST, DELETEQueue webhooks (public inbound URL → queue) — list / create / delete

Web & domains#

EndpointMethodsPurpose
/api/projects/<ref>/sitesGETList published static sites
/api/projects/<ref>/sites/<site>GET, POST, DELETESite manifest (paths + ETags) / upload a file / prune paths or delete the site
/api/projects/<ref>/sites/<site>/publishPOSTTurn staged uploads into a new, previewable version — not live until promoted
/api/projects/<ref>/sites/<site>/promotePOSTMake a version live and flush the edge cache — also how to roll back
/api/projects/<ref>/sites/<site>/versionsGETVersion history for a site
/api/projects/<ref>/domainsGET, POST, DELETEList / connect / disconnect a domain
/api/projects/<ref>/domains/<domain>/recordsGET, POST, DELETEList / add / delete DNS records
/api/projects/<ref>/distributionsGET, POST, DELETEAttach / detach a custom domain to a site or the project API

Monitoring#

EndpointMethodsPurpose
/api/projects/<ref>/services/logs?service=…GETThe 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>/auditGETThe project's change history — console, CLI, MCP and service tokens — newest first, filterable by area and actor
/api/projects/<ref>/observability[?section=…]GETResources overview, or per-product detail (database, auth, storage, functions, queues, sites)
/api/projects/<ref>/signals?range=…GETSignals overview aggregates
/api/projects/<ref>/signals/eventsGETRaw event feed, newest first, paginated
/api/projects/<ref>/signals/usersGETUser profiles derived from events
/api/projects/<ref>/signals/metaGETEvent names / property keys / top property values in a range

Organization#

EndpointMethodsPurpose
/api/orgGET, PATCHOrganization detail / rename
/api/org/membersGET, POST, DELETEAdmin accounts — list / invite / remove
/api/org/auditGETThe organization-wide change history
/api/projects/<ref>/mcp-tokensGET, POSTMCP access tokens — list / create (DELETE on /<id>, POST /<id>/rotate)
/api/projects/<ref>/service-tokensGET, POSTProject 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.