Como criar endpoints de webhook, gerenciar secrets e validar assinaturas HMAC-SHA256 para garantir a autenticidade das notificações.
Para receber notificações, crie um endpoint de webhook pelo painel ou via API:
curl -X POST https://api.payhubr.com/v1/postbacks/endpoints \
-H "Authorization: Basic {credentials}" \
-H "Content-Type: application/json" \
-d '{
"url": "https://meusite.com/webhooks",
"events": ["charge.captured", "charge.refunded", "charge.failed"]
}'A resposta inclui o secret do endpoint, que será exibido apenas uma vez:
{
"data": {
"id": "uuid-do-endpoint",
"url": "https://meusite.com/webhooks",
"secret": "a1b2c3d4e5f6...",
"events": ["charge.captured", "charge.refunded", "charge.failed"],
"status": "active",
"created_at": "2026-02-24T10:00:00.000Z"
}
}Copie e guarde o secret imediatamente. Ele não será exibido novamente. Se perder, será necessário regenerar.
Cada endpoint pode ser atualizado individualmente:
PATCH /v1/postbacks/endpoints/{id} com { "url": "nova-url" }PATCH /v1/postbacks/endpoints/{id} com { "events": ["charge.captured"] }PATCH /v1/postbacks/endpoints/{id} com { "status": "paused" } ou { "status": "active" }DELETE /v1/postbacks/endpoints/{id}Toda notificação inclui o header X-SoarLabz-Signature com uma assinatura HMAC-SHA256 do corpo da requisição. Use essa assinatura para verificar que a notificação realmente veio da PayHub.
Cada endpoint tem seu próprio secret, gerado automaticamente na criação. Você pode regenerar o secret a qualquer momento via POST /v1/postbacks/endpoints/{id}/secret/regenerate.
O valor segue o formato sha256=<hex>.
Use o secret do endpoint como chave.
Use comparação em tempo constante para evitar timing attacks.
const crypto = require('crypto');
function validateSignature(body, signature, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(body)
Nunca exponha o secret em código client-side ou repositórios públicos. Trate-o como uma credencial sensível.
import hmac
import hashlib
def validate_signature(body: str, signature: str, secret: str) -> bool:
expected = hmac.new(
secret.encode(),
body.encode(),
hashlib.sha256
).hexdigest()
received = signature.replace('sha256=', '')
return hmac.compare_digest(expected, received)function validateSignature(string $body, string $signature, string $secret): bool
{
$expected = hash_hmac('sha256', $body, $secret);
$received = str_replace('sha256=', '', $signature);
return hash_equals($expected, $received);
}