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": "dep_01HZX...",
"siteId": "site_01HZX...",
"environment": "preview",
"status": "queued",
"createdAt": "2026-05-14T15:00:00Z"
}
}
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 is gated by step-up MFA and an approval. This means it cannot be driven from a token-only REST or CI client: the publish must be requested and approved from a human web session. Agents reach this path through the MCP request_publish tool, which returns a webApprovalUrl deep link to the web approval screen. Use the decision endpoint below to record an approve/reject once a request exists.
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 a previewUrl; a ready production deployment serves the site's production route.
Stream pipeline events
GET /deployments/{deploymentId}/events
Accept: text/event-stream
Server-sent events, one event per pipeline state transition + log batch:
event: status
data: { "status": "building", "at": "..." }
event: log
data: { "stream": "build", "lines": [...] }
event: status
data: { "status": "ready", "previewUrl": "https://preview-xxx.showly.app" }
The stream closes when the deployment reaches a terminal state.
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 revert programmatically, re-publish the previously-ready deployment by calling POST /sites/{siteId}/deploy with environment: "production" and that deployment's id as sourceDeploymentId (still subject to step-up MFA and approval).
List deployments
GET /deployments?siteId=...&environment=production&limit=50
Supports cursor pagination. Filter by status, siteId, environment, since, until. Scoped per-site listing is also available at 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_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). |
build_quota_exceeded | 429 | Workspace hit its concurrent-build limit. Branch on error.code — this 429 does NOT carry a Retry-After header and will not clear on a timer. |
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
Stream logs to a file:
curl -N .../deployments/$DEP/events \
| grep -A1 'event: log' \
| 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.