HTTP API

Call any operation over plain HTTP: pick an app by host or header, send a bearer key, and get typed JSON back.

Docs menu

Base URL and app selection

Every call goes to a base URL with a /v1/... path: your app's host, such as https://my-app.substrio.com, or https://mcp.substrio.com. An app is named one of two ways:

  • By host. https://<app>.substrio.com or 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 as mcp.substrio.com with an account key.

An app key is bound to its app: a call with one 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 answers 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 (a client timeout, a dropped connection). A retried request with the same key against the same operation answers the first attempt's result again instead of writing twice. Choose a key that is unique to the one logical write (an order id, a job id), not to the HTTP request.

Paging

A list operation takes limit and cursor, and answers next_cursor: a string while more rows follow, null (or absent) on the last page. Pass the previous answer's next_cursor back as cursor to continue; do not construct a cursor value 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 answers a JSON error envelope with a stable code, an HTTP status, retryable and a next_action hint: see Errors. The typed request and result every transport shares, including this one, 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/.