Deployments

Create, update, promote, cancel, and stream logs for deployments.

A deployment is one version of an app running on the platform. It holds a spec (replicas, resources, image or artifact, env vars) and a status.

Status lifecycle: pendingrunningsucceeded | failed | cancelled

POST /api/v1/apps//deployments — Create

Creates a new deployment for the app. If artifact_id or a Docker image is provided, the scheduler is notified immediately. Without either, the deployment waits for a build to complete.

Body

  • environment (string): "development" (default) or "production" or any custom slug
  • process_type (string): "tish" (native binary) or "docker". Default "tish"
  • artifact_id (UUID, optional): Required for tish apps — reference to a compiled binary in the registry
  • image (string, optional): Required for docker apps — e.g. "nginx:latest"
  • replicas (number): Default 1
  • resources (object): { "cpu": "100m", "memory": "128Mi" } — defaults shown
  • networking (object):
    • port (number, optional): Leave null to have the platform assign a port
    • protocol (string): "http" (default)
    • health_path (string): e.g. "/health"
  • env (object): Additional env vars merged on top of app-level vars
  • cold_start_enabled (boolean): Enable scale-to-zero. Default true
  • idle_timeout_secs (number): Seconds before an idle task is stopped. Default 300
  • max_runtime_secs (number, optional): Kill task after this many seconds
  • volumes (array): [{ "host_path": "/data", "container_path": "/app/data" }]

Deploy a Docker container

curl -X POST http://localhost:47080/api/v1/apps/$APP_ID/deployments \
  -H 'Content-Type: application/json' \
  -d '{
    "process_type": "docker",
    "image": "ghcr.io/myorg/my-api:latest",
    "replicas": 2,
    "environment": "production",
    "resources": {"cpu":"250m","memory":"256Mi"},
    "networking": {"port":8080,"health_path":"/health"},
    "env": {"LOG_LEVEL":"info"}
  }'

Deploy a tish binary

curl -X POST http://localhost:47080/api/v1/apps/$APP_ID/deployments \
  -H 'Content-Type: application/json' \
  -d "{
    \"artifact_id\": \"$ARTIFACT_ID\",
    \"process_type\": \"tish\",
    \"replicas\": 1,
    \"environment\": \"development\",
    \"networking\": {\"port\": 8080}
  }"

Response 201 Created

{
  "id": "uuid",
  "sha": "a1b2c3d4",
  "app_id": "uuid",
  "version": 3,
  "status": "pending",
  "spec": { ... },
  "tasks_ready": 0,
  "tasks_total": 2,
  "progress": 0,
  "environment_slug": "production",
  "preview_url": "https://my-api-a1b2c3d4-production.example.com",
  "created_at": "...",
  "updated_at": "..."
}

GET /api/v1/deployments/ — Status

Includes live tasks_ready, tasks_total, and progress (0–100).

# Poll until running
while true; do
  D=$(curl -sf http://localhost:47080/api/v1/deployments/$DEPLOY_ID)
  echo "$(echo $D | jq -r .status) — $(echo $D | jq -r .tasks_ready)/$(echo $D | jq -r .tasks_total) ready"
  [ "$(echo $D | jq -r .status)" != "pending" ] && break
  sleep 3
done

GET /api/v1/apps//deployments — List for app

Cursor-based pagination. Pass page_token (a version number) for subsequent pages.

Query paramspage_size (default 20, max 100), page_token

{ "deployments": [ { ...deployment } ], "next_page_token": "42" }

GET /api/v1/deployments — List all

Supports app_id, page, page_size, sort_by, sort_order query params.

curl "http://localhost:47080/api/v1/deployments?app_id=$APP_ID&sort_order=desc"

PATCH /api/v1/deployments/ — Scale / update spec

Updates the spec in place and tells the scheduler to reconcile. No new deployment object is created.

Bodyspec with any of: replicas, resources, image, process_type, volumes

# Scale to 3
curl -X PATCH http://localhost:47080/api/v1/deployments/$DEPLOY_ID \
  -H 'Content-Type: application/json' \
  -d '{"spec":{"replicas":3}}'
 
# Scale to zero (traffic wakes it via cold start)
curl -X PATCH http://localhost:47080/api/v1/deployments/$DEPLOY_ID \
  -H 'Content-Type: application/json' \
  -d '{"spec":{"replicas":0}}'

POST /api/v1/apps//deploy/trigger 🔒

Trigger a build-and-deploy from the app's configured Git source. Requires source config to be set. Polls the build service internally (up to 5 minutes) and creates the deployment when the build succeeds.

Body

  • branch (string, optional): Override the configured branch
  • ref (string, optional): Deploy a specific commit SHA
  • skip_build (boolean): Default false
  • environment (string): Default "development"
curl -X POST http://localhost:47080/api/v1/apps/$APP_ID/deploy/trigger \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"branch":"main","environment":"development"}'
// 201 Created
{ "deployment_id": "uuid", "status": "pending", "message": "Deployment created and scheduler notified" }

Only "github" source type is supported today. GitLab returns 501.

POST /api/v1/deployments//promote — Promote

Creates a new deployment in the target environment using the same artifact or image. The source deployment is not modified. Target environment's env vars are applied to the new deployment.

Body

  • strategy (string): "instant" (reuse artifact/image) or "rebuild" (new build from same source)
  • environment (string): Default "production"
# Get the latest development deployment
DEV_ID=$(curl -sf "http://localhost:47080/api/v1/apps/$APP_ID/deployments?page_size=1" \
  | jq -r '.deployments[0].id')
 
curl -X POST http://localhost:47080/api/v1/deployments/$DEV_ID/promote \
  -H 'Content-Type: application/json' \
  -d '{"strategy":"instant","environment":"production"}'
// 201 Created
{ "deployment_id": "uuid", "message": "Deployment created and scheduler notified" }

Poll the returned deployment_id to track the new deployment's status.

POST /api/v1/deployments//cancel

Cancels a pending or running deployment. Returns the updated deployment object.

Logs

GET /api/v1/deployments//logs

Fetch stored log entries for all tasks in the deployment.

curl http://localhost:47080/api/v1/deployments/$DEPLOY_ID/logs | jq '.[] | .message'

GET /api/v1/deployments//logs/stream

Live log stream as Server-Sent Events. Connect with Accept: text/event-stream.

curl -N -H 'Accept: text/event-stream' \
  http://localhost:47080/api/v1/deployments/$DEPLOY_ID/logs/stream

In JavaScript:

const evtSource = new EventSource(
  `http://localhost:47080/api/v1/deployments/${deploymentId}/logs/stream`
);
evtSource.onmessage = (e) => {
  const entry = JSON.parse(e.data);
  console.log(`[${entry.timestamp}] ${entry.message}`);
};

GET /api/v1/deployments//tasks

List the task instances (replicas) for this deployment. See Tasks.

Webhooks

POST /api/v1/webhooks/github

GitHub sends push and pull-request events here. The platform verifies X-Hub-Signature-256 against the webhook secret in source config, then triggers a deploy on matching push events.

See also

  • Builds & artifacts — build from source or upload binaries manually
  • Tasks — inspect and stop individual running replicas
  • Applications — source config, env vars, custom domains