Webhook Tools
These tools let an AI client manage your workspace's webhook subscriptions — arrangements to POST an event to a URL when something happens in CheckFlow — and look at what was actually delivered. They mirror the Webhooks REST routes. Subscriptions have no page in the app, so the API and these tools are the only way to see them.
Three things about webhooks shape every tool on this page:
- Event names are opaque identifiers, matched exactly, case included. Six are snake_case —
new_checklist,task_completed,file_uploaded,checklist_completed,comment_created,task_assigned— and three are dotted —data_set.record.created,data_set.record.updated,data_set.record.deleted. A plausible correction such astask.completedis refused. - Every key in a subscription's scope is a template-level key. A checklist's task carries the key of the template task it was made from, so a subscription scoped to a task fires for that task in every checklist started from the template, not for one task on one checklist. There is no way to subscribe to a single occurrence. The exception is a standalone task, whose key is its own.
- The signing secret never passes through these tools. Deliveries are signed with a
CF-Signatureheader, but a tool result ends up in a transcript, socreate_webhookdoes not return the secret and there is no tool to rotate it. Whoever owns the integration callsPOST /v3/webhooks/{id}/rotate-secretover the REST API, which issues a secret and returns it once. Until they do, the receiving end cannot check the signature.
A delivery that fails is posted again — up to five attempts over about three hours, every one carrying the same CF-Delivery-Id — and then dropped; nothing is replayed automatically. Ten consecutive events that fail to be delivered switch a subscription off. For the product-level introduction, see Web Hooks.
How to Read This Page
Every tool acts on the workspace your API key belongs to, as the member (or the workspace) the key acts as. There is no workspace argument. See Connecting.
- The Read/Write column in the summary table says whether a tool can change anything.
- Annotations are the hints a tool publishes to your client:
readOnlyHint,destructiveHintandidempotentHint. A hint a tool does not declare is left out of its definition, and the MCP specification tells a client to assume the cautious default in that case — that the tool may write, may be destructive and is not idempotent. See Tool Annotations. idempotencyKeyappears on the write tools that accept it. It is optional and at most 255 characters. If a call times out or its answer is lost, send it again with the same key and the same arguments: the first call's answer comes back, markedcheckflow.io/idempotentReplayin the result's_meta, instead of the work happening twice. The same key with different arguments is refused withCONFLICT, and so is a retry while the first call is still running. See Idempotency.- Refusals come back as an ordinary tool result with
isErrorset.structuredContentcarries the v3 error body —code,message,requestIdandfield— and the text block summarises it. See Errors and How It Works. - A tool that returns nothing, such as a delete, answers with a result that is not flagged
isErrorand carries no data.
Two REST routes have no tool. GET /v3/webhooks/{id}/deliveries/{deliveryId} returns a delivery's payload — your workspace's own data — and is left to a person rather than put into a transcript. POST /v3/webhooks/{id}/rotate-secret returns a secret, for the reason above.
Tool Summary
| Tool | What it does | Read/Write |
|---|---|---|
list_webhooks | Lists the workspace's webhook subscriptions | Read |
get_webhook | Returns one subscription | Read |
list_webhook_deliveries | Lists a subscription's delivery attempts | Read |
replay_webhook_delivery | Posts one delivery again, now | Write |
create_webhook | Creates a subscription | Write |
update_webhook | Changes a subscription's target, label or active state | Write |
delete_webhook | Deletes a subscription | Write |
list_webhooks
Lists the workspace's webhook subscriptions, newest first. It is the way to find out whether an integration that thinks it subscribed actually did. The description tells the model how to read each row:
isActivefalse means the subscription is skipped when its event fires; nothing is queued while it is paused and nothing is replayed when it resumes.- On an inactive row, a
disabledReasonmeans the platform switched it off after ten consecutive failed events; nodisabledReasonmeans a person paused it. Those need opposite advice. consecutiveFailuresabove zero on an active row means the receiver is currently missing events.
Reactivating is update_webhook with isActive true, which clears the counter and the reason and replays nothing.
| Name | Type | Required | Description |
|---|---|---|---|
eventType | string | No | Only subscriptions to this event — one of the nine event names, matched exactly. Anything else is refused. |
source | string | No | Only subscriptions carrying this label, ignoring case. ALL means the label ALL, not "no filter". |
isActive | boolean | No | true for delivering subscriptions, false for paused ones. Omit for both. |
sort | string | No | field, field:asc or field:desc, where field is createdDateTime, eventType or targetUrl. Default createdDateTime:desc. |
after | string | No | The nextCursor from the previous page. Send the same filters with it. |
pageSize | integer | No | Results per page, 1 to 100. Default 50. A value outside the range is not refused; the default of 50 is used instead. |
- Returns: the standard list envelope (see Pagination) holding Webhook objects, each with
id,eventType,targetUrl,source,isActive,consecutiveFailures,scope,createdDateTimeand, when it applies,disabledDateTimeanddisabledReason. - Annotations:
readOnlyHinttrue,idempotentHinttrue. - REST equivalent:
GET /v3/webhooks. - Example prompt: "What webhooks are set up in our CheckFlow workspace, and are any of them failing?"
get_webhook
Returns one subscription by the id create_webhook returned — the same row list_webhooks shows. It lets an integration holding an id check that its subscription still exists and is active without paging through the workspace. An id belonging to another workspace is refused with WEBHOOK_NOT_FOUND.
| Name | Type | Required | Description |
|---|---|---|---|
webhookId | string | Yes | The subscription's id, from list_webhooks or create_webhook. |
- Returns: a Webhook object.
- Annotations:
readOnlyHinttrue,idempotentHinttrue. - REST equivalent:
GET /v3/webhooks/{id}. - Example prompt: "Is the webhook we set up for the accounts system still active?"
list_webhook_deliveries
Lists every attempt to deliver one subscription's events, newest first: what fired, what the receiving end answered, how long it took and what went wrong. The description calls it the first tool to reach for when somebody says a webhook is not working, because it separates two cases that look the same from everywhere else — an empty list means the subscription is not firing (a scope or event problem), and a list of failures means it is firing into an endpoint that will not accept it.
Each row's outcome is one of:
| Outcome | Meaning |
|---|---|
delivered | The receiver answered with a 2xx. |
failed | Requests were made and none got a 2xx; the platform has stopped trying. |
refused | No request was made, because the target resolved to an address inside CheckFlow's own network. Retrying will not fix it. |
pending | Not delivered yet and another attempt is queued. Not a failure, and not something to replay. |
Rows carry no payload. The history goes back 30 days.
| Name | Type | Required | Description |
|---|---|---|---|
webhookId | string | Yes | The subscription's id, from list_webhooks. |
outcome | string | No | delivered, failed, refused or pending, ignoring case. Anything else is refused. Paging through pending can skip a row that lands while you read. |
after | string | No | The nextCursor from the previous page. Send the same filters with it. |
pageSize | integer | No | Results per page, 1 to 100. Default 50. A value outside the range is not refused; the default of 50 is used instead. |
- Returns: the standard list envelope holding Delivery objects without
payloadortargetUrl, each withid,webhookId,eventType,outcome,statusCode,failure,attemptCount,durationMs,createdDateTimeandlastAttemptDateTime, each present when it applies. - Annotations:
readOnlyHinttrue,idempotentHinttrue. - REST equivalent:
GET /v3/webhooks/{id}/deliveries. - Example prompt: "Why isn't our task_completed webhook reaching the accounts system?"
replay_webhook_delivery
Posts one delivery again, now. This makes a real HTTP request to the subscriber's endpoint while the model waits, so its effect is felt outside your workspace: your workspace's data arrives in somebody's system a second time. It is the same delivery rather than a new event — the same body under the same CF-Delivery-Id — so a receiver that deduplicates on that header recognises it and one that does not processes the event twice. The description tells the model to say which it knows before replaying, and never to call this in a loop.
The answer is the delivery as it now stands; the model is told to read its outcome, because an answer means the attempt was made, not that it arrived. A pending delivery is refused with CONFLICT (the platform is already retrying it), and so is a delivery on a subscription that is not active — reactivate it with update_webhook instead. A replay does not change consecutiveFailures. attemptCount goes up and can pass five, the limit the automatic retries keep to.
| Name | Type | Required | Description |
|---|---|---|---|
webhookId | string | Yes | The subscription's id, from list_webhooks. |
deliveryId | string | Yes | The delivery's id, from list_webhook_deliveries — the same value the subscriber received in CF-Delivery-Id. Only the last 30 days of deliveries exist. |
idempotencyKey | string | No | Retries this call safely. See How to Read This Page. |
- Returns: the delivery, with the outcome of the attempt just made and its
targetUrl. - Annotations:
destructiveHinttrue,idempotentHintfalse. - REST equivalent:
POST /v3/webhooks/{id}/deliveries/{deliveryId}/replay. - Example prompt: "The accounts system was down this morning — resend the failed task_completed delivery from 09:14."
A replay cannot be taken back. If the receiving system does not deduplicate on CF-Delivery-Id, it processes the event again.
create_webhook
Subscribes a URL to an event. Every key in the scope is checked against your workspace before the subscription is written, so a mistake is refused now rather than surfacing weeks later as a subscription that never fires. There is no duplicate check: two identical subscriptions deliver every event twice. The event type and scope cannot be changed afterwards — delete the subscription and create another.
The answer does not include the signing secret. See the note at the top of this page.
| Name | Type | Required | Description |
|---|---|---|---|
eventType | string | Yes | The event to fire on — one of the nine names, matched exactly including case and punctuation. See Event Types. |
targetUrl | string | Yes | Where to POST the event: an absolute https URL on the public internet, at most 1,000 characters, with no username or password in it. http is refused, and so is anything naming or resolving to an address inside CheckFlow's own network (loopback, private ranges, link-local, the cloud metadata endpoint). |
scope | object | No | What to narrow the subscription to: type and key. type is Workspace, Template, Task or Field; key is the template, task or field key from get_template, and is left out for Workspace. Omit scope for the whole workspace. A scope the event cannot fire under is refused, and the refusal lists the ones it accepts. |
source | string | No | A label for whoever is setting this up, such as zapier. At most 20 characters, default api. Nothing reads it except the source filter on list_webhooks. |
isActive | boolean | No | Whether to start delivering straight away. Default true. false sets the subscription up while the receiving end is still being built. |
idempotencyKey | string | No | Retries this call safely. See How to Read This Page. |
- Returns: the new Webhook object, without
secret. - Annotations:
destructiveHintfalse. - REST equivalent:
POST /v3/webhooks(which, unlike the tool, returns the secret once). - Example prompt: "When anyone completes the 'Approve payment' task in Invoice Review, post it to https://hooks.acme.example/checkflow."
Event Types
| Event | Fires when | Scopes it accepts |
|---|---|---|
new_checklist | A checklist is started from a template | Template |
task_completed | A task is marked done | Task, Template or Workspace |
file_uploaded | A file is attached to a File Upload field | Field |
checklist_completed | A checklist is finished (not when it is reopened) | Template or Workspace |
comment_created | Somebody comments on a task; the delivery carries the comment text as typed | Task or Workspace |
task_assigned | A task is given to somebody who did not already have it — one delivery per person | Task, Template or Workspace |
data_set.record.created | A Data Set record is created | Workspace |
data_set.record.updated | A Data Set record is updated | Workspace |
data_set.record.deleted | A Data Set record is deleted | Workspace |
new_checklist and file_uploaded have no workspace scope, so omitting scope for them is refused. The description warns the model that a comment_created subscription with no scope sends every comment anybody writes in the workspace out of CheckFlow, and tells it to narrow the scope to a task unless the whole workspace is the point.
update_webhook
Changes where a subscription delivers, what it is labelled, or whether it delivers at all — those three and nothing else. The event type and scope define the subscription; to change them, delete it and create another. Sending none of the three is refused. Nothing here can be cleared.
| Name | Type | Required | Description |
|---|---|---|---|
webhookId | string | Yes | The subscription's id, from list_webhooks. |
targetUrl | string | No | The new target. The same rules as create_webhook, including https only. |
source | string | No | The new label, at most 20 characters. |
isActive | boolean | No | Whether to deliver. Pausing keeps everything else and skips the subscription when the event fires; nothing is buffered or replayed on resuming. Setting true also clears consecutiveFailures and disabledReason. Setting the value it already has is not refused. |
- Returns: the Webhook object as it now stands.
- Annotations:
idempotentHinttrue. - REST equivalent:
PATCH /v3/webhooks/{id}. - Example prompt: "Switch the accounts system webhook back on."
delete_webhook
Deletes a subscription: the row goes and the events stop. Nothing restores it, so pausing with update_webhook is the reversible alternative. An id that names nothing is refused with WEBHOOK_NOT_FOUND. An event raised just before the delete may still be delivered just after it.
| Name | Type | Required | Description |
|---|---|---|---|
webhookId | string | Yes | The subscription's id, from list_webhooks. |
- Returns: nothing.
- Annotations:
destructiveHinttrue,idempotentHinttrue. - REST equivalent:
DELETE /v3/webhooks/{id}. - Example prompt: "Remove the Zapier webhooks we no longer use."
Related Pages
- Webhooks — the REST routes behind these tools, including the delivery payload and secret rotation that the tools leave out.
- Web Hooks — the product-level introduction to webhooks and the events CheckFlow raises.
- Template Authoring Tools —
get_template, where the template, task and field keys for a scope come from. - Data Set Tools — the record writes that raise the
data_set.record.*events, and the one bulk write that does not.