Skip to Content
Webhooks

Webhooks

WebPinch sends a signed HTTP POST to a URL of your choosing whenever something you subscribed to happens in a project: a task is created, its status changes, a comment is posted, an audit finishes.

This is what Zapier, Make, n8n and your own services use to react to WebPinch in real time instead of polling.

Event types

EventWhen
task.createdA task is created from the dashboard, the REST API, MCP, or a guest pin (widget, extension, review link)
task.updatedOne or more fields on a task change
task.status_changedStatus (kanban column) changes — fires in addition to task.updated
comment.createdA team member comments on a task
audit.completedA site audit finishes successfully
audit.failedA site audit fails

Subscribers receive only the events they registered for. Reordering cards inside a column does not send task.updated.

Registration

Webhooks are managed with a personal access token that has the webhooks:write scope. You can register a webhook on any project you can open, and you see and manage only the webhooks you registered.

# Register curl https://www.webpinch.com/api/v1/webhooks \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{ "projectId": "...", "url": "https://example.com/webhooks/webpinch", "events": ["task.created", "task.status_changed"] }' # List (optionally for one project) curl https://www.webpinch.com/api/v1/webhooks?projectId=... \ -H "Authorization: Bearer $TOKEN" # Get one curl https://www.webpinch.com/api/v1/webhooks/$ID \ -H "Authorization: Bearer $TOKEN" # Delete curl -X DELETE https://www.webpinch.com/api/v1/webhooks/$ID \ -H "Authorization: Bearer $TOKEN"

The registration response includes a secret (whsec_…). It is shown once — store it somewhere safe; you need it to verify delivery signatures.

The URL must use https and resolve to a public address. A project can have up to 20 active webhooks. A webhook stops automatically if its creator loses access to the project.

Delivery format

Each delivery is an HTTP POST to your URL with:

POST /webhooks/webpinch HTTP/1.1 Content-Type: application/json X-Webpinch-Event: task.status_changed X-Webpinch-Delivery: 01HX... X-Webpinch-Signature: sha256=<hex>

Body shape:

{ "id": "01HX...", "type": "task.status_changed", "createdAt": "2026-05-04T10:30:00Z", "projectId": "...", "data": { "taskId": "...", "from": "in_progress", "to": "done" } }

Event data

Every task event (task.* and comment.created) also carries data.task: the task exactly as GET /api/v1/tasks/:id returns it, so you don’t need a second request to act on the event.

Eventdata fields
task.createdtaskId, task
task.updatedtaskId, changes (the field names that changed), task
task.status_changedtaskId, from, to, task
comment.createdtaskId, commentId, comment (id, body, author, createdAt), task
audit.completedauditId, audit (status, rootUrl, summary, timestamps)
audit.failedauditId, audit (as above, plus error)

Signature verification

X-Webpinch-Signature: sha256=<hex> is HMAC-SHA256(rawBody, webhookSecret) rendered as a lowercase hex string.

Always verify the signature before trusting the body. Example in Node:

import crypto from "node:crypto"; function verifyWebpinchSignature(rawBody, signatureHeader, secret) { const expected = "sha256=" + crypto .createHmac("sha256", secret) .update(rawBody) .digest("hex"); return crypto.timingSafeEqual( Buffer.from(signatureHeader), Buffer.from(expected) ); }

Use a constant-time comparison (like timingSafeEqual) to prevent timing attacks.

Responding, retries and ordering

  • Respond fast with a 2xx. Anything else — a 3xx, 4xx, 5xx, or no answer within 10 seconds — counts as a failed attempt. Redirects are not followed.
  • Retries: a failed delivery is retried 5 minutes, 1 hour, 6 hours and 24 hours after the first attempt (5 attempts in total).
  • Unsubscribe: answer 410 Gone and the webhook is switched off immediately. A webhook whose deliveries keep failing every retry is switched off after 10 such deliveries in a row.
  • Ordering: events are dispatched in the order they happen, but retries can cause out-of-order delivery on your end. Always treat events as eventually-consistent.
  • At-least-once: the same event may be delivered more than once. Dedupe by id (the same for every subscriber of an event) or X-Webpinch-Delivery (unique per subscriber).

Local testing

Point a webhook at something like webhook.site to see real deliveries, or run a tunnel (ngrok, Cloudflare Tunnel) in front of your local handler — the URL must be publicly reachable.

See also

Last updated on

Last updated on