Update a webhook trigger
const url = 'https://example.com/v1/webhooks/2489E9AD-2EE2-8E00-8EC9-32D5F69181C0';const options = { method: 'PATCH', headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'}, body: '{"config":{"input":"example"},"label":"example","flowVersion":"example","hmacSecretName":"example","signature":{"kind":"hmac-sha256","encoding":"hex","header":"example","prefix":"example"},"deliveryIdHeader":"example","bodyLimitBytes":1,"rateLimitPerMinute":1,"toolsAllowedUnattended":["example"]}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request PATCH \ --url https://example.com/v1/webhooks/2489E9AD-2EE2-8E00-8EC9-32D5F69181C0 \ --header 'Authorization: Bearer <token>' \ --header 'Content-Type: application/json' \ --data '{ "config": { "input": "example" }, "label": "example", "flowVersion": "example", "hmacSecretName": "example", "signature": { "kind": "hmac-sha256", "encoding": "hex", "header": "example", "prefix": "example" }, "deliveryIdHeader": "example", "bodyLimitBytes": 1, "rateLimitPerMinute": 1, "toolsAllowedUnattended": [ "example" ] }'Changes the flow version (which needs execute on the flow, and must be a version the trigger’s project runs), the input, the label, which secret signs (hmacSecretName, never a model provider’s key), the signature scheme, the delivery-id header, the body cap or the rate (null clears the last three). The flow itself stays: register another trigger for another flow. Rotating the secret’s value goes through POST /v1/secrets/{name}/rotate. toolsAllowedUnattended replaces the list ([] clears it; absent keeps it, a new flow version too): naming it takes admin on the trigger’s project, it’s checked against the flow at the version the trigger will run, and every change is audited. A webhook trigger is personal or shared, and no change moves its owner: only POST /v1/webhooks/{triggerId}/owner does. A trigger a person owns is personal: only they (holding write on its project) or a project admin may change it. A trigger a service account owns is shared: changing its flow version, its input, its toolsAllowedUnattended or hmacSecretName takes admin on its project, and the project’s writers may change its label and delivery settings. Without an authorization store, a project admin here is a tenant-admin key. A change by anyone but a personal trigger’s owner is audited as trigger-changed-for-owner, naming the fields changed (and the signing secret’s name before and after) and the trigger’s version after it, never their values.
Authorizations
Section titled “Authorizations”Parameters
Section titled “Parameters”Path Parameters
Section titled “Path Parameters”TriggerId — the trigger id (a UUID).
Header Parameters
Section titled “Header Parameters”Caller-supplied idempotency key, scoped to the caller: the same key from someone else in the workspace 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). A request whose key store can’t be read before it runs is answered 503 idempotency-store-unavailable with Retry-After: nothing ran, so retry with the same key (from 0.3.0).
Request Bodyrequired
Section titled “Request Bodyrequired”object
object
null stops deduping.
null: the default.
null: the default.
Replaces the trigger’s list; [] clears it, and absent keeps it (a new flowVersion too). Naming it takes admin on the trigger’s project, and it’s checked against the flow at the version the trigger will run. Each tool by its id, with no wildcard or pattern, and only tools this trigger’s flow or agent calls. It lifts only that wait: the workspace’s approval rules, the agent’s own rules, the permission check (as the trigger’s owner) and the tool’s own limits all still apply.
Responses
Section titled “Responses”Updated webhook trigger.
A webhook trigger: a signed request to its receiveUrl starts a run of its flow, as its owner. The signing secret is never on it, only its name.
object
The routable id in the receive URL. Route-minted (a random UUID); unique per workspace. Not a secret: the signature is what a request is checked by.
Where the sender posts: {public URL}/v1/hooks/{tenantId}/{webhookId}. Absent when the deployment has no public URL configured (KINDGI_PUBLIC_URL); it’s never taken from a request’s Host.
The trigger’s project: its runs are this project’s.
Who its runs act as. A person: a personal trigger, which only they or a project admin change. A service account: a shared trigger. Only a take-over (POST …/owner) changes it. Checked again at every delivery.
object
The owner’s name at the time of the response: the person’s display name, or the service account’s name. Absent when it can’t be read (no directory, a removed account) and from a runtime before Kindgi 0.1.6: show the id then.
Set when the owner is the trigger’s project’s own service account (runAsProject): the trigger is shared, and runs as the project. Show it as “This project”. Absent otherwise.
The flow’s input on every delivery, in place of the event. Absent: the event (the body, parsed as JSON for a JSON content type, else its text).
The signing secret, by name (written with POST /v1/secrets, or made by generateSecret). Read in the env the deployment serves, at hmacSecretScope.
Only in the answer to a register with generateSecret: the new signing secret, shown this once, to paste into the sender. It’s stored as hmacSecretName in the trigger’s own scope; no later read shows it.
The header whose value, with the body, is a delivery’s dedupe key (WooCommerce: X-WC-Webhook-Delivery-ID, which is per second, not per event, so the body counts too). Absent: deliveries aren’t deduped (standard-webhooks dedupes on its own webhook-id).
The largest body it takes (default 262144).
Accepted deliveries a minute (default 600); past it, 429.
Lifecycle status. Only active triggers fire. Tombstoned rows are excluded from every read path.
Why the runtime paused it (repeated refused or failed starts; a sender’s failed proofs never count), when it did.
The trigger’s newest version (GET …/versions): one more for each change to what it runs, when, as whom or with what. Absent until its first version.
Refusals and skipped deliveries this minute past the 20 recorded in its history, which only counted.
object
The tools whose calls in this trigger’s runs don’t wait for a person’s yes, though a tool asks for one in a run no person started (needsApprovalWhenUnattended). Absent: none. Each tool by its id, with no wildcard or pattern, and only tools this trigger’s flow or agent calls. It lifts only that wait: the workspace’s approval rules, the agent’s own rules, the permission check (as the trigger’s owner) and the tool’s own limits all still apply.
Example
{ "owner": { "kind": "user", "isProjectAccount": true }, "hmacSecretScope": { "kind": "tenant" }, "signature": { "kind": "hmac-sha256", "encoding": "hex" }, "status": "active"}A body that fails validation (bad-input), or provider-key-refused: hmacSecretName is a model provider’s key, or reserved-name-prefix: it’s under the reserved kindgi. prefix. Or reference-out-of-scope: the new flowVersion isn’t a version the trigger’s project runs, such as one made in an earlier environment and not yet promoted (details.issues, at /flowVersion, whose message names the version). Nothing changes.
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" }}permission-denied: the trigger is personal and the caller is neither its owner nor a project admin (the message names the owner), or it’s shared and changing what it runs takes a project admin. A caller without write on its project is refused first, and learns nothing of its owner.
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" }}No webhook trigger with that id.
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.
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" }}The Idempotency-Key store couldn’t be read before the request ran (idempotency-store-unavailable), so nothing was changed; Retry-After (whole seconds) says when to try again with the same key.
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" }}See also
GET /v1/webhooks/{triggerId}: Fetch a webhook triggerPOST /v1/webhooks/{triggerId}/pause: Pause a webhook triggerPOST /v1/webhooks/{triggerId}/resume: Resume a webhook triggerPOST /v1/webhooks/{triggerId}/unregister: Soft-delete a webhook trigger (tombstone)- Error code
bad-input - Error code
idempotency-store-unavailable - Error code
permission-denied - Error code
provider-key-refused - Error code
reference-out-of-scope - Error code
request-too-large - Error code
reserved-name-prefix - Every error code