Webhooks
Start a run of a task, or answer a gate, from any system that can send an HTTP request.
Start a task
Every task has a webhook. POST the run's input as JSON, with your enterprise's webhook secret in a header:
curl -X POST https://api.zerohuman.com/v1/webhooks/{enterprise}/tasks/{task} \
-H "x-os-webhook-secret: $WEBHOOK_SECRET" \
-H "content-type: application/json" \
-d '{"issue": 123}'
{enterprise} is your enterprise's slug and {task} the task's. The task's Triggers panel in the portal shows
its exact URL and a curl to copy, never the secret.
The body is the run's input. If the task is already running when the call arrives, the new run waits until it can start. A webhook starts the task the same way its schedule or a person does: the same version, the same gates, the same spend limits.
Answer a gate
A gate can be decided from outside the portal too:
curl -X POST https://api.zerohuman.com/v1/webhooks/{enterprise}/gates/{gateId} \
-H "x-os-webhook-secret: $WEBHOOK_SECRET" \
-H "content-type: application/json" \
-d '{"decision": "approve", "note": "Ship it."}'
decision is approve, reject or request_changes, and note is optional. The decision is recorded exactly as
one made on Gates is, by the same rules: a gate already decided cannot be decided again. Whoever holds the webhook
secret can approve what goes live, so keep it as close as you would a signing key.
The secret
The secret is your enterprise's own. Every enterprise gets one when it is created, and it is stored only as a hash, so nobody can read it back, the portal included. Settings → Webhooks rotates it and shows the new secret exactly once; the previous one stops working at once. The secret an enterprise starts with is never shown, so using webhooks starts with a rotation.
A wrong secret and an unknown enterprise get the same 401, so a call cannot tell you which enterprises exist.
History and replay
Webhooks in the portal lists every call your enterprise's webhooks received: what was sent (with credentials left out and sensitive fields redacted), what the API answered, what happened next, and a link to the execution it started or continued. A call accepted means the webhook was consumed, not that its work has finished.
A delivery can be replayed: the original request is applied again, through the task's or gate's current rules, as a new delivery linked to the original. Replaying a task starts a new run; replaying a gate decision continues its execution, and a gate already decided refuses it. Calls that never authenticated, deliveries still in progress, and bodies that contain the webhook secret cannot be replayed.
With an API token scoped webhooks:read:
| Call | What it does |
|---|---|
GET /v1/webhooks |
Deliveries, paginated, with search, sorting, and status and kind filters. |
GET /v1/webhooks/{id} |
One delivery: its request, response and what followed. |
POST /v1/webhooks/{id}/replay |
Replay it (webhooks:write). Send { "idempotencyKey": "<uuid>" }: the same key returns the same replay rather than dispatching twice. |