{"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# Install via npm\nnpm install -g hookdeck-cli\n\n# Or via Homebrew\nbrew install hookdeck/hookdeck/hookdeck\n```\n\nThen start the tunnel:\n\n```bash\nhookdeck listen 3000 --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.484","qualityRationale":"deterministic score 0.48 from registry signals: · indexed on github topic:agent-skills · 69 github stars · SKILL.md body (6,257 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-02T06:55:48.022Z","embedding":null,"createdAt":"2026-04-18T22:14:04.016Z","updatedAt":"2026-05-02T06:55:48.022Z","lastSeenAt":"2026-05-02T06:55:48.022Z","tsv":"'/data/changelog/webhook-signatures)':671 '/data/docs/working-with-webhooks)':665 '/hookdeck/webhook-skills/blob/main/skills/webhook-handler-patterns/references/error-handling.md)':586 '/hookdeck/webhook-skills/blob/main/skills/webhook-handler-patterns/references/handler-sequence.md)':569 '/hookdeck/webhook-skills/blob/main/skills/webhook-handler-patterns/references/idempotency.md)':578 '/hookdeck/webhook-skills/blob/main/skills/webhook-handler-patterns/references/retry-logic.md)':595 '/hookdeck/webhook-skills/tree/main/skills/github-webhooks)':630 '/hookdeck/webhook-skills/tree/main/skills/hookdeck-event-gateway)':652 '/hookdeck/webhook-skills/tree/main/skills/shopify-webhooks)':621 '/hookdeck/webhook-skills/tree/main/skills/stripe-webhooks)':606 '/hookdeck/webhook-skills/tree/main/skills/webhook-handler-patterns)':640 '/webhooks/webflow':163,418 '200':271,276,533 '2025':374 '3':544 '3000':416 '300000':112,122,524 '400':188,217 '5':109,521 'account':420 'acknowledg':273,536 'add':263 'alway':269,509 'api':371,449,498 'app':359,470,496 'app.post':162 'application/json':166 'april':373 'attack':108,531 'bash':353,393,413 'bodi':512 'break':243,252,262 'brew':406 'buffer.from':149,151 'build':305 'cach':303 'captur':296 'case':235,244,253,286 'catch':153 'chang':34,317,320,334 'changelog':668 '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':447 '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,481,493 'createhmac':135 'critic':527 'crypto':94,96,134 'crypto.timingsafeequal':148 'currenttim':115,119 'dashboard':446,485 'date.now':116 'debug':16 'delet':343,346 'depth':457 'detail':453 'develop':385 'developers.webflow.com':664,670 'developers.webflow.com/data/changelog/webhook-signatures)':669 'developers.webflow.com/data/docs/working-with-webhooks)':663 'differ':156,230 'digest':140 'doc':662 'duplic':580 'ecomm':28,245,306,315 'ecommerc':69,310 'environ':351 'error':582 'essenti':87 'event':22,61,71,160,226,231,265,280,282,436,581,648 'event.payload':251,261 'event.payload.data':242 'event.triggertype':234 'exampl':461,468,474 'examples/express':462 'examples/fastapi':475 'examples/nextjs':469 'expectedsignatur':133,152 'express':460 'express.raw':164 'extern':339,349 'fail':79,597 'failur':588 'fals':124,155 'fastapi':473 'flow':571 'form':24,59,236,240,287,289,294 'fulfil':322 'function':97 'g':399 'gateway':649 'generat':125 'github':626,631 'github-webhook':625 'github.com':568,577,585,594,605,620,629,639,651 'github.com/hookdeck/webhook-skills/blob/main/skills/webhook-handler-patterns/references/error-handling.md)':584 'github.com/hookdeck/webhook-skills/blob/main/skills/webhook-handler-patterns/references/handler-sequence.md)':567 'github.com/hookdeck/webhook-skills/blob/main/skills/webhook-handler-patterns/references/idempotency.md)':576 'github.com/hookdeck/webhook-skills/blob/main/skills/webhook-handler-patterns/references/retry-logic.md)':593 'github.com/hookdeck/webhook-skills/tree/main/skills/github-webhooks)':628 'github.com/hookdeck/webhook-skills/tree/main/skills/hookdeck-event-gateway)':650 'github.com/hookdeck/webhook-skills/tree/main/skills/shopify-webhooks)':619 'github.com/hookdeck/webhook-skills/tree/main/skills/stripe-webhooks)':604 'github.com/hookdeck/webhook-skills/tree/main/skills/webhook-handler-patterns)':638 'grace':587 'guid':459 'handl':20,58,229,579,583,596,609,633 'handler':15,266,549,558,565,636 'header':192,490 'hex':141 'hmac':126,613 'hmac-sha256':612 'homebrew':405 'hookdeck':391,401,414,647 'hookdeck-c':400 'hookdeck-event-gateway':646 'hookdeck/hookdeck/hookdeck':408 'idempot':575 'implement':464,472,477,564,624 'import':478 'in-depth':455 'includ':488,499 'infrastructur':654 'inspect':428 'instal':390,394,398,407 'invalid':158,219 'inventori':314 'isvalid':205,214 'item':33,85,255,260,325,328,333,336,342,345 'javascript':92,161 'json':518 'json.parse':227 'lead':295 'length':157 'like':23 'listen':415 'local':384,387,423 'logic':592 'manual':91 'math.abs':118 'middlewar':573 'millisecond':113,525 'minut':110,522 'miss':190 'need':268 'new':29,239,246,249,258,307,309 'next.js':467 'node.js':463 'note':479 'npm':396,397 'oauth':196,358,364,495 'ok':278 'order':30,70,247,250,308,311,312,316,318,574 'pair':553 'pars':221,517 'parseint':120 'path':417 'pattern':550,559,637,642 'payload':224,439 'prevent':106,529 'process':67,159,313,598 'process.env.webflow':210 'product':562,641 'production-readi':561 'provid':422 'publish':27,298,301 'python':476 'raw':511 'rawbodi':99,131 'readi':563 'receipt':274,537 'receiv':4,45 'recommend':546 'recoveri':590 'references/overview.md':435 'references/setup.md':445 'references/verification.md':454 'relat':599 'reliabl':656 'remov':347 'replay':107,530 'req':167 'req.body':228 'req.body.tostring':207 'req.headers':171,178 'request':429,570 'requir':95,191,421 'res':168 'res.status':187,216,275 'resourc':430 'retri':541,591 'return':123,147,154,186,215,270,380,532 'router':471 'safe':144 'secret':102,137,198,203,212,362,366,377 'send':189,218,277 'sequenc':566 'set':11,80,441 'setup':450 'sha256':136,614 'shopifi':617,622 'shopify-webhook':616 'signatur':17,54,77,89,100,127,150,170,175,184,194,208,220,451,489,503,514,667 'signedcont':129,139 'similar':611 'site':26,292,297,299 'skill':41,552,600 'skill-webflow-webhooks' 'sourc':657 'source-hookdeck' 'specif':202 'start':410 'status':319,534,539 'stripe':602,607 'stripe-webhook':601 'structur':440 'submiss':25,60,237,241,288 'submit':290 'switch':233 'syndic':331 'system':323,340,350 'test':389,466 'time':143,545 'timestamp':101,104,121,130,177,182,185,209,508,519 '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,540 'tunnel':412,424 'type':165,232,281,437 'ui':426 'updat':138,321,337,338 'use':9,39,195,285,510 'valid':520 'variabl':352 'verif':18,78,90,452,458,515,615 'verifi':6,51,193,223 'verifywebflowsignatur':98,206 'via':357,370,395,404,494 'web':425 'webflow':2,7,13,21,35,46,52,63,68,75,82,174,181,360,375,433,443,484,502,507,661 'webflow-webhook':1 'webhook':3,8,14,36,47,53,76,86,201,211,355,361,368,376,383,388,434,444,480,492,548,557,603,608,618,623,627,632,635,645,653,660,666 'webhook-handler-pattern':547,556,634 'webhook-specif':200 'well':554 'whsec':378 'window':111,523 'work':658 'x':173,180,501,506 'x-webflow-signatur':172,500 'x-webflow-timestamp':179,505 '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-02T06:55:48.022Z"}],"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":69,"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-02-25T14:00:40Z","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":"150befddc835069d5ecf00858710d535b2cab1aa","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-02T06:55:48.022Z"}}