webflow-webhooks

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Webflow Webhooks

Webflow Webhook

Receive, verify, and process Webflow webhook events for form submissions, CMS changes, ecommerce orders, site publishing, and more.
接收、验证并处理Webflow webhook事件,涵盖表单提交、CMS变更、电商订单、站点发布等场景。

Quick Start Workflow

快速开始流程

Prerequisite: You need a Webflow account with an active site. For signature verification, create webhooks via the API (not the dashboard) — see Setup.
  1. Create webhook: Register a webhook via the Webflow API for your desired event type
  2. Receive events: Set up an endpoint that accepts POST requests with raw body parsing
  3. Verify signatures: Validate
    x-webflow-signature
    and
    x-webflow-timestamp
    headers
  4. Process events: Route events by
    triggerType
    and handle each accordingly
  5. Acknowledge: Return
    200
    to confirm receipt (other statuses trigger retries)
前提条件:你需要一个带有活跃站点的Webflow账户。若要进行签名验证,请通过API(而非仪表盘)创建webhook——详见设置
  1. 创建webhook:通过Webflow API为你需要的事件类型注册webhook
  2. 接收事件:设置一个支持原始请求体解析的POST请求端点
  3. 验证签名:校验
    x-webflow-signature
    x-webflow-timestamp
    请求头
  4. 处理事件:根据
    triggerType
    路由事件并分别处理
  5. 确认接收:返回
    200
    状态码确认已接收(其他状态码会触发重试)

Signature Verification

签名验证

javascript
const crypto = require('crypto');

function verifyWebflowSignature(rawBody, signature, timestamp, secret) {
  // Check timestamp to prevent replay attacks (5 minute window - 300000 milliseconds)
  const currentTime = Date.now();
  if (Math.abs(currentTime - parseInt(timestamp)) > 300000) {
    return false;
  }

  // Generate HMAC signature
  const signedContent = `${timestamp}:${rawBody}`;
  const expectedSignature = crypto
    .createHmac('sha256', secret)
    .update(signedContent)
    .digest('hex');

  // Timing-safe comparison
  try {
    return crypto.timingSafeEqual(
      Buffer.from(signature),
      Buffer.from(expectedSignature)
    );
  } catch {
    return false; // Different lengths = invalid
  }
}
javascript
const crypto = require('crypto');

function verifyWebflowSignature(rawBody, signature, timestamp, secret) {
  // Check timestamp to prevent replay attacks (5 minute window - 300000 milliseconds)
  const currentTime = Date.now();
  if (Math.abs(currentTime - parseInt(timestamp)) > 300000) {
    return false;
  }

  // Generate HMAC signature
  const signedContent = `${timestamp}:${rawBody}`;
  const expectedSignature = crypto
    .createHmac('sha256', secret)
    .update(signedContent)
    .digest('hex');

  // Timing-safe comparison
  try {
    return crypto.timingSafeEqual(
      Buffer.from(signature),
      Buffer.from(expectedSignature)
    );
  } catch {
    return false; // Different lengths = invalid
  }
}

Processing Events

事件处理

