# Webhooks no sandbox (/docs/pix-processamento/sandbox/webhooks)

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

  <QuickLink href="/docs/pix-processamento/sandbox/credencial" title="Gerar credencial" />

  <QuickLink href="/docs/pix-processamento/sandbox/cenarios" title="Cenários de teste" />

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

Em produção, um webhook cadastrado em [`POST /v1/user/webhooks`](/docs/pix-processamento/endpoints/webhooks/post_user_webhook) recebe entregas imediatamente. No sandbox, qualquer pessoa pode gerar credencial e apontar um webhook para onde quiser, então a entrega só começa depois que a URL prova que é sua:

1. Ao cadastrar, o sandbox faz um `POST` na URL com o token no header `X-Callback-Challenge` e corpo `{}`.
2. O endpoint responde `2xx` ecoando o token, no corpo puro ou em `{"challenge":"<token>"}`.
3. Até passar, o webhook fica `pending` e nenhuma entrega sai.

O token vai só no header, então um serviço que devolve o corpo recebido não passa: só passa quem lê o header de propósito. A URL precisa ser HTTPS pública; endereços privados e redirecionamentos são recusados.

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

  <FlowArrow label="seu endpoint ecoa o token" />

  <FlowNode title="verified" subtitle="entregas começam" />
</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);
});
```

## Cadastrar o webhook [#cadastrar-o-webhook]

Cadastre a URL com segredo para testar a assinatura. O `secret` volta uma única vez na resposta.

```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}'
```

Confirme que a posse foi verificada antes de seguir: `GET /sandbox/webhooks/{id}/challenge` deve responder `"status": "verified"`.

## Consultar e repetir a verificação [#consultar-e-repetir-a-verificação]

Quando a entrega não acontece, consulte o motivo:

```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` ou `failed`. Depois de corrigir o endpoint, `POST /sandbox/webhooks/{id}/challenge` repete a verificação. As entregas seguem o formato e a assinatura de produção: ver [Verificação HMAC](/docs/pix-processamento/webhooks#verificação-hmac).