Skip to content

API reference

Deploys and releases

Markdown

Detect a project, build it, deploy an image, follow a deploy, list releases and roll back; previews and Git-connected deploys.

A deploy puts an image behind an app: an OCI reference such as nginx:alpine, or build:<id> for a build Rytiv made from your source. Every deploy that goes live is a release, and a rollback deploys an earlier release’s image again without a rebuild.

A deploy rolls one machine at a time: the new machine must boot and answer on its port (and pass the health check, if you set one) before an old one is taken out of traffic. If the new machine fails, the deploy stops and the old version keeps serving. After the switch, the deploy keeps watching the app’s error rate for a while and rolls back on its own if it gets worse than before; the deploy’s watch field says what it found.

The CLI does the whole path for you: ry deploy <app> --source . detects the project, uploads it, builds it on Rytiv’s machines and deploys the result. See the guide Deploy a Next.js app.

Reads a project’s manifest and answers what Rytiv would build and start, before any build.

Auth: API key with full access or a deploy scope (deploy or deploy:<app>). Every class of agent token may call it.

JSON, the shape DetectRequest of the contract.

Field Type Required Description
app string optional
inventory object required
inventory.packageJson object of any or null optional
inventory.files array of string optional 0 to 4000 items.
inventory.envExample string or null optional
inventory.envRefs array of string optional 0 to 500 items.
inventory.configs object of string optional
curl -X POST "https://api.rytiv.app/v1/detect" \
-H "Authorization: Bearer $RYTIV_TOKEN" \
-H "Content-Type: application/json" \
-d '{"inventory":{"packageJson":{"<key>":"<value>"}}}'

200 with a JSON body.

Status Code Meaning
400 bad-request The request is malformed or a field is out of range. error names every field; issues lists them.
401 unauthenticated No API key, or one that does not work.
403 token-scope The key’s scopes do not cover this route.

Uploads a source archive and starts a build on Rytiv’s build machines.

Auth: API key with full access or the scope deploy or deploy:<app> for this app. An agent token of class sandbox or twin may call it; class production is refused (agent-token-production-readonly).

Name Description
name The app’s name.
Name Description
buildMemoryMb
commitSha
curl -X POST "https://api.rytiv.app/v1/apps/<name>/builds" \
-H "Authorization: Bearer $RYTIV_TOKEN" \
-H "Content-Type: application/octet-stream" \
--data-binary @source.tar.gz

202 with a JSON object carrying id, buildId, status.

Status Code Meaning
401 unauthenticated No API key, or one that does not work.
403 token-scope The key’s scopes do not cover this route.
404 not-found Not found, or not yours. An object of another organization answers like one that does not exist.

One build with its state and log.

Auth: API key with full access or the scope deploy or deploy:<app> for this app, or the scope read. Every class of agent token may call it.

Name Description
name The app’s name.
id The object’s id.
curl -X GET "https://api.rytiv.app/v1/apps/<name>/builds/<id>" \
-H "Authorization: Bearer $RYTIV_TOKEN"

200 with a JSON body.

Status Code Meaning
401 unauthenticated No API key, or one that does not work.
403 token-scope The key’s scopes do not cover this route.
404 not-found Not found, or not yours. An object of another organization answers like one that does not exist.

Deploys an image to the app and answers the deploy right away. Poll GET /v1/deploys/:id until status is done or error.

Auth: API key with full access or the scope deploy or deploy:<app> for this app. An agent token of class sandbox or twin may call it; class production is refused (agent-token-production-readonly).

Name Description
name The app’s name.

JSON, the shape DeployRequest of the contract.