javascript
app.post('/webhooks/webflow', express.raw({ type: 'application/json' }), (req, res) => {
  const signature = req.headers['x-webflow-signature'];
  const timestamp = req.headers['x-webflow-timestamp'];

  if (!signature || !timestamp) {
    return res.status(400).send('Missing required headers');
  }

  const isValid = verifyWebflowSignature(
    req.body.toString(),
    signature,
    timestamp,
    process.env.WEBFLOW_WEBHOOK_SECRET
  );

  if (!isValid) {
    return res.status(400).send('Invalid signature');
  }

  const event = JSON.parse(req.body);

  switch (event.triggerType) {
    case 'form_submission':
      console.log('New form submission:', event.payload.data);
      break;
    case 'ecomm_new_order':
      console.log('New order:', event.payload);
      break;
    case 'collection_item_created':
      console.log('New CMS item:', event.payload);
      break;
    case 'collection_item_published':
      console.log('Published CMS items:', event.payload.items);
      break;
  }

  res.status(200).send('OK');
});
javascript
app.post('/webhooks/webflow', express.raw({ type: 'application/json' }), (req, res) => {
  const signature = req.headers['x-webflow-signature'];
  const timestamp = req.headers['x-webflow-timestamp'];

  if (!signature || !timestamp) {
    return res.status(400).send('Missing required headers');
  }

  const isValid = verifyWebflowSignature(
    req.body.toString(),
    signature,
    timestamp,
    process.env.WEBFLOW_WEBHOOK_SECRET
  );

  if (!isValid) {
    return res.status(400).send('Invalid signature');
  }

  const event = JSON.parse(req.body);

  switch (event.triggerType) {
    case 'form_submission':
      console.log('New form submission:', event.payload.data);
      break;
    case 'ecomm_new_order':
      console.log('New order:', event.payload);
      break;
    case 'collection_item_created':
      console.log('New CMS item:', event.payload);
      break;
    case 'collection_item_published':
      console.log('Published CMS items:', event.payload.items);
      break;
  }

  res.status(200).send('OK');
});

Event Types

事件类型

Webflow supports 14 webhook event types across 6 categories: Forms, Site, Pages, Ecommerce, CMS, and Comments. See references/event-types.md for the complete reference with all payload schemas and examples.
CategoryEventsRequired Scope
Forms
form_submission
forms:read
Site
site_publish
sites:read
Pages
page_created
,
page_metadata_updated
,
page_deleted
pages:read
Ecommerce
ecomm_new_order
,
ecomm_order_changed
,
ecomm_inventory_changed
ecommerce:read
CMS
collection_item_created
,
collection_item_changed
,
collection_item_deleted
,
collection_item_unpublished
,
collection_item_published
cms:read
Comments
comment_created
comments:read
Webflow支持6大分类下的14种webhook事件类型:表单、站点、页面、电商、CMS和评论。完整的参考文档包含所有负载 schema 和示例,请查看**references/event-types.md**。
分类事件所需权限范围
表单
form_submission
forms:read
站点
site_publish
sites:read
页面
page_created
,
page_metadata_updated
,
page_deleted
pages:read
电商
ecomm_new_order
,
ecomm_order_changed
,
ecomm_inventory_changed
ecommerce:read
CMS
collection_item_created
,
collection_item_changed
,
collection_item_deleted
,
collection_item_unpublished
,
collection_item_published
cms:read
评论
comment_created
comments:read

Environment Variables

环境变量

bash
undefined
bash
undefined

For webhooks created via OAuth App

For webhooks created via OAuth App

WEBFLOW_WEBHOOK_SECRET=your_oauth_client_secret
WEBFLOW_WEBHOOK_SECRET=your_oauth_client_secret

For webhooks created via API (after April 2025)

For webhooks created via API (after April 2025)

WEBFLOW_WEBHOOK_SECRET=whsec_xxxxx # Returned when creating webhook
undefined
WEBFLOW_WEBHOOK_SECRET=whsec_xxxxx # Returned when creating webhook
undefined

Best Practices

最佳实践

  1. Always verify signatures: Use HMAC-SHA256 verification for webhooks created via OAuth or API — see Verification
  2. Use raw body for verification: Never verify against parsed JSON; configure your framework accordingly
  3. Validate timestamps: Enforce a 5-minute window (300000ms) to prevent replay attacks
  4. Return 200 quickly: Acknowledge receipt immediately; process events asynchronously for heavy workloads
  5. Handle retries gracefully: Webflow retries up to 3 times on failure (10-minute intervals) — implement idempotency
  6. Use HTTPS in production: Webhook endpoints must use HTTPS for security
  1. 始终验证签名:对通过OAuth或API创建的webhook使用HMAC-SHA256验证——详见验证
  2. 使用原始请求体进行验证:绝不要对解析后的JSON进行验证;请相应配置你的框架
  3. 校验时间戳:强制执行5分钟(300000毫秒)的时间窗口以防止重放攻击
  4. 快速返回200状态码:立即确认接收;对于繁重的工作负载,异步处理事件
  5. 优雅处理重试:Webflow在请求失败时最多重试3次(间隔10分钟)——实现幂等性
  6. 生产环境使用HTTPS:Webhook端点必须使用HTTPS以保障安全

