Deploy operations

Ship the app: push a version, check it, try it in a sandbox, make it live, roll back.

Docs menu

app

app.deploy

Ship files in one call: commit the units and removals (as version.commit takes them), check the version's functions (unless check is false), make it live where to names (live, or a sandbox), test it there with app.test (unless test is false), and, with promote and a sandbox in to, make it live on the app once the test is green. Stops at the first step that fails: a refused commit, check or live answers that step's own error with stage; a failed test answers ok false, stage test and the test's failures with their fixes, and promotes nothing. Answers ok, stage, deployed {commit, live}, test and promote, each the answer of that step's own tool. Over HTTP it runs the commit, the check and live; test and promote run in the MCP tool.

Route
POST /v1/_app/deploy
Auth
App key tenant
MCP tool
substrio_app_deploy
CLI
substrio op app.deploy

Parameters

NameInTypeRequiredDescription
messagebodystringYesWhat this commit did.
unitsbodyarray of objectNoThe units this commit writes, as version.commit takes them.
removalsbodyarray of stringNoThe paths this commit removes.
branchbodystringNoThe branch to commit on (default: main).
modebody"changes" | "snapshot"Nochanges applies units and removals to the parent version (default); snapshot makes the units the whole content.
expectedbodystringNoThe version the branch must still point at (64 hex, or an empty string for a branch with no version yet). 409 when it moved: nothing is written.
checks_greenbodybooleanNotrue says the branch's required checks are green, which a protected branch needs.
tobodystringYesWhere the version goes live: live for the app, or a sandbox name from sandbox.list.
checkbodybooleanNofalse skips function.check over the version's functions before it goes live. Default true.
testbodybooleanNotrue runs app.test on where the version went live, with its defaults; a failure stops the deploy there. Default true.
promotebodybooleanNoWith a sandbox in to: once the test is green, make what the sandbox runs live on the app (live.set from the sandbox). Default false.
backupbodybooleanNofalse skips the data backup a version going live on the app takes first. Default true.
directbody"refuse" | "replace" | "keep"NoAs live.set: what to do with a function deployed outside a version that this would overwrite. Default "refuse".

Response

FieldTypePresentDescription
okbooleanAlwaystrue when every step asked for passed.
stage"done" | "test" | "promote"Alwaysdone, or the step that stopped the deploy (a refused commit, check or live answers its own error, stage commit, check or live).
deployedobjectAlways
testobject or nullAlwaysapp.test's answer; null when test was false.
promoteobject or nullAlwayslive.set's answer on the app (its url the app's address); null when promote was not asked or the test failed.

Errors

A failed call answers the error envelope with a typed code.

Example

curl -X POST "$SUBSTRIO_URL/v1/_app/deploy" \
  -H "Authorization: Bearer $SUBSTRIO_KEY" \
  -H "Content-Type: application/json" \
  -d '{"message":"message","to":"to"}'

app.diagnose

What is wrong with the app (or a sandbox) and how to fix it, in one call: which version each environment runs against main's head, function.check over the version that runs where the call looks (its diagnostics), its newest function errors, and app.test of its website and GET routes, each finding with its fix. Answers ok, sandbox, live {main, environments}, check, errors {recent, fix}, test and fixes, every fix in order. Read only; the MCP server runs it.

Route
POST /v1/_app/diagnose
Auth
App key tenant
MCP tool
substrio_app_diagnose
CLI
substrio op app.diagnose

Parameters

NameInTypeRequiredDescription
sandboxbodystringNoA sandbox name from sandbox.list: look at what it runs instead of the app.

Response

FieldTypePresentDescription
okbooleanAlwayssomething is live where the call looks, its functions pass function.check and app.test passed.
sandboxstring or nullAlways
liveobjectAlways
checkobjectAlways
errorsobjectAlways
testobject or nullAlwaysapp.test's answer; null when nothing runs there.
fixesarray of stringAlwaysevery finding's fix, in order; empty when ok.

Errors

A failed call answers the error envelope with a typed code.

Example

curl -X POST "$SUBSTRIO_URL/v1/_app/diagnose" \
  -H "Authorization: Bearer $SUBSTRIO_KEY"