Field Type Required Description
image string required What to deploy: an OCI reference, or build:<id> for a build of yours. 1 to 512 characters.
class shared-cpu-1x | shared-cpu-2x | shared-cpu-4x | shared-cpu-8x | performance-1x | performance-2x | performance-4x | performance-8x optional A named size instead of vcpus; the two must not contradict each other.
vcpus integer optional Virtual CPUs. 1 to 16, default 1.
memoryMb integer optional Memory in MB. 128 to 16384, default 512.
env object of string optional Plain environment variables. Use secrets for credentials.
diskMb integer optional The machine’s disk in MB. Without it, the image’s size plus headroom. 512 to 131072.
volumeGb integer optional A volume of this size, attached to the machine. 1 to 500.
start string optional The start command, run through /bin/sh -c. It replaces what detection chose or the image’s CMD. 1 to 2000 characters.
internalPort integer optional The port the app listens on. 1 to 65535, default 3000.
suspendPolicy object optional When the machine sleeps. Without it, a new app never sleeps; a deploy without it keeps the app’s rule.
suspendPolicy.mode suspend | stop | off optional suspend keeps the memory and resumes fast (machines up to 2048 MB; larger ones stop instead), stop shuts down, off never sleeps. default "suspend".
suspendPolicy.idleSeconds integer optional Seconds without requests and without CPU load before the machine sleeps. 10 to 86400, default 300.
suspendPolicy.stopAfterSeconds integer optional Second stage: after this many seconds since the last activity a suspended machine is stopped (its memory snapshot dropped, its disk kept). Only with mode: "suspend", and greater than idleSeconds. 10 to 604800.
healthCheck object optional An HTTP check a new machine must pass before it gets traffic.
healthCheck.path string optional The path to call; empty means the port alone. default "".
healthCheck.timeoutMs integer optional How long one probe may take. 100 to 30000, default 2000.
healthCheck.intervalMs integer optional Time between probes. 100 to 10000, default 500.
healthCheck.healthyThreshold integer optional Probes that must pass in a row. 1 to 10, default 1.
healthCheck.maxWaitMs integer optional How long a new machine may take in total before the deploy gives up on it. 1000 to 300000.
restart object optional What happens when the process ends. Without it, a crashed machine is restarted.
restart.policy never | on-failure optional never or on-failure. default "never".
restart.retries integer optional Restarts before the machine stays down. 1 to 10, default 3.
killSignal SIGTERM | SIGINT | SIGQUIT | SIGHUP | SIGUSR1 | SIGUSR2 | SIGWINCH | SIGKILL optional The signal sent before a machine is stopped or replaced. Default: the image’s STOPSIGNAL, else SIGTERM.
killTimeoutS integer optional Seconds between that signal and SIGKILL. 1 to 300.
durableCheckpoint boolean optional Agent machine: the whole state (memory and disk) is checkpointed and survives a host failure. default false.
checkpointIntervalS integer optional 5 to 3600.
console boolean optional default false.
command array of string optional Runs on a machine of its own, as an argument list. 1 to 64 items.
diskIsCache boolean optional
readiness port | boot optional boot: ready when the machine boots. port: ready when internalPort answers.
exposePorts array of integer optional 0 to 8 items.
egress object optional Outbound network: allow-all, deny-all, or allowlist with domains and cidrs.
egress.mode deny-all | allowlist required view to watch, control to take keyboard and mouse.
egress.domains array of string required 0 to 100 items.
egress.cidrs array of string required 0 to 10 items.
count integer optional How many machines the app runs. A deploy without it keeps the current count. 1 to 20.
curl -X POST "https://api.rytiv.app/v1/apps/<name>/deploy" \
-H "Authorization: Bearer $RYTIV_TOKEN" \
-H "Content-Type: application/json" \
-d '{"image":"nginx:alpine"}'

202 with the deploy (deployId repeats id for older readers):

