Webhooks no sandbox
Entrega só depois de provar posse da URL: o challenge X-Callback-Challenge, os status pending, verified e failed, e como repetir a verificação.
Em produção, um webhook cadastrado em POST /v1/user/webhooks 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:
- Ao cadastrar, o sandbox faz um
POSTna URL com o token no headerX-Callback-Challengee corpo{}. - O endpoint responde
2xxecoando o token, no corpo puro ou em{"challenge":"<token>"}. - Até passar, o webhook fica
pendinge 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.
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
Cadastre a URL com segredo para testar a assinatura. O secret volta uma única vez na resposta.
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}'A resposta 201 traz o webhook criado. Guarde o id: é ele o {id} das rotas de challenge, e o secret não volta em nenhuma outra resposta.
{
"id": "cmh2k1x9d0001s6bwjb5bez01",
"url": "https://sua-app.com.br/webhook",
"active": true,
"events": [],
"hasSecret": true,
"createdAt": "2026-08-23T12:00:00.000Z",
"updatedAt": "2026-08-23T12:00:00.000Z",
"secret": "EOvBvLmIqjcIg13T2_cf8NXn7K5txbakb053ZY8sPrA"
}Se perder o id, liste os webhooks da credencial com GET /v1/user/webhooks. O secret não aparece aqui, só o hasSecret:
curl -X GET https://pix.sandbox.payzu.dev/v1/user/webhooks \
-H "Authorization: Bearer $SANDBOX_TOKEN"Confirme que a posse foi verificada antes de seguir: GET /sandbox/webhooks/{id}/challenge deve responder "status": "verified".
Consultar e repetir a verificação
Quando a entrega não acontece, consulte o motivo com GET /sandbox/webhooks/{id}/challenge:
curl -X GET https://pix.sandbox.payzu.dev/sandbox/webhooks/$WEBHOOK_ID/challenge \
-H "Authorization: Bearer $SANDBOX_TOKEN"{
"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, repita a verificação com POST /sandbox/webhooks/{id}/challenge, mesma rota e sem corpo:
curl -X POST https://pix.sandbox.payzu.dev/sandbox/webhooks/$WEBHOOK_ID/challenge \
-H "Authorization: Bearer $SANDBOX_TOKEN"As entregas seguem o formato e a assinatura de produção: ver Verificação HMAC.