# 沙盒中的 Webhook (/zh/docs/pix-processamento/sandbox/webhooks)

<QuickLinks>
  <QuickLink href="/docs/pix-processamento/sandbox" title="Sandbox" />

  <QuickLink href="/docs/pix-processamento/sandbox/credencial" title="生成凭证" />

  <QuickLink href="/docs/pix-processamento/sandbox/cenarios" title="测试场景" />

  <QuickLink href="/docs/pix-processamento/webhooks" title="Webhooks" />
</QuickLinks>

在生产环境，通过 [`POST /v1/user/webhooks`](/docs/pix-processamento/endpoints/webhooks/post_user_webhook) 注册的 webhook 会立即收到投递。在沙盒中，任何人都可以生成凭证并把 webhook 指向任意地址，因此只有在 URL 证明归你所有之后才开始投递：

1. 注册时，沙盒向该 URL 发送 `POST`，token 放在 `X-Callback-Challenge` header 中，body 为 `{}`。
2. endpoint 返回 `2xx` 并回显 token，可以是纯文本 body，也可以是 `{"challenge":"<token>"}`。
3. 在通过之前，webhook 保持 `pending`，不会发出任何投递。

token 只出现在 header 中，因此把收到的 body 原样返回的服务无法通过：只有主动读取 header 的 endpoint 才能通过。URL 必须是公开 HTTPS；私有地址和重定向会被拒绝。

<Flow>
  <FlowNode title="Sandbox" subtitle="POST + X-Callback-Challenge" />

  <FlowArrow label="你的 endpoint 回显 token" />

  <FlowNode title="verified" subtitle="开始投递" />
</Flow>

```js
app.post('/webhook', (req, res) => {
  const challenge = req.get('X-Callback-Challenge');
  if (challenge) return res.status(200).json({ challenge });
  return handleCallback(req, res);
});
```

## 注册 webhook [#注册-webhook]

注册带 secret 的 URL，用于测试签名。`secret` 只在响应中出现一次。

```bash
curl -X POST https://pix.sandbox.payzu.dev/v1/user/webhooks \
  -H "Authorization: Bearer $SANDBOX_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://sua-app.com.br/webhook","generateSecret":true}'
```

继续之前，请确认归属已验证：`GET /sandbox/webhooks/{id}/challenge` 应返回 `"status": "verified"`。

## 查询并重新验证 [#查询并重新验证]

当投递没有发生时，查询原因：

```bash
curl https://pix.sandbox.payzu.dev/sandbox/webhooks/$WEBHOOK_ID/challenge \
  -H "Authorization: Bearer $SANDBOX_TOKEN"
```

```json
{
  "webhookId": "cmh2k1x9d0001s6bwjb5bez01",
  "url": "https://sua-app.com.br/webhook",
  "status": "failed",
  "detail": "o endpoint respondeu 2xx sem ecoar o token, no corpo ou em {\"challenge\"}",
  "checkedAt": "2026-08-23T12:00:00.000Z"
}
```

`status` 为 `pending`、`verified` 或 `failed`。修复 endpoint 后，`POST /sandbox/webhooks/{id}/challenge` 会重新验证。投递的格式和签名与生产一致：见 [HMAC 验证](/docs/pix-processamento/webhooks#verificação-hmac)。