{
"id": "<id>",
"orgId": "<orgId>",
"app": "my-app",
"image": "nginx:alpine",
"status": "running",
"created": [
"<created>"
],
"retired": [
"<retired>"
],
"at": "2026-10-21T09:00:00Z",
"deployId": "<deployId>"
}
Field Type Present Description
id string always
orgId string always The organization that owns it.
app string always
image string always An OCI reference such as nginx:alpine, or build:<id> for a build of your organization.
status running | done | error always
created array of string always
retired array of string always
at string (ISO 8601) always
error string if set
bootLog string if set
watch object if set
watch.forDeployId string always
watch.from string (ISO 8601) always
watch.until string (ISO 8601) always
watch.baseline object always
watch.rounds integer always 0 to 9007199254740991.
watch.lastAt string (ISO 8601) if set
watch.lastText string if set
watch.outcome healthy | unproven | rolled-back | not-rolled-back | superseded | expired if set
watch.outcomeText string if set
watch.outcomeAt string (ISO 8601) if set
watch.rollback object if set
watch.database object if set
kind "static" if set static for a site deploy.
deployId string always The same value as id, for readers from before.
Status Code Meaning
400 bad-request The request is malformed or a field is out of range. error names every field; issues lists them.
401 unauthenticated No API key, or one that does not work.
403 token-scope The key’s scopes do not cover this route.
404 build-not-found build:<id> is not a build of your organization.
404 not-found Not found, or not yours. An object of another organization answers like one that does not exist.
409 deploy-in-flight Another deploy of this app is running.
409 volume-needs-single-machine An app with a volume runs exactly one machine.

The app’s deploys, newest first.

Auth: API key with full access or the scope deploy or deploy:<app> for this app, or the scope read. Every class of agent token may call it.

Name Description
name The app’s name.
Name Description
limit How many entries, at most.
curl -X GET "https://api.rytiv.app/v1/apps/<name>/deploys" \
-H "Authorization: Bearer $RYTIV_TOKEN"

200 with a list of deploys, each:

[
{
"id": "<id>",
"orgId": "<orgId>",
"app": "my-app",
"image": "nginx:alpine",
"status": "running",
"created": [
"<created>"
],
"retired": [
"<retired>"
],
"at": "2026-10-21T09:00:00Z"
}
]
Field Type Present Description
id string always The deploy’s id.
orgId string always The organization that owns it.
app string always The app.
image string always What was deployed.
status running | done | error always running while it rolls, then done or error.
created array of string always The machines this deploy created.
retired array of string always The machines it took out of traffic.
at string (ISO 8601) always When it started.
error string if set On error: why.
bootLog string if set On error: the last console lines of the machine that failed.
watch object if set After the switch: what the watch over the app’s error rate found (healthy, unproven, rolled-back and more). Absent while the deploy rolls, and for a rollback.
watch.forDeployId string always
watch.from string (ISO 8601) always
watch.until string (ISO 8601) always
watch.baseline object always
watch.rounds integer always 0 to 9007199254740991.
watch.lastAt string (ISO 8601) if set
watch.lastText string if set
watch.outcome healthy | unproven | rolled-back | not-rolled-back | superseded | expired if set
watch.outcomeText string if set
watch.outcomeAt string (ISO 8601) if set
watch.rollback object if set
watch.database object if set
Status Code Meaning
401 unauthenticated No API key, or one that does not work.
403 token-scope The key’s scopes do not cover this route.
404 not-found Not found, or not yours. An object of another organization answers like one that does not exist.

One deploy: its status, the machines it created and retired, and after the switch the watch verdict.

Auth: API key with full access or a deploy scope (deploy or deploy:<app>), or the scope read. Every class of agent token may call it.

Name Description
id The deploy’s id.
curl -X GET "https://api.rytiv.app/v1/deploys/<id>" \
-H "Authorization: Bearer $RYTIV_TOKEN"

200 with the deploy:

{
"id": "<id>",
"orgId": "<orgId>",
"app": "my-app",
"image": "nginx:alpine",
"status": "running",
"created": [
"<created>"
],
"retired": [
"<retired>"
],
"at": "2026-10-21T09:00:00Z"
}
Field Type Present Description
id string always The deploy’s id.
orgId string always The organization that owns it.
app string always The app.
image string always What was deployed.
status running | done | error always running while it rolls, then done or error.
created array of string always The machines this deploy created.
retired array of string always The machines it took out of traffic.
at string (ISO 8601) always When it started.
error string if set On error: why.
bootLog string if set On error: the last console lines of the machine that failed.
watch object if set After the switch: what the watch over the app’s error rate found (healthy, unproven, rolled-back and more). Absent while the deploy rolls, and for a rollback.
watch.forDeployId string always
watch.from string (ISO 8601) always
watch.until string (ISO 8601) always
watch.baseline object always
watch.rounds integer always 0 to 9007199254740991.
watch.lastAt string (ISO 8601) if set
watch.lastText string if set
watch.outcome healthy | unproven | rolled-back | not-rolled-back | superseded | expired if set
watch.outcomeText string if set
watch.outcomeAt string (ISO 8601) if set
watch.rollback object if set
watch.database object if set
Status Code Meaning
401 unauthenticated No API key, or one that does not work.
403 token-scope The key’s scopes do not cover this route.
404 not-found Not found, or not yours. An object of another organization answers like one that does not exist.

