Autenticação de Webhooks
Todos os webhooks enviados pela API do Pagou, incluindo eventos de boletos (ex.: charge.created, charge.paid) e Pix (ex.: qrcode.completed, qrcode.refunded), incluem os headers X-Pagou-Signature e X-Pagou-Timestamp para verificar a autenticidade e integridade das notificações. Esta seção detalha como validar esses headers, incluindo o processo de verificação da assinatura HMAC-SHA256 e do timestamp, exemplos de código em Python e JavaScript, e boas práticas para segurança.
Visão Geral Técnica
Os webhooks da API do Pagou são enviados como requisições HTTP POST com corpo JSON para o notification_url configurado (ex.: https://your-webhook.com/notifications). Cada webhook inclui dois headers de autenticação:
- X-Pagou-Signature: Assinatura HMAC-SHA256 do conteúdo- timestamp + payload(onde payload é a string JSON bruta do corpo da requisição). A assinatura é gerada com a chave de API do cliente.
- X-Pagou-Timestamp: Timestamp em segundos desde o epoch (ex.: 1754332106 para 2025-08-04 18:28:26).
Validação dos Headers
Para garantir que o webhook é confiável, valide os headers X-Pagou-Signature e X-Pagou-Timestamp:
- Obter a chave de API 
- Validar - X-Pagou-Signature:- Extraia o - <hex>do header- X-Pagou-Signature.
- Concatene o valor de - X-Pagou-Timestampcom o payload JSON bruto (ex.:- 1754329142+- {"name":"charge.created",...}).
- Calcule o HMAC-SHA256 do resultado usando a chave de API. 
- Compare o hash calculado com o - <hex>do header usando uma comparação resistente a ataques de tempo (ex.:- crypto.timingSafeEqualem JavaScript,- hmac.compare_digestem Python).
 
- Rejeitar se inválido: - Retorne - 401 Unauthorizedse a assinatura ou timestamp forem inválidos.
- Registre tentativas inválidas para monitoramento. 
 
Nota: A validação dos headers é altamente recomendada para segurança, mas os webhooks são enviados mesmo que a validação não seja implementada.
Exemplos de Código
const crypto = require('crypto');
function verifySignature(payload, timestamp, signature, secret) {
    const receivedDigest = signature;
    const message = timestamp + payload;
    const hmac = crypto.createHmac('sha256', secret);
    hmac.update(message);
    const computedDigest = hmac.digest('hex');
    
    try {
        const receivedBuffer = Buffer.from(receivedDigest, 'hex');
        const computedBuffer = Buffer.from(computedDigest, 'hex');
        
        if (receivedBuffer.length !== computedBuffer.length) {
            return false;
        }
        
        return crypto.timingSafeEqual(receivedBuffer, computedBuffer);
    } catch (e) {
        return false;
    }
}
// Example usage:
const payload = '{"name":"charge.created","data":{"id":"7a86b3b7-779e-4e9f-af7d-bf2e512ddae1","transaction_id":"0","client_code":"7a86b3b7-779e-4e9f-af7d-bf2e512ddae1","payload":{"transaction_id":"123","bank_emissor":"bradesco","bank_number":"137","bank_agency":"0001","bank_account":"12345678","bar_code":"123456789098765434321","line":"1234323465654758868986","bank_assignor":"Celcoin"}}}';
const timestamp = '1754329886'; // From X-Pagou-Timestamp header
const signature = 'ff502eeda47ceb3a6c0dc32a34d9503f32224f6fd8c9ad30a25c0f7cf0ca358c'; // From X-Pagou-Signature header
const apiKey = '07ab896a-d830-418b-8c55-47874dc6760e'; // API Key
const isValid = verifySignature(payload, timestamp, signature, apiKey);
console.log('Signature valid:', isValid);Boas Práticas Técnicas
- Segurança: Sempre valide - X-Pagou-Signaturee- X-Pagou-Timestamppara garantir a origem e integridade do webhook.
- Comparação Segura: Use funções como - crypto.timingSafeEqual(JavaScript) ou- hmac.compare_digest(Python) para evitar ataques de tempo.
- Prevenção de Replay Attacks: Rejeite webhooks com - X-Pagou-Timestampfora de ±5 minutos do horário atual.
- Monitoramento: Registre - X-Pagou-Timestamp,- X-Pagou-Signature, e resultados da validação em logs para auditoria.
- HTTPS: Use um certificado SSL válido para o - notification_url.
import hmac
import hashlib
def verify_signature(payload, timestamp, signature, secret):
    message = timestamp + payload
    computed_digest = hmac.new(
        key=secret.encode('utf-8'),
        msg=message.encode('utf-8'),
        digestmod=hashlib.sha256
    ).hexdigest()
    
    return hmac.compare_digest(computed_digest, signature)
# Example usage:
payload = '{"name":"charge.created","data":{"id":"7a86b3b7-779e-4e9f-af7d-bf2e512ddae1","transaction_id":"0","client_code":"7a86b3b7-779e-4e9f-af7d-bf2e512ddae1","payload":{"transaction_id":"123","bank_emissor":"bradesco","bank_number":"137","bank_agency":"0001","bank_account":"12345678","bar_code":"123456789098765434321","line":"1234323465654758868986","bank_assignor":"Celcoin"}}}'
timestamp = '1754329886'  # From X-Pagou-Timestamp header
signature = 'ff502eeda47ceb3a6c0dc32a34d9503f32224f6fd8c9ad30a25c0f7cf0ca358c'  # From X-Pagou-Signature header
api_key = '07ab896a-d830-418b-8c55-47874dc6760e'  # API Key
is_valid = verify_signature(payload, timestamp, signature, api_key)
print('Signature valid:', is_valid)Boas Práticas Técnicas
- Segurança: Sempre valide - X-Pagou-Signaturee- X-Pagou-Timestamppara garantir a origem e integridade do webhook.
- Comparação Segura: Use funções como - crypto.timingSafeEqual(JavaScript) ou- hmac.compare_digest(Python) para evitar ataques de tempo.
- Prevenção de Replay Attacks: Rejeite webhooks com - X-Pagou-Timestampfora de ±5 minutos do horário atual.
- Monitoramento: Registre X-Pagou-Timestamp, X-Pagou-Signature, e resultados da validação em logs para auditoria. 
- HTTPS: Use um certificado SSL válido para o notification_url. 
- Testes: Valide webhooks no ambiente sandbox (https://sandbox.api.pagou.com.br/v1) usando ferramentas como ngrok. 
Last updated
