Eventos
Catálogo dos tipos de webhook, quando cada um é enviado e o formato exato do campo data.
Todo webhook tem o mesmo envelope, com dois campos:
{
"eventType": "payment_intent.succeeded",
"data": { "...": "retrato do recurso no momento do evento" }
}O envelope não tem identificador de evento, data de envio nem número de tentativa. O identificador para deduplicação está no cabeçalho X-DM-Webhook-Id (veja Duplicatas e ordem).
Tipos de evento
eventType | Quando é enviado |
|---|---|
payment_intent.succeeded | O pagamento foi confirmado: Pix pago (inclusive depois do prazo), cartão aprovado, Pix parcelado capturado. |
payment_intent.failed | O pagamento falhou depois de iniciado: cartão recusado após o desafio 3DS, falha de autenticação, falha na captura do Pix parcelado. Uma recusa de cartão sem 3DS, devolvida na própria resposta do create com status: "Failed", não gera este evento: trate a resposta síncrona. |
payment_intent.refunded | O estorno integral foi concluído. |
payment_intent.refund_failed | Uma tentativa de estorno falhou. |
payment_intent.charged_back | O emissor contestou uma cobrança de cartão (chargeback), ou um alerta de contestação levou à devolução preventiva. |
Trate tipos desconhecidos sem erro: responda 200, registre e ignore. Novos tipos podem ser adicionados sem aviso prévio.
O formato do status muda entre eventos
Em succeeded e failed, data.status vem em PascalCase ("Succeeded", "Failed"), como na consulta. Nos eventos de estorno e contestação, vem em minúsculas com sublinhado ("refunded", "refund_failed", "charged_back"). Na consulta, um estorno concluído aparece como "Refund". Mapeie os três formatos; não use um único enum.
payment_intent.succeeded
{
"eventType": "payment_intent.succeeded",
"data": {
"id": "8b727267-bf39-48a4-91ea-eb0780cb48a9",
"object": "payment_intent",
"amount": 1990,
"currency": "BRL",
"status": "Succeeded",
"merchantId": "3c1d6a2e-5b7f-4e8a-9c0d-1e2f3a4b5c6d",
"customer": {
"name": "Cliente de Teste",
"email": "cliente@example.com",
"document": null,
"documentType": null,
"phone": null,
"birthDate": null,
"address": null
},
"paymentMethods": [
{ "type": "Pix", "amount": 1990, "currency": "BRL", "card": null, "pix": { "pixKeyType": "RANDOM", "expiresInMinutes": 30 } }
],
"split": null,
"pixPayment": {
"endToEndId": "E00000000202609081504A1b2C3d4E5f",
"qrCodeEmv": "00020126...",
"expiresAt": "2026-09-08T15:30:00Z"
},
"metadata": { "orderId": "pedido-pix-1001" },
"createdAt": "2026-09-08T15:00:00Z",
"succeededAt": "2026-09-08T15:04:12+00:00"
}
}Campo de data | Descrição |
|---|---|
id | Identificador do PaymentIntent. É o mesmo id da resposta do create. |
amount, currency | Valor em centavos e moeda. Compare com o pedido antes de concluir. |
status | "Succeeded". |
merchantId | Conta que recebeu a cobrança. |
customer | Comprador, como enviado no create, com documentType calculado. Campos não enviados vêm null. |
paymentMethods[] | Método usado. Em cartão, card traz brand, bin, last4, expMonth, expYear, holderName, maskedNumber, cardTokenUid (se cobrado com token) e threeDs (used, liabilityShift). Em Pix, pix traz pixKeyType e expiresInMinutes. |
split | Regras de divisão com o valor calculado em allocatedAmount, em centavos. null quando a cobrança não tem split. |
pixPayment | Em Pix: endToEndId identifica a transferência no Banco Central. pixPayment.status registra a geração do QR Code, não o estado do pagamento: use data.status. |
metadata | O objeto que você enviou no create. |
createdAt | Criação da cobrança. |
succeededAt | Momento da confirmação. |
payment_intent.failed
{
"eventType": "payment_intent.failed",
"data": {
"id": "e092c6cc-8d6f-47d3-8616-df99670286dd",
"object": "payment_intent",
"amount": 10000,
"currency": "BRL",
"status": "Failed",
"statusDetail": "AUTHENTICATION_FAILED",
"lastPaymentError": {
"code": "51",
"reason": "Insufficient funds",
"category": "issuer_decline"
},
"merchantId": "3c1d6a2e-5b7f-4e8a-9c0d-1e2f3a4b5c6d",
"metadata": { "orderId": "pedido-card-1001" },
"createdAt": "2026-09-08T15:00:00Z",
"failedAt": "2026-09-08T15:04:12+00:00"
}
}Os demais campos seguem o formato de succeeded. A diferença está no erro:
| Campo | Descrição |
|---|---|
statusDetail | Detalhe técnico do estado final, como AUTHENTICATION_FAILED. Lista aberta: trate valores desconhecidos. |
lastPaymentError.code | Código da recusa. Use-o para decidir a mensagem ao comprador. |
lastPaymentError.reason | Texto da recusa. No create e no GET, o mesmo texto está em lastPaymentError.message. |
lastPaymentError.category | Agrupamento da recusa, como issuer_decline. Pode vir null. |
failedAt | Momento da falha. |
payment_intent.refunded
{
"eventType": "payment_intent.refunded",
"data": {
"id": "8b727267-bf39-48a4-91ea-eb0780cb48a9",
"object": "payment_intent",
"status": "refunded",
"amount": 1990,
"currency": "BRL",
"merchantId": "3c1d6a2e-5b7f-4e8a-9c0d-1e2f3a4b5c6d",
"split": null,
"refundId": "rfnd_EXEMPLO",
"refundedAt": "2026-09-08T16:00:00.0000000Z",
"refundOrigin": "MerchantRequest"
}
}data.id identifica o pagamento e data.refundId identifica a tentativa de estorno. O valor é sempre o integral da cobrança. refundOrigin é MerchantRequest quando o estorno foi pedido pela sua integração.
payment_intent.refund_failed
{
"eventType": "payment_intent.refund_failed",
"data": {
"id": "8b727267-bf39-48a4-91ea-eb0780cb48a9",
"object": "payment_intent",
"status": "refund_failed",
"amount": 1990,
"currency": "BRL",
"merchantId": "3c1d6a2e-5b7f-4e8a-9c0d-1e2f3a4b5c6d",
"refundId": "rfnd_EXEMPLO",
"reason": "MOTIVO_RETORNADO_PELA_API",
"reasonDescription": null,
"failedAt": "2026-09-08T16:00:00.0000000Z"
}
}Depois de refund_failed, uma nova solicitação de estorno é permitida. Veja Estornos.
payment_intent.charged_back
Enviado quando uma cobrança de cartão é contestada pelo portador junto ao emissor, ou quando um alerta de contestação leva a uma devolução preventiva.
{
"eventType": "payment_intent.charged_back",
"data": {
"id": "e092c6cc-8d6f-47d3-8616-df99670286dd",
"object": "payment_intent",
"status": "charged_back",
"amount": 10000,
"currency": "BRL",
"merchantId": "3c1d6a2e-5b7f-4e8a-9c0d-1e2f3a4b5c6d",
"chargebackOrigin": "acquirer",
"isChargebackNotification": false,
"chargedBackAt": "2026-10-02T12:00:00.0000000Z",
"refundId": null,
"refundedAt": null,
"refundOrigin": null,
"split": null
}
}| Campo | Descrição |
|---|---|
chargebackOrigin | notification (aviso preventivo, que pode vir com devolução ao comprador) ou acquirer (contestação confirmada pelo adquirente). |
isChargebackNotification | true para o aviso preventivo. |
refundId, refundedAt, refundOrigin | Preenchidos quando houve devolução preventiva. |
A mesma cobrança pode receber um charged_back de origem notification e, depois, outro de origem acquirer. Quando os dois existirem, vale o de acquirer. Deduplique pelo par data.id + data.chargebackOrigin.
Formato dos campos
- Datas estão em ISO 8601. O sufixo pode ser
Zou+00:00, e a fração de segundo pode ter até sete dígitos. Use um parser que aceite as variações. - Campos sem valor vêm como
nullexplícito. Campos novos podem aparecer: o seu leitor de JSON deve ignorar o que não conhece. - Caracteres fora do ASCII podem chegar escapados (
"São Paulo"). É JSON válido; não altere o corpo antes de verificar a assinatura.