The app’s releases, which one runs, and which one a rollback would bring back.

Auth: API key with full access or the scope deploy or deploy:<app> for this app, or the scope read. Every class of agent token may call it.

Name Description
name The app’s name.
Name Description
limit How many entries, at most.
curl -X GET "https://api.rytiv.app/v1/apps/<name>/releases" \
-H "Authorization: Bearer $RYTIV_TOKEN"

200 with the release list:

{
"app": "<app>",
"releases": [
{
"id": "<id>",
"version": 1,
"status": "running",
"at": "2026-10-21T09:00:00Z",
"startedAt": "2026-10-21T09:00:00Z",
"image": "nginx:alpine",
"source": {
"kind": "git",
"repo": "<repo>",
"branch": "<branch>",
"commit": "<commit>"
},
"current": true,
"rolledBack": true,
"artifact": "retained",
"rollback": {
"possible": true
}
}
],
"retention": {
"keepBuilds": 1
}
}
Field Type Present Description
app string always
currentId string if set
releases array of object always The releases, newest first.
rollbackTarget object if set
rollbackTarget.id string always
rollbackTarget.version integer always 1 to 9007199254740991.
retention object always
retention.keepBuilds integer always 1 to 9007199254740991.
Status Code Meaning
401 unauthenticated No API key, or one that does not work.
403 token-scope The key’s scopes do not cover this route.
404 not-found Not found, or not yours. An object of another organization answers like one that does not exist.

Deploys an earlier release’s image again, without a rebuild, with the app’s current settings. Empty body: the previous release that went live.

Auth: API key with full access or the scope deploy or deploy:<app> for this app. An agent token of class sandbox or twin may call it; class production is refused (agent-token-production-readonly).

Name Description
name The app’s name.

JSON, the shape RollbackRequest of the contract.

Field Type Required Description
version integer optional 1 to 9007199254740991.
releaseId string optional 1 to 64 characters.
curl -X POST "https://api.rytiv.app/v1/apps/<name>/rollback" \
-H "Authorization: Bearer $RYTIV_TOKEN" \
-H "Content-Type: application/json" \
-d '{}'

202 with the deploy that brings the release back:

{
"id": "<id>",
"orgId": "<orgId>",
"app": "my-app",
"image": "nginx:alpine",
"status": "running",
"created": [
"<created>"
],
"retired": [
"<retired>"
],
"at": "2026-10-21T09:00:00Z",
"deployId": "<deployId>"
}
Field Type Present Description
id string always
orgId string always The organization that owns it.
app string always
image string always An OCI reference such as nginx:alpine, or build:<id> for a build of your organization.
status running | done | error always
created array of string always
retired array of string always
at string (ISO 8601) always
error string if set
bootLog string if set
watch object if set
watch.forDeployId string always
watch.from string (ISO 8601) always
watch.until string (ISO 8601) always
watch.baseline object always
watch.rounds integer always 0 to 9007199254740991.
watch.lastAt string (ISO 8601) if set
watch.lastText string if set
watch.outcome healthy | unproven | rolled-back | not-rolled-back | superseded | expired if set
watch.outcomeText string if set
watch.outcomeAt string (ISO 8601) if set
watch.rollback object if set
watch.database object if set
kind "static" if set static for a site deploy.
deployId string always The same value as id, for readers from before.
Status Code Meaning
400 bad-request The request is malformed or a field is out of range. error names every field; issues lists them.
401 unauthenticated No API key, or one that does not work.
403 token-scope The key’s scopes do not cover this route.
404 not-found Not found, or not yours. An object of another organization answers like one that does not exist.
404 release-not-found No release with that version or id.
409 deploy-in-flight Another deploy of this app is running.
409 no-previous-release There is no earlier release that went live.
409 release-artifact-gone The release’s image is no longer available.
409 rollback-needs-machine-config The app has no machine whose settings a rollback could reuse.
409 rollback-not-for-resources The app backs a database; databases are restored, not rolled back.
409 rollback-same-build That release runs the same build as the current one.
409 rollback-target-current That release is the one that runs.
409 rollback-target-never-live That release never went live, so there is nothing to bring back.