app.scaffold

Start an app from a template compiled into the release: commits the app's first version on main, one snapshot of the template's units, each of which passes app.test. site is a page with its stylesheet and script; site-api adds a function route (GET /api/hello) the page calls; site-data-auth is a notes page anyone reads and a signed-in person adds to (GET /api/notes, POST /api/notes auth, GET /api/me auth). Refused with 409 when main already holds a version: change an app that has one with version.commit or app.deploy. Answers version.commit's answer and template; make it live with live.set (with sandbox to try it first).

Route
POST /v1/_app/scaffold
Auth
App key tenant
MCP tool
substrio_app_scaffold
CLI
substrio op app.scaffold

Parameters

NameInTypeRequiredDescription
templatebody"site" | "site-api" | "site-data-auth"Yessite: a page, its stylesheet and script; site-api: that and a function route, GET /api/hello, the page calls; site-data-auth: a notes page anyone reads, a signed-in person adds to (GET /api/notes, POST /api/notes auth, GET /api/me auth).
messagebodystringNoThe commit's message (default: app.scaffold: and the template).

Response

FieldTypePresentDescription
branchstringAlways
versionstringAlwaysthe version's id (64 hex).
rootstringWhen set
numberintegerAlwaysthe version number, promotable at once with live.set (with sandbox to run it there first).
generationintegerWhen set
blobs_writtenintegerWhen set
trees_writtenintegerWhen set
template"site" | "site-api" | "site-data-auth"Always

Errors

A failed call answers the error envelope with a typed code.

Example

curl -X POST "$SUBSTRIO_URL/v1/_app/scaffold" \
  -H "Authorization: Bearer $SUBSTRIO_KEY" \
  -H "Content-Type: application/json" \
  -d '{"template":"site"}'

app.test

