Pular para o conteúdo principal

Webhooks de cobrança

Com callbackUrl configurada, a YumePay envia um POST a cada evento de cobrança.

{
"event": "charge.denied",
"charge": {
"id": 791,
"subscription_id": 12,
"value": 2990,
"status": "DENIED",
"due_date": "2026-10-09",
"denial_code": "05",
"denial_message": "Not Authorized",
"attempts": 1,
"next_retry_at": null
}
}
CampoDescrição
statusStatus atual da cobrança no momento da entrega: "PENDING", "CONFIRMED", "DENIED" ou "REFUNDED"
denial_code / denial_messageMotivo da recusa. Preenchidos só em cobrança negada
attemptsTentativas feitas até agora
next_retry_atPróxima retentativa, YYYY-MM-DD, ou null
EventoO que disparaQuando
charge.createdCobrança gerada no vencimentoRegistrado antes da chamada ao adquirente
charge.confirmedPagamento aprovado — na primeira tentativa ou numa retentativaLogo após a aprovação
charge.retry_scheduledTentativa negada com nova tentativa agendada. Não é negação definitiva. Só com retentativa ligadaLogo após a recusa
charge.deniedPagamento negado (definitivo, com retentativa ligada)Logo após a recusa
charge.refundedCobrança estornada pela seção Estornar uma cobrança. Status REFUNDEDLogo após o estorno
event diz o que aconteceu; charge mostra a cobrança como ela está agora

O objeto charge é lido no momento da entrega, então pode já estar à frente do evento: um charge.created que chega depois da aprovação vem com status: "CONFIRMED", e um charge.confirmed entregue depois de um estorno vem com status: "REFUNDED". Decida pelo event e use charge.status como o estado mais recente.

Qual evento libera ou bloqueia o serviço? charge.confirmed libera. charge.denied é o sinal para agir sobre a inadimplência. charge.retry_scheduled é informativo. charge.refunded indica que o valor voltou ao pagador.

Reenvio: enquanto o seu endpoint não responder 2xx, a YumePay reenvia até 10 vezes, com intervalo crescente a partir de 30 s (30 s, 1 min, 2 min, 4 min… limitado a 1 h entre tentativas).

Como testar a entrega em homologação​

Os webhooks de homologação estão ativos para todos os lojistas. Para recebê-los sem expor um servidor seu:

  1. Gere uma URL pública temporária, por exemplo em webhook.site ou com um túnel como ngrok.
  2. Crie uma assinatura com essa URL em callbackUrl e nextDueDate igual a hoje — a primeira cobrança sai na hora e dispara charge.created e charge.confirmed (ou charge.retry_scheduled / charge.denied) em menos de um minuto.
  3. Estorne essa cobrança (Estornar uma cobrança) para receber charge.refunded.
  4. Para PIX, crie uma venda PIX com callbackUrl (Cobrança PIX) e pague o QR Code.
Cartões de teste em homologação
CartãoResultado
4111111111111111Tokeniza e a cobrança é aprovada
4111111111111202 (válido, terminado em 2)Tokeniza e a cobrança volta negada com código 05 — use para testar recusa e retentativa
4111111111111112 (dígito verificador errado)400 Número do cartão inválido, sem chamar o adquirente
Validade 01/2020400 Cartão vencido
Validade 13/2030400 Data de validade inválida (use MM/AAAA)

O 422 CARD_REJECTED na tokenização não tem cartão de teste: o sandbox do adquirente tokeniza qualquer número que passe pelas validações acima.

Lembre: venda com cartão (pré-captura, captura e cancelamento, em Pagamentos avulsos) não gera webhook. Uma observação que só usou cartão avulso não recebe nada — é o esperado.

Validando a assinatura do webhook​

Vale para todos os webhooks deste guia: cobrança de assinatura, venda PIX e link de pagamento. Cada requisição vai com o cabeçalho:

X-Yumepay-Signature: sha256=<hex do HMAC-SHA256>

O HMAC é calculado sobre o corpo bruto da requisição, byte a byte. A chave secreta é entregue junto das credenciais de acesso, e é diferente entre homologação e produção.

Exemplo em Python​

import hmac, hashlib

def assinatura_confere(corpo_bruto: bytes, cabecalho: str, segredo: str) -> bool:
esperado = "sha256=" + hmac.new(segredo.encode(), corpo_bruto, hashlib.sha256).hexdigest()
return hmac.compare_digest(esperado, cabecalho)

Exemplo em Node​

const crypto = require("crypto");

function assinaturaConfere(corpoBruto, cabecalho, segredo) {
const esperado = "sha256=" + crypto.createHmac("sha256", segredo).update(corpoBruto).digest("hex");
return crypto.timingSafeEqual(Buffer.from(esperado), Buffer.from(cabecalho));
}

Regras do endpoint​

Valem para todos os webhooks deste guia: venda PIX (Webhook de venda PIX), link de pagamento (Webhook de link de pagamento) e cobrança de assinatura.

URL do endpoint​

A URL precisa ser https:// e apontar para um host público. São recusados:

  • http://;
  • usuário e senha na URL (https://user:pass@...);
  • localhost e *.localhost;
  • host que não resolve no DNS;
  • host que resolve para endereço interno (privado, loopback, link-local ou reservado).

A regra é conferida ao gravar a URL (criação e edição) e de novo a cada entrega: se o host passar a resolver para um endereço interno, o envio falha e segue a política de reenvio.

URL fora da regra devolve 400, com a mensagem da rota:

WebhookRotaMensagem
Venda PIXPOST /api/v1/online/sales/pre-capture/Webhook URL must be a safe public HTTPS URL
Link de pagamentoPOST /api/v1/payment-links/{"webhookUrl": ["Enter a safe public HTTPS URL."]}
AssinaturaCriação, edição e PUT .../callbackcallbackUrl must be a safe public HTTPS URL

Para testar, use uma URL pública temporária, como as do webhook.site ou de um túnel ngrok (ver Como testar a entrega em homologação, acima).

Ao implementar o seu endpoint​

  • Responda 2xx para confirmar o recebimento. Qualquer outro status, inclusive 3xx, é tratado como falha.
  • Responda rápido (até 10 s) e processe de forma assíncrona.
  • Seja idempotente pelo par charge.id + event: a mesma entrega pode chegar mais de uma vez, e a mesma cobrança gera vários eventos (retry_scheduled → confirmed → refunded, por exemplo).
  • Não assuma ordem de entrega. Em caso de dúvida, consulte a cobrança (Listar cobranças de uma assinatura).
  • No Express, use express.raw({ type: "application/json" }) nessa rota. No Django, leia request.body antes de qualquer parsing.