The preview apps of a Git-connected app, one per branch.

Auth: API key with full access or the scope read. Every class of agent token may call it.

Name Description
name The app’s name.
curl -X GET "https://api.rytiv.app/v1/apps/<name>/previews" \
-H "Authorization: Bearer $RYTIV_TOKEN"

200 with a JSON object carrying previews, ttlDays, maxPerApp.

Status Code Meaning
401 unauthenticated No API key, or one that does not work.
403 token-scope The key’s scopes do not cover this route.
404 not-found Not found, or not yours. An object of another organization answers like one that does not exist.

Creates a preview app for a branch.

Auth: API key with full access (a key with scopes cannot call this route). An agent token of class sandbox or twin may call it; class production is refused (agent-token-production-readonly).

Name Description
name The app’s name.
curl -X POST "https://api.rytiv.app/v1/apps/<name>/previews" \
-H "Authorization: Bearer $RYTIV_TOKEN" \
-H "Content-Type: application/json" \
-d '{"branch":"feature/login"}'

A JSON body on success.

Status Code Meaning
400 branch
400 name-reserved The platform keeps this name (for example api, console, docs, www, and every name that is rytiv or starts with rytiv-).
401 unauthenticated No API key, or one that does not work.
403 token-scope The key’s scopes do not cover this route.
404 not-found Not found, or not yours. An object of another organization answers like one that does not exist.
409 already-a-preview
409 base-branch
409 not-connected
409 preview-name-taken

Removes the preview app of a branch.

Auth: API key with full access (a key with scopes cannot call this route). An agent token of class sandbox or twin may call it; class production is refused (agent-token-production-readonly).

Name Description
name The app’s name.
branch The branch name of the preview.
curl -X DELETE "https://api.rytiv.app/v1/apps/<name>/previews/<branch>" \
-H "Authorization: Bearer $RYTIV_TOKEN"

204 with no body.

Status Code Meaning
401 unauthenticated No API key, or one that does not work.
403 token-scope The key’s scopes do not cover this route.
404 not-found Not found, or not yours. An object of another organization answers like one that does not exist.

Connects the app to a repository of an installed GitHub app: a push then deploys.

Auth: API key with full access (a key with scopes cannot call this route). An agent token of class sandbox or twin may call it; class production is refused (agent-token-production-readonly).

Name Description
name The app’s name.

JSON, the shape ConnectRepoRequest of the contract.

Field Type Required Description
installationId string required 1 to 64 characters.
repo string required 1 to 300 characters.
branch string optional 1 to 255 characters.
repoExternalId string optional 1 to 64 characters.
autoDeploy boolean optional
subdirectory string optional at most 200 characters.
previewDeploys boolean optional
curl -X PUT "https://api.rytiv.app/v1/apps/<name>/git" \
-H "Authorization: Bearer $RYTIV_TOKEN" \
-H "Content-Type: application/json" \
-d '{"installationId":"<installationId>","repo":"<repo>"}'

200 with a JSON body.

Status Code Meaning
400 bad-request The request is malformed or a field is out of range. error names every field; issues lists them.
400 branch
400 subdirectory
401 unauthenticated No API key, or one that does not work.
403 token-scope The key’s scopes do not cover this route.
404 not-found Not found, or not yours. An object of another organization answers like one that does not exist.

The app’s repository connection.

Auth: API key with full access or the scope read. Every class of agent token may call it.

Name Description
name The app’s name.
curl -X GET "https://api.rytiv.app/v1/apps/<name>/git" \
-H "Authorization: Bearer $RYTIV_TOKEN"