Test the app's website (or a sandbox's) as a browser loads it, in one call: each page of paths (default /) and every same-site page it links, every stylesheet, script, image, icon and CSS url() or @import they name, and every GET function route with no parameter, each fetched in process as route.call does, as a visitor with no credentials. Each is checked for its status, its content type (a stylesheet must be text/css, a script JavaScript, an image image/*, never the site's page in their place) and its size. Answers ok, the table of every resource (path, kind, from, status, type, bytes, ok) and each failure with its problem and its fix. References to another origin are counted, never fetched.

Route
POST /v1/_app/test
Auth
App key tenant
MCP tool
substrio_app_test
CLI
substrio op app.test

Parameters

NameInTypeRequiredDescription
sandboxbodystringNoA sandbox name from sandbox.list: test what it runs instead of the app.
pathsbodyarray of stringNoThe pages to start from (default ["/"]); every same-site <a href> page they link is tested too, up to max_pages.
routesbodybooleanNotrue also calls every GET function route that has no parameter, as a visitor with no credentials, and fails one answering 500 or above. Default true.
max_pagesbodyintegerNoPages fetched at most, paths and links together. Minimum 1. Maximum 1000. Default 20.
max_fetchesbodyintegerNoRequests made at most; a run that stops there answers truncated: true. Minimum 1. Maximum 5000. Default 200.

Response

FieldTypePresentDescription
okbooleanAlwaystrue when no resource failed.
sandboxstring or nullAlways
pagesintegerAlways
checkedintegerAlwaysrequests made.
failedintegerAlways
externalintegerAlwaysreferences to another origin, not fetched.
skipped_routesintegerAlwaysfunction routes with a parameter, a * or a method other than GET, not called.
truncatedbooleanAlwaysmax_pages or max_fetches stopped the run.
resourcesarray of objectAlways
failuresarray of objectAlways

Errors

A failed call answers the error envelope with a typed code.

Example

curl -X POST "$SUBSTRIO_URL/v1/_app/test" \
  -H "Authorization: Bearer $SUBSTRIO_KEY"

env

env.host.list

List the app's hosts, each with its environment and the version it runs, and the enabled root domains a host may be bound under.

Route
GET /v1/_env_hosts
Auth
App key tenant
MCP tool
substrio_env_host_list
CLI
substrio op env.host.list

Parameters

No parameters.

Response

FieldTypePresentDescription
hostsarray of objectAlways
rootsarray of stringAlwaysthe enabled root domains a host may be bound under.

Errors

A failed call answers the error envelope with a typed code.

Example

curl "$SUBSTRIO_URL/v1/_env_hosts" \
  -H "Authorization: Bearer $SUBSTRIO_KEY"

env.host.remove

Remove one of the app's hosts: it answers nothing from then on and its label is free. ENV_HOST_NOT_FOUND when the app holds no such host. Answers 204.

Route
DELETE /v1/_env_hosts/{host}
Auth
App key tenant
MCP tool
substrio_env_host_remove
CLI
substrio op env.host.remove

Parameters

NameInTypeRequiredDescription
hostpathstringYesA host env.host.list names.

Response

204 No Content: success has no body.

Errors

A failed call answers the error envelope with a typed code.

Example

curl -X DELETE "$SUBSTRIO_URL/v1/_env_hosts/$HOST" \
  -H "Authorization: Bearer $SUBSTRIO_KEY"

env.host.set

Bind a host of the app's choosing, <label>.<root> under an enabled root domain (my-app-v2.substrio.com), to one of its environments: live, or a sandbox (with version, a new sandbox running that version). The host answers exactly what that environment runs, with its data. A label has one owner across the platform: HOST_TAKEN when another app holds it, HOST_RESERVED for a reserved name or an app host, HOST_INVALID (with suggestion) for a label that is not a hostname label, ROOT_DOMAIN_UNKNOWN or ROOT_DOMAIN_DISABLED for the root. Binding a host the app holds again moves it. version.live.set with from: <host> pushes what it runs live.

Route
POST /v1/_env_hosts
Auth
App key tenant
MCP tool
substrio_env_host_set
CLI
substrio op env.host.set

Parameters

NameInTypeRequiredDescription
hostbodystringYes<label>.<root>: one DNS label (lowercase letters, digits, inner hyphens, 1 to 63) under a root domain env.host.list names, such as my-app-v2.substrio.com.
environmentbodystringYeslive (the app itself), or a sandbox name from sandbox.list; with version, a sandbox that does not exist yet is made and runs that version.
versionbodyintegerNoA version number from version.list to run in the environment (a sandbox) before the host is bound; absent: the environment runs what it runs. Minimum 1.

Response

FieldTypePresentDescription
hoststringAlways
labelstringAlways
rootstringAlways
environmentstringAlwayslive or the sandbox's name.
versionintegerAlwaysthe version the environment runs now; 0: none.
created_atintegerAlways

Errors

A failed call answers the error envelope with a typed code.

Example

curl -X POST "$SUBSTRIO_URL/v1/_env_hosts" \
  -H "Authorization: Bearer $SUBSTRIO_KEY" \
  -H "Content-Type: application/json" \
  -d '{"host":"host","environment":"environment"}'

route

route.call

Send one HTTP request to a route of the app or of one of its sandboxes and return the response.

Route
POST /v1/_route
Auth
App key tenant
MCP tool
substrio_route_call
CLI
substrio op route.call

Parameters

NameInTypeRequiredDescription
methodbodystringYesGET, POST, PUT, PATCH, DELETE, ...
pathbodystringYesThe route's path; a ?query here is kept. Matches ^/.
querybodystringNoa=1&b=2, added to any query in path.
headersbodyobjectNo
bodybodystringNoThe request body as text (send JSON as its text).
body_base64bodystringNoThe request body as base64, instead of body.
sandboxbodystringNoCall this sandbox of the app (for example dev) instead of the app; its outbound fence applies.

Response

A JSON object.

Errors

A failed call answers the error envelope with a typed code.

Example

curl -X POST "$SUBSTRIO_URL/v1/_route" \
  -H "Authorization: Bearer $SUBSTRIO_KEY" \
  -H "Content-Type: application/json" \
  -d '{"method":"method","path":"path"}'

route.list

List the HTTP routes the deployed functions answer: method, pattern, function and version; routes are declared in each function's manifest at deploy, there is no separate edit.

Route
GET /v1/_routes
Auth
App key tenant
MCP tool
substrio_route_list
CLI
substrio op route.list

Parameters

No parameters.

Response

FieldTypePresentDescription
routesarray of objectAlways
countintegerAlways

Errors

A failed call answers the error envelope with a typed code.

Example

curl "$SUBSTRIO_URL/v1/_routes" \
  -H "Authorization: Bearer $SUBSTRIO_KEY"

sandbox

sandbox.allow.add

Let a sandbox send outbound requests to hosts matching a pattern.

Route
POST /v1/_sandboxes/{name}/allow
Auth
App key tenant
MCP tool
substrio_sandbox_allow_add
CLI
substrio op sandbox.allow.add

Parameters

NameInTypeRequiredDescription
namepathstringYes
patternbodystringYes

Response

A JSON object.

Errors

A failed call answers the error envelope with a typed code.

Example

curl -X POST "$SUBSTRIO_URL/v1/_sandboxes/$NAME/allow" \
  -H "Authorization: Bearer $SUBSTRIO_KEY" \
  -H "Content-Type: application/json" \
  -d '{"pattern":"pattern"}'

sandbox.allow.list

List the host patterns a sandbox may send outbound requests to.

Route
GET /v1/_sandboxes/{name}/allow
Auth
App key tenant
MCP tool
substrio_sandbox_allow_list
CLI
substrio op sandbox.allow.list

Parameters

NameInTypeRequiredDescription
namepathstringYes

Response

A JSON object.

Errors

A failed call answers the error envelope with a typed code.

Example

curl "$SUBSTRIO_URL/v1/_sandboxes/$NAME/allow" \
  -H "Authorization: Bearer $SUBSTRIO_KEY"

sandbox.allow.remove

Stop letting a sandbox send outbound requests to hosts matching a pattern.

Route
DELETE /v1/_sandboxes/{name}/allow/{pattern}
Auth
App key tenant
MCP tool
substrio_sandbox_allow_remove
CLI
substrio op sandbox.allow.remove

Parameters

NameInTypeRequiredDescription
namepathstringYes
patternpathstringYes

Response

A JSON object.

Errors

A failed call answers the error envelope with a typed code.

Example

curl -X DELETE "$SUBSTRIO_URL/v1/_sandboxes/$NAME/allow/$PATTERN" \
  -H "Authorization: Bearer $SUBSTRIO_KEY"

sandbox.create

Create a sandbox: a copy of the app's data running the app's live version.

Route
POST /v1/_sandboxes
Auth
App key tenant
MCP tool
substrio_sandbox_create
CLI
substrio op sandbox.create

Parameters

NameInTypeRequiredDescription
namebodystringNo
outboundbody"live" | "fenced"Nolive: a dev environment, its requests go out as the app's do (it has its own secrets); fenced (the default): kept in its outbox.

Response

A JSON object.

Errors

A failed call answers the error envelope with a typed code.

Example

curl -X POST "$SUBSTRIO_URL/v1/_sandboxes" \
  -H "Authorization: Bearer $SUBSTRIO_KEY"

sandbox.delete

Delete one sandbox by name together with its data; the app itself is not touched. To keep the sandbox and only copy the app's data into it again, use sandbox.reset.

Route
DELETE /v1/_sandboxes/{name}
Auth
App key tenant
MCP tool
substrio_sandbox_delete
CLI
substrio op sandbox.delete

Parameters

NameInTypeRequiredDescription
namepathstringYes

Response

A JSON object.

Errors

A failed call answers the error envelope with a typed code.

Example

curl -X DELETE "$SUBSTRIO_URL/v1/_sandboxes/$NAME" \
  -H "Authorization: Bearer $SUBSTRIO_KEY"

sandbox.list

List the app's sandboxes, their hosts and live versions.

Route
GET /v1/_sandboxes
Auth
App key tenant
MCP tool
substrio_sandbox_list
CLI
substrio op sandbox.list

Parameters

No parameters.

Response

A JSON object.

Errors

A failed call answers the error envelope with a typed code.

Example

curl "$SUBSTRIO_URL/v1/_sandboxes" \
  -H "Authorization: Bearer $SUBSTRIO_KEY"

sandbox.outbox

Read the outbound requests a sandbox's fence captured instead of sending.

Route
GET /v1/_sandboxes/{name}/outbox
Auth
App key tenant
MCP tool
substrio_sandbox_outbox
CLI
substrio op sandbox.outbox

Parameters

NameInTypeRequiredDescription
namepathstringYes

Response

A JSON object.

Errors

A failed call answers the error envelope with a typed code.

Example

curl "$SUBSTRIO_URL/v1/_sandboxes/$NAME/outbox" \
  -H "Authorization: Bearer $SUBSTRIO_KEY"

sandbox.reset

Copy the app's data into a sandbox again, keeping its live version.

Route
POST /v1/_sandboxes/{name}/reset
Auth
App key tenant
MCP tool
substrio_sandbox_reset
CLI
substrio op sandbox.reset

Parameters

NameInTypeRequiredDescription
namepathstringYes

Response

A JSON object.

Errors

A failed call answers the error envelope with a typed code.

Example

curl -X POST "$SUBSTRIO_URL/v1/_sandboxes/$NAME/reset" \
  -H "Authorization: Bearer $SUBSTRIO_KEY"

sandbox.stub.clear

Forget a test tenant's stubs and the recorded fetches; answers how many of each.

Route
DELETE /v1/_stubs
Auth
App key tenant
MCP tool
substrio_sandbox_stub_clear
CLI
substrio op sandbox.stub.clear

Parameters

No parameters.

Response

FieldTypePresentDescription
cleared_stubsintegerAlways
cleared_callsintegerAlways

Errors

A failed call answers the error envelope with a typed code.

Example

curl -X DELETE "$SUBSTRIO_URL/v1/_stubs" \
  -H "Authorization: Bearer $SUBSTRIO_KEY"

sandbox.stub.list

Read a test tenant's stubs, with how often each answered, and every fetch its functions made since the last clear (method, URL, headers, body, the tenant's clock, stubbed or unmatched).

Route
GET /v1/_stubs
Auth
App key tenant
MCP tool
substrio_sandbox_stub_list
CLI
substrio op sandbox.stub.list

Parameters

No parameters.

Response

FieldTypePresentDescription
stubsarray of objectAlways
callsarray of objectAlwaysEvery fetch the tenant's functions made since the last clear, oldest first, stubbed or not.

Errors

A failed call answers the error envelope with a typed code.

Example

curl "$SUBSTRIO_URL/v1/_stubs" \
  -H "Authorization: Bearer $SUBSTRIO_KEY"

sandbox.stub.set

Stub one outbound request of a test tenant: its functions' fetch() of the given method, origin and path resolves with the stub's status, headers and body instead of going out. Only a test tenant takes stubs, any other is refused with TEST_TENANT_REQUIRED. The newest matching stub that is not spent answers; a fetch no stub matches is rejected. Answers {id}.

Route
POST /v1/_stubs
Auth
App key tenant
MCP tool
substrio_sandbox_stub_set
CLI
substrio op sandbox.stub.set

Parameters

NameInTypeRequiredDescription
methodbody"GET" | "POST" | "PUT" | "DELETE" | "PATCH" | "OPTIONS" | "HEAD"NoThe request method this stub answers; absent: any method.
urlbodystringYesThe http or https URL a function's fetch() calls, without a query: the scheme, host, port and path are the stub's key.
path_matchbody"exact" | "prefix"Noprefix: the path and everything below it, on whole segments. Default "exact".
statusbodyintegerNoThe status the fetch resolves with. Minimum 100. Maximum 599. Default 200.
headersbodyobjectNoThe response headers.
bodybodystringNoThe response body. Default "".
timesbodyintegerNoHow many answers the stub gives before it is spent; 0: no limit. Minimum 0. Default 0.

Response

FieldTypePresentDescription
idintegerAlwaysThe stub's id, as sandbox.stub.list names it.

Errors

A failed call answers the error envelope with a typed code.

Example

curl -X POST "$SUBSTRIO_URL/v1/_stubs" \
  -H "Authorization: Bearer $SUBSTRIO_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url":"url"}'

tenant

tenant.clock.set

Set a test tenant's clock: Date.now() and new Date() in its functions read it. real, frozen at an instant, or real time plus an offset; setTimeout and cron stay on real time. Only a test tenant has a clock, any other is refused with TEST_TENANT_REQUIRED. Answers the setting and the clock's reading.

Route
POST /v1/_clock
Auth
App key tenant
MCP tool
substrio_tenant_clock_set
CLI
substrio op tenant.clock.set

Parameters

NameInTypeRequiredDescription
modebody"real" | "frozen" | "offset"Yesreal: the clock runs on real time; frozen: Date.now() is the instant at, whatever the real time; offset: real time plus offset_ms.
atbodyintegerNofrozen only: the instant, in Unix milliseconds.
offset_msbodyintegerNooffset only: milliseconds added to real time (negative: earlier).

Response

FieldTypePresentDescription
mode"real" | "frozen" | "offset"Always
atinteger or nullAlways
offset_msinteger or nullAlways
now_msintegerAlwaysThe clock's reading when this answer was made, in Unix milliseconds.

Errors

A failed call answers the error envelope with a typed code.

Example

curl -X POST "$SUBSTRIO_URL/v1/_clock" \
  -H "Authorization: Bearer $SUBSTRIO_KEY" \
  -H "Content-Type: application/json" \
  -d '{"mode":"real"}'

version

version.check

Check an app version before it is pushed or made live: the body is the version.create body, or {version} naming one already committed (a number, an id, a branch, live or a sandbox's name; no manifest). Runs function.check over every function whose source is uploaded (parsed as script, CommonJS or ES module, with deploy's require() refusal) and answers ok, diagnostics (function, severity, message, line, column) and the blobs still missing. Nothing is stored or run. version.create and version.live.set run this same check unless they are sent check:false.

Route
POST /v1/_versions/_check
Auth
App key tenant
MCP tool
substrio_version_check
CLI
substrio op version.check

Parameters

NameInTypeRequiredDescription
functionsbodyarray of objectNoEvery function of the app. A function not listed here is not part of the version.
rulesbodyobject or nullNoThe security rules document (the body security.rules.set takes), by hash.
mcpbodyobject or nullNoThe app's MCP tool manifest (the body mcp.tools.set takes), by hash.
sitebodyobject or nullNoThe static site: its files by path.
cronbodyarray of objectNoSchedules made when the version goes live.
queuesbodyarray of objectNoDurable queues made when the version goes live (a send to a queue not listed is refused). Messages of a queue the version drops stay stored.
triggersbodyarray of objectNoCollection triggers made when the version goes live.
plansbodyobject or nullNoThe plans file POST /v1/_plans takes, set on the target when the version goes live; absent leaves its plans as they are.
authbodyobject or nullNoThe auth settings PUT /v1/_auth/settings takes, over the defaults, set on the target when the version goes live; absent leaves them as they are.
loginbodyobject or nullNoThe login settings PUT /v1/_auth/login takes, set on the target when the version goes live; absent leaves them as they are.
permissionsbodyobject or nullNoThe permission catalog permissions.set takes ([permissions]: names, all, implies), declared on the target first when the version goes live, append only; absent leaves it as it is.
ledgerbodyobject or nullNoThe ledger catalog ledger.catalog.set takes ([ledger]: kinds, categories), declared on the target first when the version goes live, append only; absent leaves it as it is.
collectionsbodyarray or nullNoThe declared collections, as the calls substrio deploy makes, run in order on the target when the version goes live, before any part switches: a collection that exists is kept, an index already declared the same way changes nothing; absent leaves them as they are.
versionbodyanyNoInstead of a manifest: the committed version to check, a number from version.list, an id (64 hex digits), a branch, live or a sandbox's name. The answer then names its number in version.
messagebodystringNoIgnored; kept so a version.create body can be sent as it is.

Response

FieldTypePresentDescription
okbooleanAlwaystrue when no diagnostic has severity error.
diagnosticsarray of objectAlways
missingarray of stringAlwayshashes of blobs (any part of the version) not uploaded yet.
versionintegerWhen setthe number of the committed version checked, when the call named one.

Errors

A failed call answers the error envelope with a typed code.

Example

curl -X POST "$SUBSTRIO_URL/v1/_versions/_check" \
  -H "Authorization: Bearer $SUBSTRIO_KEY"

version.create

Push an app version: the functions (each by the SHA-256 of its source), rules, MCP manifest, site files, cron, triggers, plans, auth and login settings, and the permission and ledger catalogs (declared first when it goes live, append only). Answers 201 {version, missing, existed}: missing lists the blobs you still have to upload with site.blob.upload, and existed is true when the same content was pushed before. Pushing does not change what is live: make it live with version.live.set. The version is committed on the branch named by branch (main when none is), which is created at this version when it has no version yet. Sources already uploaded are checked like function.check unless check is false; a failing one refuses the push with 400 and its diagnostics.

Route
POST /v1/_versions
Auth
App key tenant
MCP tool
substrio_version_create
CLI
substrio op version.create

Parameters

NameInTypeRequiredDescription
functionsbodyarray of objectYesEvery function of the app. A function not listed here is not part of the version.
rulesbodyobject or nullNoThe security rules document (the body security.rules.set takes), by hash.
mcpbodyobject or nullNoThe app's MCP tool manifest (the body mcp.tools.set takes), by hash.
sitebodyobject or nullNoThe static site: its files by path.
cronbodyarray of objectNoSchedules made when the version goes live.
queuesbodyarray of objectNoDurable queues made when the version goes live (a send to a queue not listed is refused). Messages of a queue the version drops stay stored.
triggersbodyarray of objectNoCollection triggers made when the version goes live.
plansbodyobject or nullNoThe plans file POST /v1/_plans takes, set on the target when the version goes live; absent leaves its plans as they are.
authbodyobject or nullNoThe auth settings PUT /v1/_auth/settings takes, over the defaults, set on the target when the version goes live; absent leaves them as they are.
loginbodyobject or nullNoThe login settings PUT /v1/_auth/login takes, set on the target when the version goes live; absent leaves them as they are.
permissionsbodyobject or nullNoThe permission catalog permissions.set takes ([permissions]: names, all, implies), declared on the target first when the version goes live, append only; absent leaves it as it is.
ledgerbodyobject or nullNoThe ledger catalog ledger.catalog.set takes ([ledger]: kinds, categories), declared on the target first when the version goes live, append only; absent leaves it as it is.
collectionsbodyarray or nullNoThe declared collections, as the calls substrio deploy makes, run in order on the target when the version goes live, before any part switches: a collection that exists is kept, an index already declared the same way changes nothing; absent leaves them as they are.
messagebodystringNoA note kept with the version (version.list shows it).
checkbodybooleanNotrue (the default) runs function.check over every function whose source is already uploaded and refuses the push, with the diagnostics, when one has an error; sources not uploaded yet are checked by version.live.set, which refuses the same way. false skips the check. Default true.
branchbodystringNoThe branch of the app's history this version is committed on (branch.list names them); the branch is created, pointing at this version, when it has no version yet. Absent: main, where every push lands. Default "main".

Response

A JSON object.

Errors

A failed call answers the error envelope with a typed code.

Example

curl -X POST "$SUBSTRIO_URL/v1/_versions" \
  -H "Authorization: Bearer $SUBSTRIO_KEY" \
  -H "Content-Type: application/json" \
  -d '{"functions":[]}'

version.diff

Show what changes between two app versions (the route's {from} and {to}): the parts added, removed and changed; 404 when either does not exist.

Route
GET /v1/_versions/{from}/diff/{to}
Auth
App key tenant
MCP tool
substrio_version_diff
CLI
substrio op version.diff

Parameters

NameInTypeRequiredDescription
frompathintegerYesMinimum 1.
topathintegerYesMinimum 1.

Response

A JSON object.

Errors

A failed call answers the error envelope with a typed code.

Example

curl "$SUBSTRIO_URL/v1/_versions/$FROM/diff/$TO" \
  -H "Authorization: Bearer $SUBSTRIO_KEY"

version.get

Read one app version by number (the route's {number}): its functions, rules, MCP manifest, site, cron, triggers and message, and in missing the blobs it still lacks. 404 when no such version.

Route
GET /v1/_versions/{number}
Auth
App key tenant
MCP tool
substrio_version_get
CLI
substrio op version.get

Parameters

NameInTypeRequiredDescription
numberpathintegerYesMinimum 1.

Response

A JSON object.

Errors

A failed call answers the error envelope with a typed code.

Example

curl "$SUBSTRIO_URL/v1/_versions/$NUMBER" \
  -H "Authorization: Bearer $SUBSTRIO_KEY"

version.list

List the app's versions, newest first, with the live version number (live), the version a rollback would restore (rollback_to), the live history with the backup each promote took, and each sandbox's live version. direct_changes lists, for the app and each sandbox, any function deployed directly (outside a version) since its live version was recorded. limit pages the versions and next_cursor (null on the last page) is the cursor the next page passes.

Route
GET /v1/_versions
Auth
App key tenant
MCP tool
substrio_version_list
CLI
substrio op version.list

Parameters

NameInTypeRequiredDescription
limitqueryinteger (0 or more)Nothe most items per page (positive); absent returns every item.
cursorquerystringNoresume after the previous page: its next_cursor.

Response

A JSON object.

Errors

A failed call answers the error envelope with a typed code.

Example

curl "$SUBSTRIO_URL/v1/_versions" \
  -H "Authorization: Bearer $SUBSTRIO_KEY"

version.live.set

Make an app version live, or roll back with version: previous; from instead of version promotes what a sandbox or a test host runs. Before anything changes it backs the app's data up (unless backup is false) and, unless check is false or this is a rollback, runs function.check over the version's functions and refuses with 400 and the diagnostics when one has an error. A version with a blob not uploaded cannot go live (upload what version.get lists in missing). When a function was deployed directly since the version now live was recorded and this would overwrite or delete it, direct controls what happens: refuse (the default) answers 409 DIRECT_CHANGES with direct_changes instead; replace applies the version anyway (reporting replaced); keep applies it except those functions, left as deployed (reporting kept). With sandbox it acts on that sandbox instead. With plan true it answers the plan of the change (each collection's shape change, the retypes and the documents they would read) and applies nothing. Answers live, previous, rollback_to, sandbox and backup_id, and direct_changes, replaced or kept when relevant.

Route
POST /v1/_live
Auth
App key tenant
MCP tool
substrio_live_set
CLI
substrio op version.live.set

Parameters

NameInTypeRequiredDescription
versionbodyanyNoA version number from version.list, or previous to roll back to the version live before this one (a rollback is never checked).
frombodystringNoInstead of version: the environment whose running version goes live, a sandbox name from sandbox.list or a host from env.host.list (my-app-v2.substrio.com); an unknown one, or one running no version, is ENVIRONMENT_NOT_FOUND.
sandboxbodystringNoA sandbox name from sandbox.list: make the version live there instead of on the app.
backupbodybooleanNofalse skips the data backup an app promote takes first (version.restore needs it). Default true.
checkbodybooleanNotrue (the default) runs function.check over every function of the version before anything changes, and refuses with the diagnostics when one has an error; false skips the check. Not applied to a rollback. Default true.
planbodybooleanNotrue answers what this change would do to each collection's declared shape and what it would cost, and applies nothing: no check, no backup, no write, and the version now live keeps serving. Answers plan, version, live and collections, each entry naming the collection, whether the change adds, removes or changes its shape, its fields (field, change: added, removed or retyped, with from and to for a retype), retypes (the fields whose new type asks something of the stored documents) and documents (what those retypes would read). Default false.
directbody"refuse" | "replace" | "keep"NoWhat to do when a function was deployed directly (function.deploy, substrio deploy NAME, function.environment.set, function.delete) since the version now live was recorded, and this promote would overwrite or delete it with something else: refuse (the default) answers 409 DIRECT_CHANGES with direct_changes instead of applying anything; replace applies the version anyway, reporting what it overwrote in replaced; keep applies the version except those functions, left exactly as deployed, reported in kept. Default "refuse".

Response

A JSON object.

Errors

A failed call answers the error envelope with a typed code.

Example

curl -X POST "$SUBSTRIO_URL/v1/_live" \
  -H "Authorization: Bearer $SUBSTRIO_KEY"