Important Notes

重要说明

  • Never handle secrets in plain text. API tokens, OAuth client secrets, and webhook signing secrets must always be stored in environment variables or a secrets manager. Never ask the user for tokens or secrets directly, and never hard-code them in source files.
  • Webhooks created through the Webflow dashboard do NOT include signature headers
  • Only webhooks created via OAuth apps or API include
    x-webflow-signature
    and
    x-webflow-timestamp
  • Timestamp validation (5 minute window - 300000 milliseconds) is critical to prevent replay attacks
  • Return 200 status to acknowledge receipt; other statuses trigger retries (up to 3 times, 10-minute intervals)
  • 绝不要明文处理密钥。API令牌、OAuth客户端密钥和webhook签名密钥必须始终存储在环境变量或密钥管理系统中。绝不要直接向用户索要令牌或密钥,也绝不要在源文件中硬编码它们。
  • 通过Webflow仪表盘创建的webhook不包含签名请求头
  • 只有通过OAuth应用或API创建的webhook才会包含
    x-webflow-signature
    x-webflow-timestamp
  • 时间戳验证(5分钟窗口 - 300000毫秒)对于防止重放攻击至关重要
  • 返回200状态码确认接收;其他状态码会触发重试(最多3次,间隔10分钟)

Reference Documentation

参考文档

Each reference file includes YAML frontmatter with
name
,
description
, and
tags
for searchability. Use the search script available in
scripts/search_references.py
to quickly find relevant references by tag or keyword.
  • references/event-types.md: Complete reference for all 14 event types with scopes, payload schemas, and examples
  • references/webhook-api.md: REST API v2 endpoints for creating, listing, getting, and deleting webhooks
  • references/overview.md: Webhook concepts, delivery behavior, limits, and security considerations
  • references/setup.md: Dashboard and API configuration, OAuth, scopes, environment setup
  • references/verification.md: HMAC-SHA256 signature verification, common gotchas, debugging
  • references/faq.md: FAQ and troubleshooting for delivery issues, signature failures, and API errors
每个参考文件都包含YAML前置元数据,包括
name
description
tags
,以便于搜索。使用
scripts/search_references.py
中的搜索脚本,可通过标签或关键词快速找到相关参考内容。
  • references/event-types.md:所有14种事件类型的完整参考,包含权限范围、负载schema和示例
  • references/webhook-api.md:用于创建、列出、获取和删除webhook的REST API v2端点
  • references/overview.md:Webhook概念、交付行为、限制和安全注意事项
  • references/setup.md:仪表盘和API配置、OAuth、权限范围、环境设置
  • references/verification.md:HMAC-SHA256签名验证、常见问题、调试方法
  • references/faq.md:交付问题、签名失败和API错误的常见问题与故障排除

Searching References

搜索参考文档

bash
undefined
bash
undefined

List all references with metadata

List all references with metadata

python scripts/search_references.py --list
python scripts/search_references.py --list

Search by tag (exact match)

Search by tag (exact match)

python scripts/search_references.py --tag <tag>
python scripts/search_references.py --tag <tag>

Search by keyword (across name, description, tags, and content)

Search by keyword (across name, description, tags, and content)

python scripts/search_references.py --search <query>
undefined
python scripts/search_references.py --search <query>
undefined

Scripts

脚本

  • scripts/search_references.py
    : Search reference files by tag, keyword, or list all with metadata
  • scripts/search_references.py
    :通过标签、关键词搜索参考文件,或列出所有带元数据的参考文件