Register a webhook endpoint
const url = 'https://example.com/v1/webhook-endpoints';const options = { method: 'POST', headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'}, body: '{"url":"https://example.com","events":["run.finished"],"filter":{"projectId":"example","flowIds":["example"],"includeDryRuns":true},"secretRef":{"envName":"example","name":"example"},"description":"example"}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request POST \ --url https://example.com/v1/webhook-endpoints \ --header 'Authorization: Bearer <token>' \ --header 'Content-Type: application/json' \ --data '{ "url": "https://example.com", "events": [ "run.finished" ], "filter": { "projectId": "example", "flowIds": [ "example" ], "includeDryRuns": true }, "secretRef": { "envName": "example", "name": "example" }, "description": "example" }'Registers a URL the platform sends signed events to. The signing secret is shared with the receiver, so it lives in your secrets (.env in development, the secrets store in production) and the endpoint references it by name (secretRef). Store it first; POST /v1/webhook-endpoints/generate-secret makes a strong one. Deliveries are signed in the Standard Webhooks format (webhook-id, webhook-timestamp, webhook-signature); verify with verifyWebhook from @kindgi/crypto or any Standard Webhooks library. The event bodies are described under webhooks in this document.
Authorizations
Section titled “Authorizations”Parameters
Section titled “Parameters”Header Parameters
Section titled “Header Parameters”Caller-supplied idempotency key, scoped to the caller: the same key from someone else in the tenant is their own request (from 0.1.5). Retries with the same key return the original response byte-identical (per docs/API-ROUTE-CONVENTIONS.md §3.1). A retry sent while the first request still runs is answered 409 idempotency-key-in-flight with Retry-After, on a runtime whose store holds keys (from 0.1.5); retry after it, and you get the first request’s answer. An answer that carries a secret (a new API key or public run token, a session token, a generated signing secret) isn’t kept: a retry gets 409 idempotency-key-replay-withheld, with the first request’s status and when it succeeded (from 0.1.5).
Request Bodyrequired
Section titled “Request Bodyrequired”object
Absolute https URL (http only where the deployment allows it, e.g. development). No credentials in the URL. The deployment may refuse private network addresses (400 webhook-url-refused).
Which events reach the endpoint. Every field narrows; absent fields do not. run.finished is sent for top-level runs only.
object
Only runs in this project.
Only runs of these flows (any version).
Dry runs are left out unless this is true.
A secret by name in the deployment’s secrets store, resolved at tenant scope (the same shape as a provider’s secret_ref). The value is whsec_ + base64 of at least 24 random bytes (or that base64 alone); the store keeps it, the endpoint keeps only this reference.
object
Responses
Section titled “Responses”Endpoint registered.
object
Which events reach the endpoint. Every field narrows; absent fields do not. run.finished is sent for top-level runs only.
object
Only runs in this project.
Only runs of these flows (any version).
Dry runs are left out unless this is true.
A secret by name in the deployment’s secrets store, resolved at tenant scope (the same shape as a provider’s secret_ref). The value is whsec_ + base64 of at least 24 random bytes (or that base64 alone); the store keeps it, the endpoint keeps only this reference.
object
Example
{ "events": [ "run.finished" ]}Malformed body or unknown field; the deployment refuses the URL (webhook-url-refused); the referenced secret does not exist (webhook-secret-not-found) or is too weak (webhook-secret-too-weak), or it’s a model provider’s key (provider-key-refused).
object
object
Stable machine-readable discriminant. Values match domain error codes (see docs/API-ROUTE-CONVENTIONS.md §4.3).
Optional, kind-specific.
object
Server-assigned request id; also echoed via X-Request-Id header.
Examplegenerated
{ "error": { "code": "example", "message": "example", "details": {}, "requestId": "example" }}Missing / malformed / expired / revoked bearer token.
object
object
Stable machine-readable discriminant. Values match domain error codes (see docs/API-ROUTE-CONVENTIONS.md §4.3).
Optional, kind-specific.
object
Server-assigned request id; also echoed via X-Request-Id header.
Examplegenerated
{ "error": { "code": "example", "message": "example", "details": {}, "requestId": "example" }}filter.projectId names no project (project-not-found).
object
object
Stable machine-readable discriminant. Values match domain error codes (see docs/API-ROUTE-CONVENTIONS.md §4.3).
Optional, kind-specific.
object
Server-assigned request id; also echoed via X-Request-Id header.
Examplegenerated
{ "error": { "code": "example", "message": "example", "details": {}, "requestId": "example" }}Idempotency-Key was reused with a different body, or resource-state conflict. Or env-not-served: this runtime keeps every value under the env it serves (whoami’s servedEnv, with refusesOtherEnvs), and the secret reference names another. Name it under details.servedEnv. Nothing is stored.
object
object
Stable machine-readable discriminant. Values match domain error codes (see docs/API-ROUTE-CONVENTIONS.md §4.3).
Optional, kind-specific.
object
Server-assigned request id; also echoed via X-Request-Id header.
Examplegenerated
{ "error": { "code": "example", "message": "example", "details": {}, "requestId": "example" }}The request body is over the API’s limit (request-too-large; details.maxBytes says how much).
object
object
Stable machine-readable discriminant. Values match domain error codes (see docs/API-ROUTE-CONVENTIONS.md §4.3).
Optional, kind-specific.
object
Server-assigned request id; also echoed via X-Request-Id header.
Examplegenerated
{ "error": { "code": "example", "message": "example", "details": {}, "requestId": "example" }}Server error (unmapped domain code or framework crash).
object
object
Stable machine-readable discriminant. Values match domain error codes (see docs/API-ROUTE-CONVENTIONS.md §4.3).
Optional, kind-specific.
object
Server-assigned request id; also echoed via X-Request-Id header.
Examplegenerated
{ "error": { "code": "example", "message": "example", "details": {}, "requestId": "example" }}