List Deploy Hooks

GET /v1/applications/{uuid}/deploy-hooks

A deploy hook is a secret URL that deploys the app when something sends it a POST: a git app's hook builds the latest commit of its branch (the production branch deploys to production, another branch builds a preview), an upload app's hook rebuilds the last upload. This lists the app's hooks. A hook's URL is never listed: it is shown once, when the hook is created or its URL replaced.

Response (200 OK)

deploy_hooks array
The app's hooks (fields below); [] when there are none.
max int
The most hooks an app can have (10).

Hook fields

uuid string (uuid)
The hook's id, for rotate and delete.
name string
The name you gave it.
branch string | null
The branch a git app's hook builds; null for an upload app's hook (it rebuilds the last upload).
token_prefix string
The first characters of the hook's URL token (ngdh_ and 7 more), to tell hooks apart.
created_at, last_used_at datetime, datetime | null
When it was created and last called.
last_result string | null
What its last call did: queued, merged (it joined a build of the hook that was still queued), rate_limited, or not_queued: <reason> (for example not_queued: app paused, not_queued: account suspended, not_queued: over a plan quota, not_queued: repository access lost, not_queued: this app has no previews, not_queued: nothing to rebuild, not_queued: try again). The URL itself never tells the caller why.
Request
curl "https://api.ngris.com/v1/applications/019be838-d261-7d9b-9499-71995a3a91c6/deploy-hooks" \ -H "X-API-KEY: <your_api_key>"
Response — 200 OK
{ "deploy_hooks": [ { "uuid": "019c0b77-2e4a-7d10-8c3f-6a9b1e2d4f58", "name": "CMS publish", "branch": "main", "token_prefix": "ngdh_k3Qw9xT", "created_at": "2026-11-02T09:00:00Z", "last_used_at": "2026-11-02T11:42:10Z", "last_result": "queued" } ], "max": 10 }

Create a Deploy Hook

POST /v1/applications/{uuid}/deploy-hooks

Add a hook and get its URL, once: store it as a secret, because anyone who has it can deploy the app. A lost URL can't be shown again; replace it. Needs permission to manage applications.

Request body (application/json)

name string, required
1 to 100 characters, with no control or invisible characters. For example what calls it: CMS publish.
branch string
Git apps: the branch it builds. Omitted: the app's production branch. Another branch builds a preview; on an app without previews (a managed backend, a function) its calls answer not_queued: this app has no previews. Upload apps take none.

Response (201 Created)

uuid, name, branch, token_prefix string
As in the list.
url string
The hook's URL, https://api.ngris.com/v1/webhooks/deploy/ngdh_…. Only in this answer.

Errors

400 Bad Request
“Give the hook a name of 1 to 100 characters, with no control or invisible characters.”, a branch that isn't a valid branch name, or a branch on an upload app's hook.
409 Conflict
The app already has 10 hooks, it is a WordPress site (nothing to deploy), a git app without a connected repository, or the app is paused over a plan limit.
Request
curl -X POST \ "https://api.ngris.com/v1/applications/019be838-d261-7d9b-9499-71995a3a91c6/deploy-hooks" \ -H "X-API-KEY: <your_api_key>" \ -H "Content-Type: application/json" \ -d '{"name": "CMS publish"}'
Response — 201 Created
{ "uuid": "019c0b77-2e4a-7d10-8c3f-6a9b1e2d4f58", "name": "CMS publish", "branch": "main", "token_prefix": "ngdh_k3Qw9xT", "url": "https://api.ngris.com/v1/webhooks/deploy/ngdh_k3Qw9xT…" }

Replace a Hook's URL

POST /v1/applications/{uuid}/deploy-hooks/{hook_uuid}/rotate

Give the hook a new URL, shown once in the answer. The old URL stops working at once, so update whatever calls it. The hook keeps its name, branch and history.

Response (200 OK)

uuid, token_prefix, url string
The hook, its new prefix and its new URL (only in this answer).

Errors

404 Not Found
deploy hook not found.
409 Conflict
The app is paused over a plan limit.
Request
curl -X POST \ "https://api.ngris.com/v1/applications/019be838-d261-7d9b-9499-71995a3a91c6/deploy-hooks/019c0b77-2e4a-7d10-8c3f-6a9b1e2d4f58/rotate" \ -H "X-API-KEY: <your_api_key>"

Delete a Deploy Hook

DELETE /v1/applications/{uuid}/deploy-hooks/{hook_uuid}

Remove the hook; its URL stops working at once. This works on a paused app too.

Response (200 OK)

status string
deleted.

Errors

404 Not Found
deploy hook not found.
Request
curl -X DELETE \ "https://api.ngris.com/v1/applications/019be838-d261-7d9b-9499-71995a3a91c6/deploy-hooks/019c0b77-2e4a-7d10-8c3f-6a9b1e2d4f58" \ -H "X-API-KEY: <your_api_key>"

Call a Deploy Hook

POST /v1/webhooks/deploy/{token}

The hook's URL. No API key: the token in the URL is the credential. Send a POST with any body and any content type; the body is not read. The answer is the same for everyone who calls: it never says which app the hook belongs to or why a build didn't start (the hook's last_result, which your account sees, says why).

Response

202 Accepted
{"status":"queued"}: a build is queued. A call while the hook's previous build is still queued joins it instead of queuing another.
409 Conflict
{"status":"not_queued"}: nothing could start; see the hook's last_result.
429 Too Many Requests
{"status":"rate_limited"} with Retry-After: a hook starts at most one build every 30 seconds and 30 an hour. Calls from one IP address (for IPv6, one /64 network) are also limited to 60 a minute across all hook URLs.
404 Not Found
{"error":"not found"}: the same answer for a URL that never existed, was replaced or deleted, or whose app is gone. A URL created or replaced a moment ago starts working within about a second; retry once if it answers 404 right away.
405 Method Not Allowed
Any method other than POST.
Request
curl -X POST "https://api.ngris.com/v1/webhooks/deploy/ngdh_<secret>"
Response — 202 Accepted
{ "status": "queued" }
Was this helpful?