Upload a Deploy

POST /v1/applications/{uuid}/deploys

Upload a new version of a static app as a .zip of built files (with index.html at the publish-dir root). The archive is staged and a build job is enqueued; the build runs asynchronously in the background. Send multipart/form-data with a single file field.

For a fullstack app, zip the whole project: the backend at the root and the front end in its own folder — the output folder of a build Ngris runs (dist/, build/, out/…) or, with no build, public/ (or the app's publish_dir). Only that folder is published. Without one the deploy fails (its error says why) and nothing is published — see Full-stack project layout.

Request (multipart/form-data)

file file (.zip)
Required. A .zip of your site — source (Ngris builds it) or built files. At most 100 MB per upload; the account's storage quota applies too.
version string
Optional display label (max 64 chars), e.g. v2.1.0. When unset the display falls back to the git commit short SHA (git deploys) or v{n} (uploads).
activate boolean
Optional. When true the build goes live once it's ready (the normal behaviour). Pass a falsey value (false, 0, no, off) to build a candidate instead: it still builds, but production is untouched — turn on its preview URL to check it, then promote it when you're ready. When omitted: true, or false when the app has require_manual_promotion on.

Per-app environment variables are injected into the build; watch it live via the build log.

Response (202 Accepted)

The new deploy, with the deploy fields of the list except the list-only preview_url, display_version, pruned and rollbackable:

uuid string (uuid)
The new deploy's identifier (the {deploy_uuid} of activate and the build log).
application_uuid, account_uuid string (uuid)
The app and the account the deploy belongs to.
trigger_type string
upload.
status string
queued — poll the list until it reaches ready.
auto_activate boolean
false for a candidate (see activate).

Deprecated: until the sunset deploy objects also carry the legacy integer id and *_id fields. Don't use them; read uuid and the *_uuid fields.

Errors

400 / 413
Missing/non-zip file (400) or a body over the size limit or not valid multipart (413).
403
Storage quota exceeded.
409
The app is paused over a plan limit (quota_paused).
502
Staging the archive in storage failed; the deploy is marked failed. Retry.
503
Object storage is not configured, or another deploy is being started for the account at the same moment (retry).
Request
curl -X POST "https://api.ngris.com/v1/applications/019be838-d261-7d9b-9499-71995a3a91c6/deploys" \ -H "X-API-KEY: <your_api_key>" \ -F "file=@dist.zip"
Request — build a candidate (don't go live)
curl -X POST "https://api.ngris.com/v1/applications/019be838-d261-7d9b-9499-71995a3a91c6/deploys" \ -H "X-API-KEY: <your_api_key>" \ -F "file=@dist.zip" \ -F "activate=false"
Response — 202 Accepted
{ "uuid": "019bfcc3-acae-71e4-a084-e58362ea942d", "application_uuid": "019be838-d261-7d9b-9499-71995a3a91c6", "account_uuid": "019a68b9-1a79-7820-a884-41f554aba6bd", "version": 3, "trigger_type": "upload", "status": "queued", "size_bytes": 1048576, "file_count": 0, "preview_enabled": false, "auto_activate": true, "created_at": "2026-07-28T12:10:00Z", "updated_at": "2026-07-28T12:10:00Z" }

List Deploys

GET /v1/applications/{uuid}/deploys

List an app's deploys, newest first (highest version first), one page at a time. Poll this after an upload or a git push to watch a build progress.

Query parameters

page int
1-based page number. Default 1.
page_size int
Deploys per page. Default 15, max 200 (larger values are clamped).

Response (200 OK)

deploys array
This page's deploys (fields below); [] when there are none.
page int
The page that was returned.
page_size int
The effective page size.
total int
The app's deploys across all pages.

Deploy fields

uuid string (uuid)
Deploy identifier (used to activate + fetch the build log).
application_uuid, account_uuid string (uuid)
The app and the account the deploy belongs to.
version int
Monotonic version number.
display_version string
The label to show: your version_label if set, else the git commit short SHA (git), else v{version}.
version_label string?
The optional label you set on the deploy. Omitted when unset.
preview_enabled boolean
Whether the deploy's public preview URL is on. Off by default; turn it on per deploy with POST …/preview (branch previews turn it on themselves).
preview_url string?
Shareable, read-only preview URL (https://<deploy uuid>.<your plan's domain>) — independent of which version is live. Present only while preview_enabled is on and the deploy is ready/superseded.
preview_alias, preview_expires_at string?, datetime?
Branch previews only: the stable per-branch host label (it always serves the branch's newest preview) and when the preview expires. Omitted for other deploys. See Previews.
trigger_type string
upload, git_manual, or git_push.
status string
queued → processing → ready (or failed); a replaced live version becomes superseded. Managed backends add the finer states building → image_ready → rolling_out.
auto_activate bool
Whether this deploy goes live automatically once built. true is the default; false marks a candidate — a build made with activate=false (or while the app has require_manual_promotion on) that stays off production until you promote it. Use it to tell a candidate apart from a live build.
rollbackable bool
true when this deploy can be activated / rolled back to / promoted — it is a terminal, built version (ready/superseded), not pruned, and not already the live version.
pruned bool
true once the retention policy has deleted this deploy's build artifact (static bundle or OCI image). The row survives for history, but it can no longer be rolled back to. pruned_at (datetime) says when; omitted until then.
size_bytes / file_count int
Total bytes and file count (set once built).
git_sha, branch string?
Git deploys: the deployed commit and the branch it was built from. Omitted for uploads.
image_ref string?
Managed / fullstack apps: the immutable, digest-pinned image the deploy runs (enables instant rollback). Omitted for static deploys and until the image is built.
signature, scan_result, scan_report string?
Managed / fullstack apps: the image's signature, its vulnerability-scan verdict (pending, pass or blocked — a blocked image never rolls out) and the scan's report. Omitted for static deploys and until the scan has run.
platform_image_key string?
Set on a deploy that runs a platform-provided image (managed WordPress: wordpress) rather than one built from your code. Omitted otherwise.
error string?
Build failure reason when status = failed — or read the full build log. Omitted otherwise.
created_at, updated_at datetime
RFC 3339 UTC timestamps.
Retention window. Only the newest N terminal deploys stay rollbackable (the deploy_max_rollback_versions entitlement, per plan). Older deploys are pruned — their artifacts are deleted and rollbackable is false. The live version is always kept.
Candidates vs. live builds. auto_activate lets you tell them apart: a deploy created with activate=false (a candidate) has auto_activate: false and never touched production — it just built; turn on its preview to get a preview_url. Promote it with activate when it checks out. Note that “live” only exists once the app has a production endpoint; an app with deploys but no attached endpoint just has builds.
Response — 200 OK
{ "deploys": [ { "uuid": "019bfcc3-acae-71e4-a084-e58362ea942d", "application_uuid": "019be838-d261-7d9b-9499-71995a3a91c6", "account_uuid": "019a68b9-1a79-7820-a884-41f554aba6bd", "version": 2, "display_version": "v2.1.0", "version_label": "v2.1.0", "trigger_type": "git_push", "git_sha": "9fceab1c4e2d7a8b6f3e1d0c9b8a7f6e5d4c3b2a", "branch": "main", "status": "ready", "preview_enabled": true, "preview_url": "https://019bfcc3-acae-71e4-a084-e58362ea942d.ngris.dev", "auto_activate": true, "rollbackable": false, "pruned": false, "size_bytes": 1048576, "file_count": 42, "created_at": "2026-07-28T12:12:00Z", "updated_at": "2026-07-28T12:13:10Z" }, { "uuid": "019bf3d2-0116-7612-9567-75a812bf45fc", "application_uuid": "019be838-d261-7d9b-9499-71995a3a91c6", "account_uuid": "019a68b9-1a79-7820-a884-41f554aba6bd", "version": 1, "display_version": "v1", "trigger_type": "upload", "status": "superseded", "preview_enabled": false, "auto_activate": true, "rollbackable": true, "pruned": false, "size_bytes": 1036288, "file_count": 41, "created_at": "2026-07-28T12:10:00Z", "updated_at": "2026-07-28T12:12:40Z" } ], "page": 1, "page_size": 15, "total": 2 }

Activate (Restart / Rollout / Rollback)

POST /v1/applications/{uuid}/deploys/{deploy_uuid}/activate

Make any built, non-current deploy the live one — promote a newer candidate, roll back to an older version, or restart the current one. There is no separate promote endpoint: it's the same call either way. For static apps this is an atomic pointer flip; for managed / fullstack apps it re-rolls the pod onto that deploy's digest-pinned image. A pruned version can't be activated (409).

See the full reference on the dedicated page: Activate (Promote / Roll back / Restart).

Request
curl -X POST \ "https://api.ngris.com/v1/applications/019be838-d261-7d9b-9499-71995a3a91c6/deploys/019bf3d2-0116-7612-9567-75a812bf45fc/activate" \ -H "X-API-KEY: <your_api_key>" \ -H "Content-Type: application/json"
Response — 200 OK (static app)
{ "status": "ok", "current_deploy_uuid": "019bf3d2-0116-7612-9567-75a812bf45fc" }
Response — 200 OK (managed / fullstack app)
{ "status": "rolling_out", "deploy_uuid": "019bf3d2-0116-7612-9567-75a812bf45fc" }

Redeploy

POST /v1/applications/{uuid}/redeploy

Rebuild and re-ship the application — an upload app from its last uploaded source, a git app from the latest commit of its production branch — with no re-upload or push needed. For an upload app the source of its newest deploy (highest version) is reused, a fresh deploy is created, and a build job is enqueued (a static bundle rebuild, or a signed image rebuild for managed / fullstack apps). Useful to pick up a changed environment variable, changed build settings or a base-image refresh without re-sending the archive. Every redeploy builds with the app's current build settings, and for a managed, fullstack or function app it always builds a fresh image.

For a git app it builds the head of the configured branch, like the first deploy on connect, so it works while push-to-deploy is off (auto_deploy false) and to retry a failed build.

Request (multipart/form-data, optional)

activate boolean
Optional. A falsey value (false, 0, no, off) rebuilds a candidate — it builds without disturbing production. Promote it afterward. Omit the body entirely to redeploy live as before (or as a candidate when the app has require_manual_promotion on).

Response (202 Accepted)

deploy object
The newly created deploy (uuid, version, status: "queued", auto_activate, …). Poll list deploys or the build log for progress.
status string
queued.

Errors

403
Storage quota exceeded.
409
An upload app with no prior deploy to rebuild from, or the app is paused over a plan limit.
503
Object storage is not configured on this deployment, or another deploy is being started for the account at the same moment (retry).
Request
curl -X POST \ "https://api.ngris.com/v1/applications/019be838-d261-7d9b-9499-71995a3a91c6/redeploy" \ -H "X-API-KEY: <your_api_key>" \ -H "Content-Type: application/json"
Request — rebuild a candidate (don't go live)
curl -X POST \ "https://api.ngris.com/v1/applications/019be838-d261-7d9b-9499-71995a3a91c6/redeploy" \ -H "X-API-KEY: <your_api_key>" \ -F "activate=false"
Response — 202 Accepted
{ "deploy": { "uuid": "019c0a41-5d2e-7b88-8f13-c6e2a4d97b05", "version": 12, "status": "queued", "auto_activate": true }, "status": "queued" }
Was this helpful?