API reference
Deployments
List deployments, read build and runtime logs, redeploy and promote.
See Builds and Environments for how deployments are created by pushes and what each status means.
POST /v1/protection/token
A two-minute sign-in link to a protected deployment URL for the signed-in person: they need deployments:read in the deployment's organization. People only, not keys.
Auth: user access token or platform agent key · Allowed: deployments:read
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
host | string | Yes | 1–253 characters; trimmed |
next | string | No | up to 2,048 characters |
Response 200
{
url: string
}Errors
| Status | Message |
|---|---|
403 | Only people can open protected deployments. |
403 | You don't have access to this deployment. Ask an owner of its organization to invite you. |
404 | Deployment not found. |
POST /v1/orgs/:orgId/projects/:projectId/uploads
A presigned PUT URL (15 minutes) for one source archive of size bytes (gzipped tar, at most 250 MB). Send the archive with exactly the returned headers, then start a deployment with the uploadId.
Auth: user access token or platform agent key · Scope: deployments:write
| Path parameter | Description |
|---|---|
:orgId | Organization id (org_…). |
:projectId | Serverless App Service id (prj_…). |
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
size | integer | Yes | 1–262144000 |
Response 201
{
uploadId: string
url: string
headers: {
"content-type": string
"content-length": string
}
expiresIn: number
}Errors
| Status | Message |
|---|---|
404 | Serverless App Service not found |
POST /v1/orgs/:orgId/projects/:projectId/uploads/plan
Plans an upload from the working tree's index (files: path → "<mode> <blob id>", at most 50,000). skip: a ready deployment of the same files and build inputs (none with force); else base and need: an earlier full upload to send only the changed files on top of; else neither (upload it whole). Writes nothing.
Auth: user access token or platform agent key · Scope: deployments:write
| Path parameter | Description |
|---|---|
:orgId | Organization id (org_…). |
:projectId | Serverless App Service id (prj_…). |
Request body
| Field | Type | Required | Default | Notes |
|---|---|---|---|---|
target | "production" | "preview" | Yes | ||
files | object | Yes | values: string | |
force | boolean | No | false |
Response 200
{
tree: string
skip: {
deploymentId: string
host?: string
}
}
| {
tree: string
}
| {
tree: string
base: {
uploadId: string
}
need: string[]
}Errors
| Status | Message |
|---|---|
400 | The file list can't be used (over 50,000 files, or odd paths): upload the whole tree. |
404 | Serverless App Service not found |
POST /v1/orgs/:orgId/projects/:projectId/deployments
Starts a deployment of the Serverless App Service. git: a commit of the linked repository on branch, with target (default: production for the production branch, else preview); a commit that already has a building or ready deployment for that target returns it (200) unless force. upload: the archive uploaded with uploadId, built as target.
Auth: user access token or platform agent key · Scope: deployments:write
| Path parameter | Description |
|---|---|
:orgId | Organization id (org_…). |
:projectId | Serverless App Service id (prj_…). |
Request body
| Field | Type | Required | Default | Notes |
|---|---|---|---|---|
source | "git" | "upload" | Yes | ||
branch | string | No | 1–255 characters; trimmed | |
commitSha | string | No | matches ^[0-9a-f]{40}$ | |
uploadId | string | No | matches ^up_[A-Za-z0-9_-]{16,64}$ | |
target | "production" | "preview" | No | ||
force | boolean | No | false | |
manifest | object | No | values: any JSON | |
files | object | No | values: string | |
base | string | No | matches ^up_[A-Za-z0-9_-]{16,64}$ | |
skip | string | No | 1–64 characters | |
meta | object | No | ||
meta.branch | string | No | up to 255 characters | |
meta.commit | string | No | matches ^[0-9a-f]{7,40}$ | |
meta.dirty | boolean | No | ||
meta.machine | string | No | up to 64 characters |
Response 200
{
deployment: {
deploymentId: string
host?: string
target: "preview" | "production"
}
existing: true
}Response 201
{
deployment: {
deploymentId: string
host: string
target: "preview" | "production"
}
existing: false
}
| {
deployment: {
deploymentId: string
host?: string
target: "preview" | "production"
}
existing: false
skipped: true
}Errors
| Status | Message |
|---|---|
400 | A git deployment needs branch and commitSha. |
400 | An upload deployment needs a target. |
400 | The file list can't be used (over 50,000 files, or odd paths). |
400 | A skip needs the file list. |
400 | An upload deployment needs uploadId and target. |
400 | A delta needs the file list. |
404 | Serverless App Service not found |
404 | Not found |
404 | Commit not found |
409 | Link a repository to this Serverless App Service first. |
409 | Something changed since the plan: upload the files. |
409 | The upload wasn't found. Upload the archive first. |
409 | The base upload is gone or isn't a full upload: upload the whole tree. |
413 | The archive is larger than 250 MB. |
502 | Couldn't start the build. Try again. |
GET /v1/orgs/:orgId/deployments/:deploymentId/build-log
Build output after cursor (from the first step on), with the deployment's status. Poll with the returned cursor until done: the deployment has finished and no output is left.
Auth: user access token or platform agent key · Scope: logs:read
| Path parameter | Description |
|---|---|
:orgId | Organization id (org_…). |
:deploymentId | Deployment id (dpl_…). |
| Query parameter | Type | Required | Notes |
|---|---|---|---|
cursor | string | No | up to 2,048 characters |
Response 200
{
lines: []
cursor: null | string
status: "error" | "queued" | "building" | "deploying" | "ready" | "canceled" | "expired" | "skipped"
error: null | string
done: boolean
}
| {
status: "error" | "queued" | "building" | "deploying" | "ready" | "canceled" | "expired" | "skipped"
error: null | string
done: boolean
lines: {
t: number
m: string
}[]
cursor: string
}Errors
| Status | Message |
|---|---|
404 | Deployment not found |
GET /v1/orgs/:orgId/deployments/:deploymentId/runtime-logs/tail
Server function log events from since (epoch ms, at most an hour back; default the last minute) to now, oldest first, with event ids. q filters case-insensitively. Poll again from next, re-reading a few seconds (late events) and skipping ids already seen.
Auth: user access token or platform agent key · Scope: logs:read
| Path parameter | Description |
|---|---|
:orgId | Organization id (org_…). |
:deploymentId | Deployment id (dpl_…). |
| Query parameter | Type | Required | Notes |
|---|---|---|---|
since | integer | No | ≥ 0; coerced from a string |
q | string | No | up to 200 characters; trimmed |
Response 200
{
available: false
lines: []
next: number
more: false
}
| {
lines: {
id: string
t: number
level: "error" | "platform" | "warn" | "info" | "debug"
requestId?: string
message: string
truncated?: boolean
}[]
next: number
more: boolean
available: true
}Errors
| Status | Message |
|---|---|
404 | Deployment not found |
GET /v1/orgs/:orgId/deployments
Lists deployments across Serverless App Services, newest first. Pass the returned cursor to get the next page.
Auth: user access token or platform agent key · Scope: deployments:read
| Path parameter | Description |
|---|---|
:orgId | Organization id (org_…). |
| Query parameter | Type | Required | Default | Notes |
|---|---|---|---|---|
projectId | string | No | at least 1 character | |
target | "production" | "preview" | No | ||
status | "queued" | "building" | "deploying" | "ready" | "error" | "canceled" | "expired" | "skipped" | No | ||
branch | string | No | 1–255 characters | |
cursor | string | No | at least 1 character | |
limit | integer | No | 50 | 1–100; coerced from a string |
Response 200
{
deployments: {
region?: string
error?: string
status?: "error" | "queued" | "building" | "deploying" | "ready" | "canceled" | "expired" | "skipped"
createdAt?: number
updatedAt?: number
orgId: string
createdBy?: string
projectId: string
reason?: string
location: string
edgeOnly?: boolean
deploymentId: string
target: "preview" | "production"
branch?: string
commitSha?: string
commitMessage?: string
commitAuthor?: string
host?: string
buildId?: string
server?: "node"
buildLogGroup?: string
builtOrgId?: string
buildDurationMs?: number
readyAt?: number
envTarget?: "preview" | "production"
memoryMb?: number
timeoutSeconds?: number
crons?: string
envHash?: string
previousDeploymentId?: string
source?: "git" | "upload"
sourceArchive?: string
sourceBase?: string
sourceTree?: string
sourceManifest?: string
buildMetrics?: {
restoreMs?: number
installMs?: number
buildMs?: number
uploadMs?: number
saveMs?: number
depsCache?: "hit" | "partial" | "miss" | "off"
nextCache?: "hit" | "partial" | "miss" | "off"
packageManager?: string
installDir?: string
}
}[]
cursor: null | string
}Errors
| Status | Message |
|---|---|
404 | Serverless App Service not found |
404 | Not found |
404 | Commit not found |
GET /v1/orgs/:orgId/deployments/:deploymentId
A deployment and a summary of its Serverless App Service.
Auth: user access token or platform agent key · Scope: deployments:read · Allowed: domains:read
| Path parameter | Description |
|---|---|
:orgId | Organization id (org_…). |
:deploymentId | Deployment id (dpl_…). |
Response 200
{
deployment?: {
region?: string
error?: string
status?: "error" | "queued" | "building" | "deploying" | "ready" | "canceled" | "expired" | "skipped"
createdAt?: number
updatedAt?: number
orgId: string
createdBy?: string
projectId: string
reason?: string
location: string
edgeOnly?: boolean
deploymentId: string
target: "preview" | "production"
branch?: string
commitSha?: string
commitMessage?: string
commitAuthor?: string
host?: string
buildId?: string
server?: "node"
buildLogGroup?: string
builtOrgId?: string
buildDurationMs?: number
readyAt?: number
envTarget?: "preview" | "production"
memoryMb?: number
timeoutSeconds?: number
crons?: string
envHash?: string
previousDeploymentId?: string
source?: "git" | "upload"
sourceArchive?: string
sourceBase?: string
sourceTree?: string
sourceManifest?: string
buildMetrics?: {
restoreMs?: number
installMs?: number
buildMs?: number
uploadMs?: number
saveMs?: number
depsCache?: "hit" | "partial" | "miss" | "off"
nextCache?: "hit" | "partial" | "miss" | "off"
packageManager?: string
installDir?: string
}
}
project: {
projectId: string
name: string
slug: string
productionDeploymentId?: string
repoId?: string
framework?: "static" | "nextjs" | "node"
location: string
rootDirectory?: string
}
productionHost?: string
domains?: {
hostname: string
status?: "error" | "active" | "pending" | "verifying"
redirectTo?: string
}[]
function: null | {
region: string
name: string
memoryMb: number
timeoutSeconds: number
architecture: "arm64"
runtime: "nodejs22.x"
}
}Errors
| Status | Message |
|---|---|
404 | Deployment not found |
404 | Serverless App Service not found |
404 | Not found |
404 | Commit not found |
GET /v1/orgs/:orgId/deployments/:deploymentId/logs
Build output, starting at the first build step.
Auth: user access token or platform agent key · Scope: logs:read
| Path parameter | Description |
|---|---|
:orgId | Organization id (org_…). |
:deploymentId | Deployment id (dpl_…). |
Response 200
{
lines: {
t?: number
m: string
}[]
}Errors
| Status | Message |
|---|---|
404 | Deployment not found |
GET /v1/orgs/:orgId/deployments/:deploymentId/runtime-logs
Server function logs, newest first, at most 500 per page. range (1h, 6h, 24h, 7d; default 1h) bounds how far back; pass the returned older as before for the next page; after returns only newer events (live tail). q filters messages case-insensitively. available is false for deployments without a server function.
Auth: user access token or platform agent key · Scope: logs:read
| Path parameter | Description |
|---|---|
:orgId | Organization id (org_…). |
:deploymentId | Deployment id (dpl_…). |
| Query parameter | Type | Required | Notes |
|---|---|---|---|
q | string | No | up to 200 characters; trimmed |
range | `` | No | |
before | integer | No | > 0; coerced from a string |
after | integer | No | > 0; coerced from a string |
Response 200
{
available: false
lines: []
}
| {
older?: number
lines: {
id?: string
t: number
level: "error" | "platform" | "warn" | "info" | "debug"
requestId?: string
message: string
truncated?: boolean
}[]
from: number
to: number
limited: boolean
available: true
}Errors
| Status | Message |
|---|---|
404 | Deployment not found |
POST /v1/orgs/:orgId/deployments/:deploymentId/redeploy
Builds the deployment's commit again as a new deployment with the same target.
Auth: user access token or platform agent key · Scope: deployments:write
| Path parameter | Description |
|---|---|
:orgId | Organization id (org_…). |
:deploymentId | Deployment id (dpl_…). |
Response 201
{
deployment: {
deploymentId: string
host: string
target: "preview" | "production"
}
}Errors
| Status | Message |
|---|---|
404 | Deployment not found |
404 | Serverless App Service not found |
409 | This deployment is still in progress. |
409 | This upload has expired. Deploy again from your terminal. |
409 | This deployment has no commit to build. |
409 | Link a repository to this Serverless App Service first. |
502 | Couldn't start the build. Try again. |
POST /v1/orgs/:orgId/deployments/:deploymentId/promote
Makes a ready deployment production without rebuilding: promotes a preview, or rolls back to an earlier production deployment. A promoted preview's function switches to production's variables unless the body is { "env": "preview" }. A rollback holds production there: new production builds don't go live until a deployment is promoted.
Auth: user access token or platform agent key · Scope: deployments:write
| Path parameter | Description |
|---|---|
:orgId | Organization id (org_…). |
:deploymentId | Deployment id (dpl_…). |
Response 200
{
deployment: {
region?: string
error?: string
status?: "error" | "queued" | "building" | "deploying" | "ready" | "canceled" | "expired" | "skipped"
createdAt?: number
updatedAt?: number
orgId: string
createdBy?: string
projectId: string
reason?: string
location: string
edgeOnly?: boolean
deploymentId: string
target: "preview" | "production"
branch?: string
commitSha?: string
commitMessage?: string
commitAuthor?: string
host?: string
buildId?: string
server?: "node"
buildLogGroup?: string
builtOrgId?: string
buildDurationMs?: number
readyAt?: number
envTarget?: "preview" | "production"
memoryMb?: number
timeoutSeconds?: number
crons?: string
envHash?: string
previousDeploymentId?: string
source?: "git" | "upload"
sourceArchive?: string
sourceBase?: string
sourceTree?: string
sourceManifest?: string
buildMetrics?: {
restoreMs?: number
installMs?: number
buildMs?: number
uploadMs?: number
saveMs?: number
depsCache?: "hit" | "partial" | "miss" | "off"
nextCache?: "hit" | "partial" | "miss" | "off"
packageManager?: string
installDir?: string
}
}
productionHost: string
productionHold: boolean
}Errors
| Status | Message |
|---|---|
400 | Invalid request. |
404 | Deployment not found |
404 | Serverless App Service not found |
409 | This deployment has expired. Redeploy it instead. |
409 | Only ready deployments can be promoted. |
409 | This is already the production deployment. |
409 | This deployment's server function was removed. Redeploy it instead. |
502 | Couldn't apply the production environment variables. Production wasn't changed; try again. |
502 | Couldn't update production routing. Try again. |