200 with a JSON object carrying connected.

Status Code Meaning
401 unauthenticated No API key, or one that does not work.
403 token-scope The key’s scopes do not cover this route.
404 not-found Not found, or not yours. An object of another organization answers like one that does not exist.

Disconnects the repository.

Auth: API key with full access (a key with scopes cannot call this route). An agent token of class sandbox or twin may call it; class production is refused (agent-token-production-readonly).

Name Description
name The app’s name.
curl -X DELETE "https://api.rytiv.app/v1/apps/<name>/git" \
-H "Authorization: Bearer $RYTIV_TOKEN"

204 with no body.

Status Code Meaning
401 unauthenticated No API key, or one that does not work.
403 token-scope The key’s scopes do not cover this route.
404 not-found Not found, or not yours. An object of another organization answers like one that does not exist.

The deploys a push triggered.

Auth: API key with full access or the scope read. Every class of agent token may call it.

Name Description
name The app’s name.
Name Description
limit How many entries, at most.
curl -X GET "https://api.rytiv.app/v1/apps/<name>/git/deploys" \
-H "Authorization: Bearer $RYTIV_TOKEN"

200 with a JSON body.

Status Code Meaning
401 unauthenticated No API key, or one that does not work.
403 token-scope The key’s scopes do not cover this route.
404 not-found Not found, or not yours. An object of another organization answers like one that does not exist.

Starts the installation of the GitHub app and answers the link to open.

Auth: API key with full access (a key with scopes cannot call this route). Refused for every agent token (agent-token-credential).

curl -X POST "https://api.rytiv.app/v1/git/connect" \
-H "Authorization: Bearer $RYTIV_TOKEN"

201 with a JSON body.

Status Code Meaning
401 unauthenticated No API key, or one that does not work.
403 token-scope The key’s scopes do not cover this route.

Whether that installation has completed.

Auth: API key with full access or the scope read. Every class of agent token may call it.

Name Description
id The object’s id.
curl -X GET "https://api.rytiv.app/v1/git/connect/<id>" \
-H "Authorization: Bearer $RYTIV_TOKEN"

200 with a JSON body.

Status Code Meaning
401 unauthenticated No API key, or one that does not work.
403 token-scope The key’s scopes do not cover this route.
404 not-found Not found, or not yours. An object of another organization answers like one that does not exist.

Records an installation of the GitHub app.

Auth: API key with full access (a key with scopes cannot call this route). Refused for every agent token (agent-token-credential).

JSON, the shape ConnectInstallationRequest of the contract.

Field Type Required Description
provider github optional
externalId string required
state string required
code string required 1 to 256 characters.
curl -X POST "https://api.rytiv.app/v1/git/installations" \
-H "Authorization: Bearer $RYTIV_TOKEN" \
-H "Content-Type: application/json" \
-d '{"externalId":"<externalId>","state":"<state>","code":"<code>"}'

200 or 201 with a JSON body.

Status Code Meaning
400 bad-request The request is malformed or a field is out of range. error names every field; issues lists them.
401 unauthenticated No API key, or one that does not work.
403 state
403 token-scope The key’s scopes do not cover this route.

The organization’s installations.

Auth: API key with full access or the scope read. Every class of agent token may call it.

curl -X GET "https://api.rytiv.app/v1/git/installations" \
-H "Authorization: Bearer $RYTIV_TOKEN"

200 with a JSON body.

Status Code Meaning
401 unauthenticated No API key, or one that does not work.
403 token-scope The key’s scopes do not cover this route.

Forgets an installation.

Auth: API key with full access (a key with scopes cannot call this route). Refused for every agent token (agent-token-credential).

Name Description
id The object’s id.
Name Description
force
curl -X DELETE "https://api.rytiv.app/v1/git/installations/<id>" \
-H "Authorization: Bearer $RYTIV_TOKEN"

204 with no body.

Status Code Meaning
401 unauthenticated No API key, or one that does not work.
403 token-scope The key’s scopes do not cover this route.
404 not-found Not found, or not yours. An object of another organization answers like one that does not exist.