Skip to Content
Webhooks

Webhooks

Preview — not yet shipped. Webhooks are documented here so you can plan against the locked data model. Delivery is not implemented in the current release. The Webhook schema and the dispatch hook in mutating routes are in place; only the delivery worker is pending.

When webhook delivery ships, WebPinch will send signed HTTP POSTs to a URL of your choosing whenever interesting things happen — task created, task status changed, audit completed, and so on.

Why we’re documenting now

The data shape (event types, payload format, signature scheme, registration model) is already finalized in code so that future delivery doesn’t break anything you build today against this spec. If you’re planning an integration that needs near-real-time updates, design against this contract.

Planned event types

EventWhen
task.createdA task is created via dashboard, REST, MCP, or guest widget
task.updatedAny field on a task changes
task.status_changedStatus (kanban column) changes — fires in addition to task.updated
comment.createdA comment is posted on a task
audit.completedA site audit finishes successfully
audit.failedA site audit fails

More event types will be added as we go. Subscribers receive only the events they registered for.

Registration

Planned endpoints under /api/v1/webhooks/* (scope webhooks:write):

# 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 curl https://www.webpinch.com/api/v1/webhooks?projectId=... \ -H "Authorization: Bearer $TOKEN" # Delete curl -X DELETE https://www.webpinch.com/api/v1/webhooks/$ID \ -H "Authorization: Bearer $TOKEN"

The response on registration will include a secret — store it somewhere safe; you’ll need it to verify delivery signatures.

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" } }

The exact data shape varies per event type and will be documented per-event when delivery ships.

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.

Retries and ordering

Planned behavior:

  • Retries: failed deliveries (non-2xx response, timeout) are retried with exponential backoff up to 5 attempts over ~24 hours.
  • 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. Use id to dedupe.
  • At-least-once: the same event may be delivered more than once. Dedupe by X-Webpinch-Delivery.

Local testing

Until delivery ships, the easiest way to test your handler is to spin up something like webhook.site and POST sample payloads to it manually. The shape above is final — any mismatch when delivery lands will be in your handler, not the contract.

When will it ship?

No firm date yet — webhook delivery requires a worker, retry queue, and dead-letter handling, all of which take ongoing operational ownership. We’re prioritizing on user pull. If you need this for a specific use case, tell us.

See also

Last updated on