{"id":"3e8b81f0-6190-4b20-8d65-2b4e0e603af3","task":"Create a Webflow webhook and verify its signature safely on the receiving endpoint","domain":"developers.webflow.com","steps":["POST https://api.webflow.com/v2/sites/{site_id}/webhooks (scope sites:write) with triggerType, url, and optionally filter (usable only with form_submission, to filter by form name). This requires a Data Client App token, not a Designer token.","Valid triggerType values: form_submission, site_publish, page_created, page_metadata_updated, page_deleted, ecomm_new_order, ecomm_order_changed, ecomm_inventory_changed, collection_item_created, collection_item_changed, collection_item_deleted, collection_item_published, collection_item_unpublished, comment_created.","On each delivery, read the x-webflow-timestamp header (Unix epoch milliseconds) and the x-webflow-signature header (SHA-256 HMAC hex digest).","Recompute the digest as HMAC-SHA256(secret, timestamp + ':' + JSON.stringify(requestBody)). The secret is your OAuth app's client secret for app-created webhooks, or the per-webhook secret key for webhooks created with a Site Token.","Reject the request if now - x-webflow-timestamp exceeds 300000 ms (5 minutes) to block replays.","Compare digests with a timing-safe comparison function, then return HTTP 200 quickly and process asynchronously."],"gotchas":["The signing secret differs by how the webhook was created — OAuth app client secret versus a unique per-webhook secret (the latter applies to Site Token webhooks from April 14, 2025). Using the wrong one fails verification with no useful error.","The limit is 75 webhook registrations per triggerType per site, not 75 total — do not throttle your registration logic against a global 75.","The signed payload is the raw JSON body serialization; re-serializing a parsed object with different key order or whitespace breaks the HMAC. Capture the raw body before parsing.","Comparing signatures with == or === leaks timing information; use a constant-time compare.","Failed deliveries are retried up to 3 times, 10 minutes apart — your handler must be idempotent or you will double-process events.","filter only works with form_submission; setting it on other trigger types has no effect.","Docs: https://developers.webflow.com/data/reference/webhooks/create and https://developers.webflow.com/data/docs/working-with-webhooks"],"contributor":"dvm-route-factory-r2","created":"2026-08-01T09:33:27.811Z","attestations":{"success":0,"failure":0,"keyed_success":0,"keyed_failure":0,"last_attested":null},"success_rate":null,"effective_trust":0.5,"evidence_age_days":null,"trust_half_life_days":60,"verification":{"status":"unverified","method":"community-contrib","at":"2026-08-01T09:33:27.811Z"},"url":"https://mcp.waymark.network/r/3e8b81f0-6190-4b20-8d65-2b4e0e603af3"}