Deployments API
Trigger publishes, query rollbacks, and stream pipeline events.
The deployments surface covers preview builds, production publishes, and pipeline event streams. Paths are unprefixed and rooted at https://api.showly.ai (there is no version prefix).
Create a deployment
POST /sites/{siteId}/deploy
Authorization: Bearer <token>
Idempotency-Key: <uuid>
Content-Type: application/json
{
"environment": "preview",
"commitSha": "abc123...",
"branch": "main"
}
This is the only route that creates a deployment (siteId is in the path; there is no POST /deployments). It requires an Idempotency-Key header — a missing key returns 428, and a replayed key that conflicts returns 409. It returns 202 + a deployment record in queued state. The build runs asynchronously; subscribe to events or poll the deployment record.
{
"ok": true,
"data": {
"id": "8c9d3e2a-4f1b-4c6d-9a2e-1f0b3c4d5e6f",
"siteId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"target": "preview",
"status": "queued",
"createdAt": "2026-05-14T15:00:00Z"
}
}
The environment field on a deployment record is named target and is one of preview, staging, or production.
Publish to production
Production publishes use the same endpoint with environment: "production" and a sourceDeploymentId naming the already-built ready preview being promoted:
POST /sites/{siteId}/deploy
Authorization: Bearer <token>
Idempotency-Key: <uuid>
Content-Type: application/json
{
"environment": "production",
"sourceDeploymentId": "dep_01HZX..."
}
Production publish does not require OTP or MFA enrollment. It still requires an explicit publish action and, on plans with approval workflows (Team/Enterprise), a second-person approval. Agents use request_publish on approval-workflow plans or the two-step publish_site confirmation on self-serve plans.
Get a deployment
GET /deployments/{deploymentId}
A deployment status is exactly one of five values:
queued → building → ready
↘ failed
↘ canceled
ready is the terminal success state for both preview and production deployments; failed and canceled are the terminal failure states. There is no built or live status. A ready preview deployment carries its address in the url field; a ready production deployment serves the site's production route.
Stream build progress
Live build progress streams over SSE from the previews surface:
GET /previews/{deploymentId}/stream
Accept: text/event-stream
The stream emits status transitions and closes when the deployment reaches a terminal state. For post-hoc reads, two plain endpoints cover most needs:
GET /deployments/{deploymentId}/log?lineCount=200— the captured build log tail.GET /deployments/{deploymentId}/diagnostics— a structured failure bundle (stage, error code, log tail, ranked hypotheses) designed for agent self-debugging.
Approve / reject a production publish request
POST /approvals/{requestId}/decision
Content-Type: application/json
{
"decision": "approve" | "reject",
"notes": "looks good"
}
Requires an active user membership with an allowed approval role. The originating actor is forbidden from approving their own request (separation of duties).
Rollback
There is no rollback REST endpoint. Reverting to a prior deployment is a web-UI operation only. To re-publish a previously ready Preview, call POST /sites/{siteId}/deploy with environment: "production" and that deployment's id as sourceDeploymentId; normal approval, quota, and security gates still apply, but OTP enrollment is not required.
List deployments
GET /deployments
Returns the full deployment list for your workspace as a plain array — there are no filter or pagination parameters yet. For a single site's history, use GET /sites/{siteId}/deployments.
Errors specific to deployments
| Code | Status | Meaning |
|---|---|---|
idempotency_key_required | 428 | POST /sites/{siteId}/deploy was called without an Idempotency-Key header. |
idempotency_key_conflict | 409 | The supplied Idempotency-Key was already used with a different request. |
deployment_not_found | 404 | Token can't see this deployment. |
approval_required | 428 | Production publish needs an approval before it can promote. |
source_deployment_required | 428 | Production publish must name the ready preview via sourceDeploymentId. |
self_approval_forbidden | 403 | Approver is the originating actor (separation of duties). |
source_deployment_not_found | 404 | The sourceDeploymentId doesn't exist or isn't visible to your token. |
source_deployment_not_ready | 409 | The named source deployment isn't in a publishable (ready) state. |
Exhausting the monthly deploy quota returns 402 with a quota error — upgrade the plan or wait for the monthly reset.
Patterns
Wait for a deployment to finish (CI):
DEP=$(curl ... | jq -r .data.id)
while :; do
S=$(curl -sS .../deployments/$DEP | jq -r .data.status)
[ "$S" = "ready" ] && break
{ [ "$S" = "failed" ] || [ "$S" = "canceled" ]; } && exit 1
sleep 10
done
Read the build log:
curl -sS ".../deployments/$DEP/log?lineCount=500" \
| jq -r '.data.lines[]' | tee build.log
For most automation, the [MCP create_preview tool](/docs/mcp/tool-reference) is simpler — the REST API exists for the cases MCP doesn't fit.