跳转到主要内容

Documentation Index

Fetch the complete documentation index at: https://waffo.com/docs/llms.txt

Use this file to discover all available pages before exploring further.

每个 Webhook 请求的 Header 都包含 X-SIGNATURE,该签名使用 Waffo 私钥生成。商户必须使用 Waffo 公钥来验证签名。

获取 Waffo 公钥

登录 Merchant PortalIntegration 菜单,即可查看和复制 Waffo 公钥。
需要 DevAdmin 角色权限才能访问该页面。

推荐方式:使用 SDK

SDK 的 handleWebhook() 方法会自动执行签名验证、事件解析、路由以及响应签名:
app.post('/webhook', express.raw({ type: 'application/json' }), async (req, res) => {
  const body = req.body.toString();
  const signature = req.headers['x-signature'] as string;

  const result = await waffo.webhook().handleWebhook(body, signature);

  res.setHeader('X-SIGNATURE', result.responseSignature);
  res.setHeader('Content-Type', 'application/json');
  res.status(200).send(result.responseBody);
});

手动验证

如果你需要手动处理(不使用 SDK),验证步骤如下:
1

获取签名

从请求 Header 中获取 X-SIGNATURE
2

获取原始 Body

获取原始请求 Body 字符串(不要先 JSON parse 再 stringify)。
3

验证签名

使用 Waffo 公钥 + SHA256WithRSA 验证签名。
4

处理事件

在签名验证通过后处理事件。
5

对响应签名

你必须在响应中设置 X-SIGNATURE Header(使用商户私钥对响应 body 进行签名)。

手动示例

import { createVerify, createSign } from 'crypto';

function verifyWaffoSignature(body: string, signature: string): boolean {
  const verify = createVerify('SHA256');
  verify.update(body);
  return verify.verify(process.env.WAFFO_PUBLIC_KEY!, signature, 'base64');
}

function signResponse(responseBody: string): string {
  const sign = createSign('SHA256');
  sign.update(responseBody);
  return sign.sign(process.env.MERCHANT_PRIVATE_KEY!, 'base64');
}

app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
  const body = req.body.toString();
  const signature = req.headers['x-signature'] as string;

  if (!verifyWaffoSignature(body, signature)) {
    const failedBody = JSON.stringify({ message: 'failed' });
    res.setHeader('X-SIGNATURE', signResponse(failedBody));
    return res.status(200).send(failedBody);
  }

  // 处理事件...

  const successBody = JSON.stringify({ message: 'success' });
  res.setHeader('X-SIGNATURE', signResponse(successBody));
  res.status(200).send(successBody);
});

注意事项

  • 你必须在处理事件之前验证签名。不要先响应再验证。
  • 响应必须包含 X-SIGNATURE Header,否则 Waffo 会将该次投递视为失败。
  • 使用原始请求 body 来验证签名;不要先 JSON parse 再 stringify。
  • SDK 提供了完整的 webhook 处理流水线。相比手动处理,推荐使用 SDK。