Applications and deploys

An application is one deployable island, defined by a compose file. A deployment is one immutable revision of it. Deploying is uploading a new revision; rolling back is activating an older one.

Create an application

POST /cli/applications
{"slug": "vpn-alice", "name": "Alice's VPN", "organization": "acme"}

organization may be omitted when exactly one of your organizations is eligible. Slugs are lowercase letters, numbers and dashes, unique per organization, and are what every other path here names the application by.

Response Means
201 Created; the body describes it
400 The slug is not a valid slug
403 You are a member but not an owner or admin
409 That slug already exists in that organization, or you must name one

Upload a revision

POST /applications/{slug}/bundle

A multipart upload of the compose text plus a tar.gz per build: context. The platform parses the compose at ingest — an unusable file is a 400 before anything is stored — then builds the contexts, pins the images to digests, places the revision on a context, and deploys it. See agent-cli.md for the wire format; the sc CLI is a reference implementation of this one call.

Only a subset of compose is acted on: image, build, command, restart, environment, ports, deploy, x-someones. Anything else is stripped with a warning rather than rejected, and the warnings come back with the upload. Under x-someones: the only key is http, naming the container port that speaks HTTP (ports). Under deploy: the subset is narrower still — replicas and resources.limits.{cpus,memory} — and everything else there (placement, restart_policy, update_config, mode, labels, resources.reservations) warns by its full path.

restart: is the only spelling for what happens when a container exits, and it decides more than the restart condition:

Written Deployed as Means
absent, always, unless-stopped replicated service, restart on any exit a server
on-failure, on-failure:N replicated service, restart on non-zero exit a retry; N is ignored and retries are unbounded
no swarm job, replicas completions, never restarted a migration or batch job — expected to exit 0 and stay exited

unless-stopped has no swarm equivalent and warns that it was treated as always. Anything else is a 400.

Configuration

PUT /cli/applications/{slug}/variables
{"variables": {"OVPN_SERVER_CONF": "…"}, "sensitive": true}

A map at a time, in one transaction, so a dropped connection cannot leave half an environment applied. sensitive marks values unreadable afterwards — nothing in the API ever loads a value back, only its metadata, which is why a secret cannot escape through a field somebody adds later.

Variables are resolved and frozen into a revision when it deploys, so changing one affects the next deploy rather than what is running.

Watch it

Deployment is a readable resource with status and statusReason. Poll it, or list revisions inline:

GET /cli/applications/{slug}?deployments=1

The statuses that matter to a consumer are pendingbuildingbuiltdeployingrunning, with failed reachable from any of them and statusReason carrying the sentence explaining why. A revision that landed badly also carries failure{"reference": "F-24GT1BQ7", "url": "…"} — which is where the rest of the account is: the phase, whose fault it was, and the build log. It is null on every revision that is fine. Logs stream from GET /cli/applications/{slug}/services/{service}/logs.

Once a revision is running, ask where it answers.

← All developer pages