{"id":"94b584dd-f647-4694-babe-cf1fa055fd95","shortId":"aepzCB","kind":"skill","title":"webflow-webhooks","tagline":"Receive and verify Webflow webhooks. Use when setting up Webflow webhook handlers, debugging signature verification, or handling Webflow events like form_submission, site_publish, ecomm_new_order, or collection item changes.","description":"# Webflow Webhooks\n\n## When to Use This Skill\n\n- How do I receive Webflow webhooks?\n- How do I verify Webflow webhook signatures?\n- How do I handle form_submission events from Webflow?\n- How do I process Webflow ecommerce order events?\n- Why is my Webflow webhook signature verification failing?\n- Setting up Webflow CMS collection item webhooks\n\n## Essential Code\n\n### Signature Verification (Manual)\n\n```javascript\nconst crypto = require('crypto');\n\nfunction verifyWebflowSignature(rawBody, signature, timestamp, secret) {\n  // Check timestamp to prevent replay attacks (5 minute window - 300000 milliseconds)\n  const currentTime = Date.now();\n  if (Math.abs(currentTime - parseInt(timestamp)) > 300000) {\n    return false;\n  }\n\n  // Generate HMAC signature\n  const signedContent = `${timestamp}:${rawBody}`;\n  const expectedSignature = crypto\n    .createHmac('sha256', secret)\n    .update(signedContent)\n    .digest('hex');\n\n  // Timing-safe comparison\n  try {\n    return crypto.timingSafeEqual(\n      Buffer.from(signature),\n      Buffer.from(expectedSignature)\n    );\n  } catch {\n    return false; // Different lengths = invalid\n  }\n}\n```\n\n### Processing Events\n\n```javascript\napp.post('/webhooks/webflow', express.raw({ type: 'application/json' }), (req, res) => {\n  const signature = req.headers['x-webflow-signature'];\n  const timestamp = req.headers['x-webflow-timestamp'];\n\n  if (!signature || !timestamp) {\n    return res.status(400).send('Missing required headers');\n  }\n\n  // Verify signature (use OAuth client secret or webhook-specific secret)\n  const isValid = verifyWebflowSignature(\n    req.body.toString(),\n    signature,\n    timestamp,\n    process.env.WEBFLOW_WEBHOOK_SECRET\n  );\n\n  if (!isValid) {\n    return res.status(400).send('Invalid signature');\n  }\n\n  // Parse the verified payload\n  const event = JSON.parse(req.body);\n\n  // Handle different event types\n  switch (event.triggerType) {\n    case 'form_submission':\n      console.log('New form submission:', event.payload.data);\n      break;\n    case 'ecomm_new_order':\n      console.log('New order:', event.payload);\n      break;\n    case 'collection_item_created':\n      console.log('New CMS item:', event.payload);\n      break;\n    // Add more event handlers as needed\n  }\n\n  // Always return 200 to acknowledge receipt\n  res.status(200).send('OK');\n});\n```\n\n## Common Event Types\n\n| Event | Triggered When | Use Case |\n|-------|----------------|----------|\n| `form_submission` | Form submitted on site | Contact forms, lead capture |\n| `site_publish` | Site is published | Clear caches, trigger builds |\n| `ecomm_new_order` | New ecommerce order | Order processing, inventory |\n| `ecomm_order_changed` | Order status changes | Update fulfillment systems |\n| `collection_item_created` | CMS item created | Content syndication |\n| `collection_item_changed` | CMS item updated | Update external systems |\n| `collection_item_deleted` | CMS item deleted | Remove from external systems |\n\n## Environment Variables\n\n```bash\n# For webhooks created via OAuth App\nWEBFLOW_WEBHOOK_SECRET=your_oauth_client_secret\n\n# For webhooks created via API (after April 2025)\nWEBFLOW_WEBHOOK_SECRET=whsec_xxxxx  # Returned when creating webhook\n```\n\n## Local Development\n\nFor local webhook testing, install Hookdeck CLI:\n\n```bash\n```\n\nThen start the tunnel:\n\n```bash\nnpx hookdeck-cli listen 3000 webflow --path /webhooks/webflow\n```\n\nNo account required. Provides local tunnel + web UI for inspecting requests.\n\n## Resources\n\n- [What Are Webflow Webhooks](references/overview.md) - Event types and payload structure\n- [Setting Up Webflow Webhooks](references/setup.md) - Dashboard configuration and API setup\n- [Signature Verification Details](references/verification.md) - In-depth verification guide\n- [Express Example](examples/express/) - Node.js implementation with tests\n- [Next.js Example](examples/nextjs/) - App Router implementation\n- [FastAPI Example](examples/fastapi/) - Python implementation\n\n## Important Notes\n\n- Webhooks created through the Webflow dashboard do NOT include signature headers\n- Only webhooks created via OAuth apps or API include `x-webflow-signature` and `x-webflow-timestamp`\n- Always use raw body for signature verification, not parsed JSON\n- Timestamp validation (5 minute window - 300000 milliseconds) is critical to prevent replay attacks\n- Return 200 status to acknowledge receipt; other statuses trigger retries (up to 3 times)\n\n## Recommended: webhook-handler-patterns\n\nThis skill pairs well with webhook-handler-patterns for production-ready implementations:\n\n- [Handler sequence](https://github.com/hookdeck/webhook-skills/blob/main/skills/webhook-handler-patterns/references/handler-sequence.md) — Request flow and middleware order\n- [Idempotency](https://github.com/hookdeck/webhook-skills/blob/main/skills/webhook-handler-patterns/references/idempotency.md) — Handling duplicate events\n- [Error handling](https://github.com/hookdeck/webhook-skills/blob/main/skills/webhook-handler-patterns/references/error-handling.md) — Graceful failure and recovery\n- [Retry logic](https://github.com/hookdeck/webhook-skills/blob/main/skills/webhook-handler-patterns/references/retry-logic.md) — Handling failed processing\n\n## Related Skills\n\n- [stripe-webhooks](https://github.com/hookdeck/webhook-skills/tree/main/skills/stripe-webhooks) - Stripe webhook handling with similar HMAC-SHA256 verification\n- [shopify-webhooks](https://github.com/hookdeck/webhook-skills/tree/main/skills/shopify-webhooks) - Shopify webhook implementation\n- [github-webhooks](https://github.com/hookdeck/webhook-skills/tree/main/skills/github-webhooks) - GitHub webhook handling\n- [webhook-handler-patterns](https://github.com/hookdeck/webhook-skills/tree/main/skills/webhook-handler-patterns) - Production patterns for all webhooks\n- [hookdeck-event-gateway](https://github.com/hookdeck/webhook-skills/tree/main/skills/hookdeck-event-gateway) - Webhook infrastructure and reliability\n\nSources:\n- [Working with Webhooks – Webflow Docs](https://developers.webflow.com/data/docs/working-with-webhooks)\n- [Webhook Signatures Changelog](https://developers.webflow.com/data/changelog/webhook-signatures)","tags":["webflow","webhooks","webhook","skills","hookdeck","agent-skills","ai-coding","api-integrations","event-driven","github-webhooks","llm-tools","shopify-webhooks"],"capabilities":["skill","source-hookdeck","skill-webflow-webhooks","topic-agent-skills","topic-ai-coding","topic-api-integrations","topic-event-driven","topic-github-webhooks","topic-llm-tools","topic-shopify-webhooks","topic-stripe-webhooks","topic-webhook-security","topic-webhook-signatures","topic-webhooks"],"categories":["webhook-skills"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/hookdeck/webhook-skills/webflow-webhooks","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add hookdeck/webhook-skills","source_repo":"https://github.com/hookdeck/webhook-skills","install_from":"skills.sh"}},"qualityScore":"0.485","qualityRationale":"deterministic score 0.48 from registry signals: · indexed on github topic:agent-skills · 71 github stars · SKILL.md body (6,168 chars)","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill-github:v1","enrichmentVersion":1,"enrichedAt":"2026-05-18T18:56:56.988Z","embedding":null,"createdAt":"2026-04-18T22:14:04.016Z","updatedAt":"2026-05-18T18:56:56.988Z","lastSeenAt":"2026-05-18T18:56:56.988Z","tsv":"'/data/changelog/webhook-signatures)':660 '/data/docs/working-with-webhooks)':654 '/hookdeck/webhook-skills/blob/main/skills/webhook-handler-patterns/references/error-handling.md)':575 '/hookdeck/webhook-skills/blob/main/skills/webhook-handler-patterns/references/handler-sequence.md)':558 '/hookdeck/webhook-skills/blob/main/skills/webhook-handler-patterns/references/idempotency.md)':567 '/hookdeck/webhook-skills/blob/main/skills/webhook-handler-patterns/references/retry-logic.md)':584 '/hookdeck/webhook-skills/tree/main/skills/github-webhooks)':619 '/hookdeck/webhook-skills/tree/main/skills/hookdeck-event-gateway)':641 '/hookdeck/webhook-skills/tree/main/skills/shopify-webhooks)':610 '/hookdeck/webhook-skills/tree/main/skills/stripe-webhooks)':595 '/hookdeck/webhook-skills/tree/main/skills/webhook-handler-patterns)':629 '/webhooks/webflow':163,407 '200':271,276,522 '2025':374 '3':533 '3000':404 '300000':112,122,513 '400':188,217 '5':109,510 'account':409 'acknowledg':273,525 'add':263 'alway':269,498 'api':371,438,487 'app':359,459,485 'app.post':162 'application/json':166 'april':373 'attack':108,520 'bash':353,393,398 'bodi':501 'break':243,252,262 'buffer.from':149,151 'build':305 'cach':303 'captur':296 'case':235,244,253,286 'catch':153 'chang':34,317,320,334 'changelog':657 'check':103 'clear':302 'cli':392,402 'client':197,365 'cms':83,259,327,335,344 'code':88 'collect':32,84,254,324,332,341 'common':279 'comparison':145 'configur':436 'console.log':238,248,257 'const':93,114,128,132,169,176,204,225 'contact':293 'content':330 'creat':256,326,329,356,369,382,470,482 'createhmac':135 'critic':516 'crypto':94,96,134 'crypto.timingsafeequal':148 'currenttim':115,119 'dashboard':435,474 'date.now':116 'debug':16 'delet':343,346 'depth':446 'detail':442 'develop':385 'developers.webflow.com':653,659 'developers.webflow.com/data/changelog/webhook-signatures)':658 'developers.webflow.com/data/docs/working-with-webhooks)':652 'differ':156,230 'digest':140 'doc':651 'duplic':569 'ecomm':28,245,306,315 'ecommerc':69,310 'environ':351 'error':571 'essenti':87 'event':22,61,71,160,226,231,265,280,282,425,570,637 'event.payload':251,261 'event.payload.data':242 'event.triggertype':234 'exampl':450,457,463 'examples/express':451 'examples/fastapi':464 'examples/nextjs':458 'expectedsignatur':133,152 'express':449 'express.raw':164 'extern':339,349 'fail':79,586 'failur':577 'fals':124,155 'fastapi':462 'flow':560 'form':24,59,236,240,287,289,294 'fulfil':322 'function':97 'gateway':638 'generat':125 'github':615,620 'github-webhook':614 'github.com':557,566,574,583,594,609,618,628,640 'github.com/hookdeck/webhook-skills/blob/main/skills/webhook-handler-patterns/references/error-handling.md)':573 'github.com/hookdeck/webhook-skills/blob/main/skills/webhook-handler-patterns/references/handler-sequence.md)':556 'github.com/hookdeck/webhook-skills/blob/main/skills/webhook-handler-patterns/references/idempotency.md)':565 'github.com/hookdeck/webhook-skills/blob/main/skills/webhook-handler-patterns/references/retry-logic.md)':582 'github.com/hookdeck/webhook-skills/tree/main/skills/github-webhooks)':617 'github.com/hookdeck/webhook-skills/tree/main/skills/hookdeck-event-gateway)':639 'github.com/hookdeck/webhook-skills/tree/main/skills/shopify-webhooks)':608 'github.com/hookdeck/webhook-skills/tree/main/skills/stripe-webhooks)':593 'github.com/hookdeck/webhook-skills/tree/main/skills/webhook-handler-patterns)':627 'grace':576 'guid':448 'handl':20,58,229,568,572,585,598,622 'handler':15,266,538,547,554,625 'header':192,479 'hex':141 'hmac':126,602 'hmac-sha256':601 'hookdeck':391,401,636 'hookdeck-c':400 'hookdeck-event-gateway':635 'idempot':564 'implement':453,461,466,553,613 'import':467 'in-depth':444 'includ':477,488 'infrastructur':643 'inspect':417 'instal':390 'invalid':158,219 'inventori':314 'isvalid':205,214 'item':33,85,255,260,325,328,333,336,342,345 'javascript':92,161 'json':507 'json.parse':227 'lead':295 'length':157 'like':23 'listen':403 'local':384,387,412 'logic':581 'manual':91 'math.abs':118 'middlewar':562 'millisecond':113,514 'minut':110,511 'miss':190 'need':268 'new':29,239,246,249,258,307,309 'next.js':456 'node.js':452 'note':468 'npx':399 'oauth':196,358,364,484 'ok':278 'order':30,70,247,250,308,311,312,316,318,563 'pair':542 'pars':221,506 'parseint':120 'path':406 'pattern':539,548,626,631 'payload':224,428 'prevent':106,518 'process':67,159,313,587 'process.env.webflow':210 'product':551,630 'production-readi':550 'provid':411 'publish':27,298,301 'python':465 'raw':500 'rawbodi':99,131 'readi':552 'receipt':274,526 'receiv':4,45 'recommend':535 'recoveri':579 'references/overview.md':424 'references/setup.md':434 'references/verification.md':443 'relat':588 'reliabl':645 'remov':347 'replay':107,519 'req':167 'req.body':228 'req.body.tostring':207 'req.headers':171,178 'request':418,559 'requir':95,191,410 'res':168 'res.status':187,216,275 'resourc':419 'retri':530,580 'return':123,147,154,186,215,270,380,521 'router':460 'safe':144 'secret':102,137,198,203,212,362,366,377 'send':189,218,277 'sequenc':555 'set':11,80,430 'setup':439 'sha256':136,603 'shopifi':606,611 'shopify-webhook':605 'signatur':17,54,77,89,100,127,150,170,175,184,194,208,220,440,478,492,503,656 'signedcont':129,139 'similar':600 'site':26,292,297,299 'skill':41,541,589 'skill-webflow-webhooks' 'sourc':646 'source-hookdeck' 'specif':202 'start':395 'status':319,523,528 'stripe':591,596 'stripe-webhook':590 'structur':429 'submiss':25,60,237,241,288 'submit':290 'switch':233 'syndic':331 'system':323,340,350 'test':389,455 'time':143,534 'timestamp':101,104,121,130,177,182,185,209,497,508 'timing-saf':142 'topic-agent-skills' 'topic-ai-coding' 'topic-api-integrations' 'topic-event-driven' 'topic-github-webhooks' 'topic-llm-tools' 'topic-shopify-webhooks' 'topic-stripe-webhooks' 'topic-webhook-security' 'topic-webhook-signatures' 'topic-webhooks' 'tri':146 'trigger':283,304,529 'tunnel':397,413 'type':165,232,281,426 'ui':415 'updat':138,321,337,338 'use':9,39,195,285,499 'valid':509 'variabl':352 'verif':18,78,90,441,447,504,604 'verifi':6,51,193,223 'verifywebflowsignatur':98,206 'via':357,370,483 'web':414 'webflow':2,7,13,21,35,46,52,63,68,75,82,174,181,360,375,405,422,432,473,491,496,650 'webflow-webhook':1 'webhook':3,8,14,36,47,53,76,86,201,211,355,361,368,376,383,388,423,433,469,481,537,546,592,597,607,612,616,621,624,634,642,649,655 'webhook-handler-pattern':536,545,623 'webhook-specif':200 'well':543 'whsec':378 'window':111,512 'work':647 'x':173,180,490,495 'x-webflow-signatur':172,489 'x-webflow-timestamp':179,494 'xxxxx':379","prices":[{"id":"0765fe05-9beb-42d4-b39f-8722869eb0b3","listingId":"94b584dd-f647-4694-babe-cf1fa055fd95","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"hookdeck","category":"webhook-skills","install_from":"skills.sh"},"createdAt":"2026-04-18T22:14:04.016Z"}],"sources":[{"listingId":"94b584dd-f647-4694-babe-cf1fa055fd95","source":"github","sourceId":"hookdeck/webhook-skills/webflow-webhooks","sourceUrl":"https://github.com/hookdeck/webhook-skills/tree/main/skills/webflow-webhooks","isPrimary":false,"firstSeenAt":"2026-04-18T22:14:04.016Z","lastSeenAt":"2026-05-18T18:56:56.988Z"},{"listingId":"94b584dd-f647-4694-babe-cf1fa055fd95","source":"skills_sh","sourceId":"hookdeck/webhook-skills/webflow-webhooks","sourceUrl":"https://skills.sh/hookdeck/webhook-skills/webflow-webhooks","isPrimary":true,"firstSeenAt":"2026-05-07T20:45:31.607Z","lastSeenAt":"2026-05-07T22:43:26.985Z"}],"details":{"listingId":"94b584dd-f647-4694-babe-cf1fa055fd95","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"hookdeck","slug":"webflow-webhooks","github":{"repo":"hookdeck/webhook-skills","stars":71,"topics":["agent-skills","ai-coding","api-integrations","event-driven","github-webhooks","llm-tools","shopify-webhooks","stripe-webhooks","webhook-security","webhook-signatures","webhooks"],"license":"mit","html_url":"https://github.com/hookdeck/webhook-skills","pushed_at":"2026-05-15T15:30:15Z","description":"Webhook integration skills for AI coding agents (Claude Code, Cursor, Copilot). Step-by-step guidance for setting up webhook receivers, signature verification, and event handling for Stripe, Shopify, GitHub, and more. Built on the Agent Skills specification.","skill_md_sha":"990275c6449aec6407b97a5512b6047652faa98c","skill_md_path":"skills/webflow-webhooks/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/hookdeck/webhook-skills/tree/main/skills/webflow-webhooks"},"layout":"multi","source":"github","category":"webhook-skills","frontmatter":{"name":"webflow-webhooks","license":"MIT","description":"Receive and verify Webflow webhooks. Use when setting up Webflow webhook handlers, debugging signature verification, or handling Webflow events like form_submission, site_publish, ecomm_new_order, or collection item changes."},"skills_sh_url":"https://skills.sh/hookdeck/webhook-skills/webflow-webhooks"},"updatedAt":"2026-05-18T18:56:56.988Z"}}