Deploy API
Create API tokens and trigger deployments programmatically from CI, a CMS, or any HTTP client.
The Deploy API lets you trigger a deployment of your project from outside the dashboard — from a CI pipeline, a CMS webhook, or any script that can make an HTTP request. You authenticate with a bearer token that you create on this page.
To open it, go to your project's Settings, and under Integrations click Deploy API.
Note: Managing deploy tokens requires an organization admin role. If you don't have it, you'll be redirected to the project settings page.
Create a token
- Click New token in the top-right.
- In the New deploy token dialog, fill in:
- Name — a label so you remember what the token is for (for example,
GitHub Actions production). It's also shown in deploy notifications. - Scope — choose one of:
- Live deployment — always deploys your project's deploy branch (typically
main) to the production URL. - Preview branch — deploys one specific branch to a preview URL. A Branch field appears for you to name it.
- Any branch in this project — the caller chooses the branch and whether it's live or preview, per request. Useful for A/B variants and CI scripts that build many branches under one token.
- Live deployment — always deploys your project's deploy branch (typically
- Expires in — Never, 7 days, 30 days, 90 days, or 1 year. After it expires, the token stops working and returns a "token expired" error.
- Name — a label so you remember what the token is for (for example,
- Click Create token.
Warning: The token is shown once, right after creation, in a highlighted box with a Copy button. Copy it now and store it somewhere safe — it won't be shown again. If you lose it, revoke it and create a new one.
Treat tokens like passwords: keep them out of source control, and give each integration its own token with the narrowest scope it needs.
Manage existing tokens
Each token appears in the Tokens list with its name, a masked prefix, what it deploys, when it was created, and when it was last used (or Never used). Expired tokens are flagged.
To revoke a token, click Revoke on its row and confirm. The token stops working immediately, so any integration using it will need a new one.
Trigger a deployment
The page shows the exact base URL for your project. It looks like this:
https://<api-host>/v1/projects/<your-project-slug>/deployments
There are two endpoints:
| Method | Path | Purpose |
|---|---|---|
POST |
/v1/projects/<slug>/deployments |
Trigger a new deployment |
GET |
/v1/projects/<slug>/deployments/<deployment-id> |
Poll deployment status |
Authenticate every request by sending your token in the Authorization header:
Authorization: Bearer pdt_...
Trigger with curl
curl -X POST https://<api-host>/v1/projects/<slug>/deployments \
-H "Authorization: Bearer pdt_..." \
-H "Content-Type: application/json" \
-d '{"branch": "main", "triggeredBy": "ci-build-${BUILD_ID}"}'
Trigger with fetch (JavaScript)
const res = await fetch('https://<api-host>/v1/projects/<slug>/deployments', {
method: 'POST',
headers: {
'Authorization': 'Bearer pdt_...',
'Content-Type': 'application/json',
},
body: JSON.stringify({
branch: 'main', // omit for branch-scoped tokens
// isLive: false, // optional override; inferred from branch
triggeredBy: 'ci-build',
}),
})
const { deploymentId, statusUrl } = await res.json()
Trigger with Python
import requests
res = requests.post(
'https://<api-host>/v1/projects/<slug>/deployments',
headers={'Authorization': 'Bearer pdt_...'},
json={
'branch': 'main', # omit for branch-scoped tokens
# 'isLive': False, # optional override; inferred from branch
'triggeredBy': 'ci-build',
},
)
data = res.json()
deployment_id = data['deploymentId']
status_url = data['statusUrl']
Tip: The dashboard's API documentation section has ready-to-copy snippets for curl, fetch, PHP, and Python — and when you've just created a token, the snippets are pre-filled with the real token value.
Request body
POST accepts an optional JSON body (Content-Type: application/json, max 8 KB):
| Field | Type | When | Description |
|---|---|---|---|
triggeredBy |
string | optional | Free-form label shown next to the token name in deploy notifications (max 100 chars). |
branch |
string | required for any branch tokens; ignored for branch-scoped tokens | The branch to deploy. |
isLive |
boolean | optional override | Defaults to true when branch matches the project's deploy branch (typically main), otherwise false. Pass it explicitly only for edge cases. |
For a branch-scoped token (Live deployment or Preview branch), you can omit the body entirely — the token already knows what to deploy.
Response
A successful POST returns 202 Accepted with the deployment id and the URL to poll:
{
"deploymentId": "01J...",
"statusUrl": "https://<api-host>/v1/projects/<slug>/deployments/01J..."
}
Poll deployment status
Send a GET to the statusUrl with the same bearer token:
curl https://<api-host>/v1/projects/<slug>/deployments/<deployment-id> \
-H "Authorization: Bearer pdt_..."
The response reports progress:
{
"deploymentId": "01J...",
"status": "running",
"createdAt": "2026-05-07T12:00:00.000Z",
"startedAt": "2026-05-07T12:00:01.000Z",
"completedAt": null,
"publishedUrl": null,
"errorMessage": null
}
The status field moves through:
pending → queued → running → completed
Or it ends in a terminal failure state:
failed— the build or deploy hit an error; seeerrorMessage.cancelled— a newer deployment for the same branch superseded this one.
When a deployment completes, publishedUrl points at the live result.
Good to know
- Idempotency-Key. To make retries safe, send an
Idempotency-Keyheader. A secondPOSTwithin 24 hours using the same key (and same branch) returns the originaldeploymentIdinstead of creating a duplicate, and the replay carries anIdempotent-Replayed: trueheader. Use a UUID, build id, or content hash (1–200 chars). - Rate limits. Each token is limited to 60 requests per minute; exceeding it
returns
429 Too Many Requests. Bursts to the same branch are coalesced — only the latest deployment runs — while different branches deploy in parallel. - Errors. All errors return JSON shaped like
{"error": {"code": "...", "message": "..."}}. Switch oncodein your scripts; the human-readablemessagemay change. Common codes includemissing_authorization,invalid_token,token_expired,invalid_branch, andrate_limited. - Builds disabled. If the project has managed builds disabled,
a
POSTreturns409with codebuilds_disabled— deploy the site through your own CI instead.
Related
- History and changes — see your deployments in the project's activity log.
- Hosting and domains — point a custom domain at your deployed site.