403 { "error": "Not your project" }; an unknown project is 404.
Register a webhook
urlmust behttpsand publicly routable.http://returns400 "url must use https"; localhost and private ranges return400 "url must be publicly routable".eventsis optional. Omit it to subscribe to all six event types. An unknown event returns400 "Invalid events: ... Valid: ...".- Maximum 10 webhooks per project (
400at the cap).
secret lives inside webhook, not at the top level, and is returned once. Store it; you need it to verify signatures. Listing never returns it again.
List webhooks
lastDeliveryAt and lastStatus (the HTTP status your endpoint last returned) are the health signal. Poll them to spot a failing receiver.
Update a webhook in place
Change the URL or events without minting a new secret. The id stays the same and your receiver keeps verifying. Prefer this over delete and re-register, which mints a new secret and breaks the receiver.{ projectId, id, url?, events?, rotateSecret? }. At least one of url, events, rotateSecret is required (400 otherwise). Unknown id: 404 "Webhook not found".
Rotate the secret
secret inside webhook, shown once. The old secret stops working immediately. In-flight retries are re-signed with the current secret, so rotation never breaks a pending delivery.
Delete a webhook
id. Any other name (webhookId, for example) returns 400 { "error": "id is required" }. An unknown id returns 404 { "error": "Webhook not found" }.
Event types
Phases are named
iteration in the API. The event names and the payload field are the stable API identifier. The product UI calls the same thing a phase.Payload
status: "done" means the job is live in production. You may still see "delivered" on nodes written by older integrations; it is deprecated and means “not done yet”.
Phase events carry iteration instead of node: { "iteration": { "name": "MVP", "status": "done" } }. iteration.updated includes status only when the update changed it; a rename carries { "name": "<new>" } plus previous_name.
Headers
Verifying signatures
Delivery semantics
At-least-once. Every event is persisted before the first attempt, so a receiver that is briefly down never loses it. Delivery is attempted immediately. If your endpoint returns a non-2xx status or does not respond within 5 seconds, the event is retried with exponential backoff, up to 6 attempts in total, then markedfailed.
The backoff between attempts is 2, 4, 8, 16 and 32 minutes (capped at 60). Retries are picked up by a scheduler that runs every 2 minutes, so each wait can be up to 2 minutes longer than the nominal figure. A delivery that fails every attempt is exhausted roughly an hour after the first try.
Because delivery is at-least-once, your receiver must be idempotent. The same event can arrive more than once (for example you process it but acknowledge past the 5-second window). Dedup on X-ProductBrain-Delivery.
- Health monitoring.
GET /webhooksreturnslastDeliveryAtandlastStatusper webhook. - Reconcile failures. A delivery that exhausts all 6 attempts is marked
failedand not retried further. Catch up by readingGET /nodes.

