Base URL and app selection
Send each call to a base URL with a /v1/... path. Use your app's host, such as https://my-app.substrio.com, or https://mcp.substrio.com. Select an app in one of two ways:
- By host.
https://<app>.substrio.comor the app's custom domain selects that app. - By header.
X-Substrio-Tenant: <app>selects the app on a host that does not carry its name, such asmcp.substrio.comwith an account key.
An app key is bound to its app. A call using it needs neither the header nor a matching host.
curl -s $SUBSTRIO_URL/v1/notes -H "Authorization: Bearer $SUBSTRIO_KEY"
curl -s $SUBSTRIO_URL/v1/notes -H "Authorization: Bearer $SUBSTRIO_KEY" -H "X-Substrio-Tenant: acme"
Authentication
Send a key as Authorization: Bearer <key>.
| Key kind | Scope |
|---|---|
| Account key | Create and list apps and account members for its one account; administer a named app with X-Substrio-Tenant. |
| App key | Its one app's data, functions, files and settings. No header or host needed. |
GET /v1/_whoami returns the key's kind, account id, app, and scopes, so you can check which key a request used.
curl -s $SUBSTRIO_URL/v1/_whoami -H "Authorization: Bearer $SUBSTRIO_KEY"
# {"key":"tenant","account_id":1,"tenant":"demo","tenant_id":2,"scopes":["tenant_admin"]}
Request bodies
A JSON body is the resource itself, with no wrapper: an insert's body is the document, a collection create's body is {"name": "..."}. Send content-type: application/json.
curl -s -X POST $SUBSTRIO_URL/v1/notes -H "Authorization: Bearer $SUBSTRIO_KEY" \
-H 'content-type: application/json' -d '{"title":"hello","n":1}'
# {"_id":"Qs7HRQnMTg","status":"created"}
Idempotency
Send Idempotency-Key: <your-key> on a mutation you may need to retry after a timeout or dropped connection. A retry with the same key against the same operation returns the first attempt's result rather than writing twice. Choose a key unique to the logical write, such as an order id or job id, and reuse it for retries.
Paging
A list operation takes limit and cursor and returns next_cursor. It is a string when more rows follow and null or absent on the last page. To continue, pass the previous response's next_cursor as cursor. Do not construct a cursor yourself.
curl -s "$SUBSTRIO_URL/v1/_collections?limit=50" -H "Authorization: Bearer $SUBSTRIO_KEY"
# {"collections":[...],"next_cursor":"notes"}
curl -s "$SUBSTRIO_URL/v1/_collections?limit=50&cursor=notes" -H "Authorization: Bearer $SUBSTRIO_KEY"
# {"collections":[...],"next_cursor":null}
WebSocket paths
/v1/query/ws streams query frames, /v1/realtime serves realtime subscriptions, /v1/kv/ws serves KV streaming and /v1/_logs/ws streams function logs. Each frame is parsed into a typed operation; the authenticated app and database are selected at upgrade.
Errors
A failed call returns a JSON error envelope with a stable code, HTTP status, retryable, and a next_action hint. See Errors. The typed request and result shared by each transport are described in API contracts.
Reference
Every operation's route, method, arguments and result are in the generated reference, by area: /docs/reference/functions/, /docs/reference/deploy/, /docs/reference/data/, /docs/reference/query/, /docs/reference/schema/, /docs/reference/schedule/, /docs/reference/files/, /docs/reference/config/, /docs/reference/access/, /docs/reference/realtime/, /docs/reference/observability/, /docs/reference/backup/, /docs/reference/ai/, /docs/reference/account/ and /docs/reference/platform/. The runtime's own globals and types (db, event, Response) are at /docs/runtime/api/.