POST requests. Each request follows
Standard Webhooks, so any of its libraries
can check it.
Create an endpoint
whsec_ and the base64 of
random bytes. Store it now: it is shown on create and on rotate only, and a
retry with the same idempotency key answers secret: null. Send a secret of
your own (whsec_ and the base64 of 24 to 64 bytes) to keep one you already
have.
Endpoints and deliveries take a secret key, as runs do. On the console’s
address, /webhook_endpoints and /webhook_deliveries with ?projectId=
serve the project’s admins and developers, signed in or through OAuth.
Paths
Underhttps://<slug>.<project-domain>/workflows/v1:
Every write takes an
Idempotency-Key header. A retry with the same key and
body never repeats the write: it answers the first result again, or
409 conflict when the first attempt was made but its answer was lost (a
5xx or a dropped connection). Read the endpoint or the deliveries to see
what it did. The SDK names them client.webhooks.endpoints and
client.webhooks.deliveries.
Endpoint URLs
The URL must behttps, at most 2,048 characters, with no user, password or
fragment, and name a public host: an IP address, localhost and cloud metadata
hosts are refused. A refused URL is 422 webhook_url_invalid, with reason
naming the rule:
Each address the host resolves to is checked again when a request is sent, so
a name that later points at a private network is not reached.
Events
An endpoint receives only the event types it lists:
Each request’s body is
{ "type", "timestamp", "data" }, with the event’s own
data. A body over 64 KiB is sent with
data: { "eventId", "subjectId", "truncated": true } instead; read the event
from its own API.
Order is not guaranteed: use timestamp to order events, and webhook-id,
the same on every retry and redelivery, to drop a repeat.
Check a request
Three headers sign each request:
Check the raw body, before any JSON parsing:
2xx within 15 seconds to take it; do slow work after answering.
Retries
A request that times out, cannot connect, or answers408, 429 or 5xx is
tried again: immediately, then after 5 seconds, 5 minutes, 30 minutes, 2
hours, 5 hours, 10 hours and 10 hours, each wait spread by up to a fifth
either way. A Retry-After header on 429 or 503 is honoured, up to an
hour. A redirect or any other 4xx stops the delivery (dead), and 410 Gone also turns the endpoint off.
When every attempt is used the delivery is exhausted and the project emits
webhooks/delivery.exhausted. An endpoint whose every attempt has failed for
5 days is turned off with disabledReason: "failing" and
webhooks/endpoint.disabled is emitted; turn it on again with
PATCH { "enabled": true }.
When your receiver answers 429, 502 or 504, the endpoint is slowed:
every endpoint answer then carries throttleDelayMs, the pause in
milliseconds, and throttledUntil, when it ends. The endpoint is slowed while
throttleDelayMs is above 0, even when throttledUntil has passed. Both are
left out when the endpoint is not slowed.
A delivery is pending, failed (waiting for its next attempt),
succeeded, exhausted or dead. Redeliver any of them; one being sent at
that moment is 409 conflict.
Rotate a secret
POST /webhook_endpoints/{id}/rotate_secret answers a new secret once. The
old one keeps signing beside it for 24 hours, so your receiver can move over;
send overlapHours from 0 to 168 to change that, 0 to stop the old secret
at once. A retry with the same Idempotency-Key does not rotate again, so the
secret your receiver holds keeps signing until the overlap ends. If that retry
is 409 conflict, the rotation’s new secret is not shown again: rotating once
more gives you one, but stops your receiver’s secret at once.
Send from a workflow
webhook.send(id, input) in a workflow’s handler is a step: it sends once,
and the handler running again for later steps sends nothing more. It takes an
endpoint or a URL, never both:
type is custom when left out; otherwise words of letters, digits and _
joined by ., at most 256 characters. The endpoint receives it whatever
event types it lists. Its webhook-id is the delivery’s id, it is retried,
throttled and counted toward the endpoint’s health like any delivery, and it
shows in the delivery log with the event type custom. To an endpoint that
is turned off the delivery is dead.
The step resolves once the send is stored, before the request goes out. An
endpoint id the project does not have, a type on a URL send, a bad type,
data that is not JSON, or a body over 64 KiB is never sent: the run fails with
error.code step_failed and the reason as its message.
MCP tools
Both MCP servers offer these tools, as they do the workflows tools: the project server lists the write tools only while MCP writes are on for the project’s workflows. None takes or shows a signing secret: read a new endpoint’s secret by rotating it through the API.
Errors are listed in the REST reference.