Webhook
把 Surpasso 文章发送到 Make、Zapier、n8n、Lovable 或自建网站。
如果网站不属于现成的发布平台,可以使用 Webhook。每次发送文章时,Surpasso 会把 完整文章作为一个安全的 HTTPS 请求发送给自动化流程或网站。
使用 Make 的最简单方法
- 在 Make 中创建一个 Scenario。
- 第一个模块选择 Webhooks → Custom webhook。
- 创建 Webhook,复制 Make 提供的 HTTPS 地址。
- 点击 Run once,让 Make 开始等待 Surpasso 的测试请求。
- 在 Surpasso 选择 Webhook,填写连接名称并粘贴 Make 地址。
- 点击 创建并发送测试。
- 复制只显示一次的签名密钥,并安全保存。
- 在 Make 中添加负责创建或更新 CMS 文章的动作,并对应
article中的字段。 - 开启 Scenario,再从 Surpasso 发布一篇测试文章。
第一次连接测试不包含文章内容。发送第一篇草稿或正式文章后,Make 才会看到完整字段。
Zapier 和 n8n
- Zapier 使用 Webhooks by Zapier → Catch Hook。
- n8n 使用 Webhook Trigger;工作流开启后复制 Production URL。
- 在接收流程处于等待状态时,把 HTTPS 地址粘贴到 Surpasso。
Zapier 官方 Catch Hook 教程 展示了添加 Webhook Trigger、复制接收地址和发送测试数据的位置。

如果使用自建 Next.js 接收端,可下载的 Starter 已包含
app/api/surpasso-webhook/route.ts。它会基于未经修改的请求正文验证 HMAC 签名、拒绝
超过 5 分钟的时间戳,并返回接收端需要保存的 delivery 和幂等字段。持久化去重记录
仍应使用你自己的数据库或 Redis。
Surpasso 会发送什么
每次请求都是 JSON POST,event 说明发生的动作:
integration.test:设置或测试连接。article.draft_created:创建网站草稿。article.published:正式发布文章。article.updated:更新网站上的已有文章。
{
"schemaVersion": "1",
"event": "article.published",
"deliveryId": "unique-delivery-id",
"idempotencyKey": "publication:unique-delivery-id",
"occurredAt": "2026-10-13T10:00:00.000Z",
"article": {
"id": "article-id",
"title": "文章标题",
"slug": "article-title",
"excerpt": "文章摘要",
"contentHtml": "<p>完整 HTML 正文</p>",
"contentMarkdown": "完整 Markdown 正文",
"metaTitle": "SEO 标题",
"metaDescription": "SEO 描述",
"canonicalUrl": "https://example.com/blog/article-title",
"author": "作者名称",
"categories": ["分类"],
"tags": ["标签"],
"featuredImage": null,
"images": []
}
}避免重复文章
临时故障可能触发重试。接收端应保存 deliveryId 或 idempotencyKey;再次收到相同
值时直接返回成功,不要创建第二篇文章。使用 article.id 找到并更新原来的 CMS 记录。
验证请求来源
请求包含 x-surpasso-event、x-surpasso-delivery、x-surpasso-timestamp 和
x-surpasso-signature。自建 Node.js 或 Next.js 接口可以验证原始正文:
import { createHmac, timingSafeEqual } from 'node:crypto';
export async function POST(request: Request) {
const body = await request.text();
const timestamp = request.headers.get('x-surpasso-timestamp') || '';
const received = (request.headers.get('x-surpasso-signature') || '').replace(
/^sha256=/,
''
);
const expected = createHmac('sha256', process.env.SURPASSO_WEBHOOK_SECRET!)
.update(`${timestamp}.${body}`)
.digest('hex');
const timestampSeconds = Number(timestamp);
const fresh =
Number.isFinite(timestampSeconds) &&
Math.abs(Date.now() / 1000 - timestampSeconds) <= 300;
const valid =
fresh &&
/^[a-f0-9]{64}$/.test(received) &&
timingSafeEqual(Buffer.from(received, 'hex'), Buffer.from(expected, 'hex'));
if (!valid) return new Response('Unauthorized', { status: 401 });
const event = JSON.parse(body);
// 用数据库唯一约束或 Redis SET NX 原子保存 event.idempotencyKey。
// 如果已经处理过,直接返回 204;否则按 event.article.id 创建或更新。
return new Response(null, { status: 204 });
}签名密钥只能放在服务端环境变量中。密钥泄露后,请断开并重新创建 Webhook。
接收端应拒绝超过 5 分钟的时间戳,并至少在整个重试周期内保存已经处理的
idempotencyKey。这两项检查可以阻止重放请求造成重复文章或旧内容覆盖。
接收地址要求
- 使用公开 HTTPS 地址,不要把请求重定向到其他地址。
- 尽快返回
2xx;耗时操作应先进入队列。 - 不能要求先打开浏览器登录。
- 能够接收
application/json请求。
常见问题
**连接测试失败:**确认工作流已开启、填写的是 Production URL,并会返回 2xx。
Make 用户需要先点击 Run once。
**出现重复文章:**使用 idempotencyKey 去重,并用 article.id 更新原记录。
**签名无效:**必须使用未经解析的原始请求正文计算签名。