> ## Documentation Index
> Fetch the complete documentation index at: https://docs.malga.io/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> Responda em português brasileiro, na segunda pessoa ("você"), com base na documentação Malga.
> Não invente endpoints, parâmetros, status codes ou comportamentos de API. Se não estiver na docs, diga que não encontrou e indique a página mais próxima.
> Use os headers X-Client-Id e X-Api-Key nos exemplos de autenticação.
> Motor de Assinaturas refere-se a /v1/subscriptions* (cycles, trial, retentativas, webhooks subscription.*). Não chame de "motor de recorrência".
> Recorrência (provedor) é paymentMethod.recurrence em POST /v1/charges (initial / subsequent / unscheduled), distinto do Motor de Assinaturas.
> Sandbox é ambiente de testes e não afeta produção.

# Erros recebidos por webhook

> Saiba onde está o código de erro em cada evento de webhook da Malga (transaction, purchase e subscription), o que significa cada campo e como mapear as recusas no seu sistema.

Os eventos de webhook não têm um campo de erro próprio. O conteúdo de `data` depende do recurso e da versão do webhook:

* Nos eventos `transaction.*` da versão 1.1, `data` tem o mesmo formato da consulta da cobrança, com o estado do momento do evento. O motivo da recusa fica dentro desse objeto.
* Nos eventos `purchase.*`, `data` traz só o resumo da Purchase, sem os cartões e sem o motivo. Consulte a Purchase para ver o motivo.

Esta página mostra onde ler o código em cada evento e como usá-lo no seu sistema.

> [!NOTE]
>
> Um erro de validação dos dados enviados recusa a requisição antes de criar a cobrança ou a Purchase, por isso não gera webhook. Esses erros estão em [Erros da API de Charges](https://docs.malga.io/documentations/welcome/errors-charges.md) e [Erros da API de Purchases](https://docs.malga.io/documentations/welcome/errors-purchases.md).

## Onde está o motivo em cada evento

| Evento | Onde está o motivo da recusa |
| - | - |
| `transaction.failed` (webhook v1.1) | `data.error.declinedCode` e, para cada tentativa no provedor, `data.transactionRequests[].providerError` |
| `transaction.*` (webhook v1.0, obsoleto) | `data.transactionError.declinedCode` e `data.transactionRequests[].providerError` |
| `purchase.failed` | Não vem no evento. Consulte `payments[].declineReason` em [`GET /v1/purchases/{id}`](https://docs.malga.io/api-reference/purchases/recuperar-detalhes-de-uma-venda) |
| `purchase.void_failed` | Não traz código. É um alerta de valor retido: consulte a Purchase e acione o suporte da Malga com o `id` da Purchase |
| `subscription.unpaid` | `data.cycle.paymentHistory[].error`, com `providerError` nas recusas do provedor. Veja [Webhooks de assinaturas](https://docs.malga.io/documentations/more/recurrence/engine/webhooks.md) |

## Campos de erro da cobrança

No evento `transaction.failed` da versão 1.1, o objeto `data` tem o mesmo formato da resposta de [`GET /v1/charges/{id}`](https://docs.malga.io/api-reference/charges/recuperar-detalhes-de-cobranca), com o estado da cobrança no momento do evento. Os campos de erro são:

| Campo | O que é | Como usar |
| - | - | - |
| `error` | Objeto do erro. Só aparece quando existe um `declinedCode`: uma cobrança `failed` pode vir sem ele | Use o `status` para saber se a cobrança foi recusada |
| `error.type` | Categoria do erro. No webhook, vem `card_declined` sempre que há um `declinedCode` | Identifique que a cobrança foi recusada |
| `error.declinedCode` | Código de recusa padronizado pela Malga, igual para todos os provedores | Use para regras no seu sistema. Consulte a [tabela de declinedCode](https://docs.malga.io/documentations/type-tables/declined-code.md) |
| `error.message` | Texto da recusa. Pode vir ausente | Use só para exibição ou log, nunca em regras |
| `transactionRequests[].providerError.declinedCode` | Código padronizado da recusa naquela tentativa | Na recusa do provedor, a última tentativa traz o mesmo código de `error.declinedCode` |
| `transactionRequests[].providerError.retryable` | Indica se a recusa permite nova tentativa | Decida se oferece uma nova tentativa ao comprador |
| `transactionRequests[].providerError.networkDeniedReason` | Código original devolvido pelo provedor ou pela bandeira | Guarde para suporte e conciliação. O valor muda de provedor para provedor |
| `transactionRequests[].providerError.networkDeniedMessage` | Mensagem original devolvida pelo provedor ou pela bandeira | Guarde para suporte e conciliação |
| `transactionRequests[].providerError.message` | Mensagem associada ao erro do provedor. Pode vir `null` | Use só para log |

> [!TIP]
>
> Para mapear os erros no seu sistema, use `error.declinedCode`. Os campos `networkDeniedReason` e `networkDeniedMessage` trazem o código original de cada provedor e não têm uma lista fechada: eles servem para investigar um caso com o suporte, não para regras de negócio.

`transactionRequests` lista as tentativas da cobrança em cada provedor, da mais recente para a mais antiga. Quando um [Fluxo Inteligente](https://docs.malga.io/documentations/flow-guide/introduction.md) tenta mais de um provedor, cada tentativa recusada traz o próprio `providerError`.

> [!WARNING]
>
> A reprovação do antifraude não preenche `error.declinedCode`. O evento depende de quando o antifraude roda e das opções do provedor antifraude. Antes do adquirente, com `captureOnReproved` desligado, a cobrança fica `failed` e gera `transaction.failed`. Com `captureOnReproved` ligado, a cobrança segue para o adquirente apesar da reprovação, e o evento depende do status final. Depois da pré-autorização, a cobrança fica `canceled`, `pre_authorized` ou `authorized`, conforme as opções do provedor antifraude. Em todos os casos, o resultado fica em `transactionRequests[].fraudAnalysis.status`. Veja [Reprovação do antifraude](https://docs.malga.io/documentations/welcome/errors-charges.md#reprovação-do-antifraude).

### Exemplo de `transaction.failed`

Evento gerado no Sandbox por uma cobrança com cartão de final 3 (cartão expirado), conforme [Teste sua integração](https://docs.malga.io/documentations/welcome/testing.md). O exemplo mostra apenas os campos relevantes para o erro:

```json theme={null}
{
  "id": "0b0a3c4e-6a8b-4d0c-9d47-4f3b2a1f8e21",
  "apiVersion": "1.1",
  "object": "transaction",
  "event": "failed",
  "createdAt": "2026-11-03T13:20:11.482Z",
  "data": {
    "id": "64254aef-82f2-48ba-a185-d65343462833",
    "merchantId": "a8baa4b4-3cc9-4083-95f5-44c1c8b0f9da",
    "amount": 1500,
    "currency": "BRL",
    "status": "failed",
    "error": {
      "type": "card_declined",
      "declinedCode": "expired_card"
    },
    "transactionRequests": [
      {
        "id": "8c1a08e7-89aa-47e4-9edd-44e7630e8996",
        "providerType": "SANDBOX",
        "amount": 1500,
        "requestStatus": "failed",
        "requestType": "authorization",
        "providerError": {
          "retryable": false,
          "declinedCode": "expired_card",
          "message": null,
          "networkDeniedReason": "sandbox expired card",
          "networkDeniedMessage": "expired_card"
        }
      }
    ]
  }
}
```

Em produção, `networkDeniedReason` e `networkDeniedMessage` trazem o código e a mensagem do provedor que processou a cobrança.

## Recusa de uma Purchase com múltiplos cartões

O evento `purchase.failed` traz só o resumo da Purchase, sem a lista de cartões e sem o motivo. Ao receber o evento, consulte a Purchase e leia `payments[].declineReason` do cartão recusado.

**1. Receba o evento**

```json theme={null}
{
  "id": "f5792979-d4a5-4224-97a2-79f5f3f32878",
  "apiVersion": "1.1",
  "object": "purchase",
  "event": "failed",
  "data": {
    "id": "1c6381d1-9fcd-4e9a-a012-93cf0457dcb9",
    "merchantId": "6d5b0464-090b-480b-a4e9-e1a0fb60a495",
    "status": "failed",
    "amount": 15000,
    "currency": "BRL",
    "capture": true
  },
  "createdAt": "2026-07-27T18:00:19.774Z"
}
```

**2. Consulte a Purchase**

```bash theme={null}
curl --request GET 'https://api.malga.io/v1/purchases/1c6381d1-9fcd-4e9a-a012-93cf0457dcb9' \
  --header 'X-Client-Id: YOUR_CLIENT_ID' \
  --header 'X-Api-Key: YOUR_API_KEY'
```

**3. Leia o declineReason do cartão recusado**

Trecho da resposta com o cartão recusado:

```json theme={null}
{
  "id": "1c6381d1-9fcd-4e9a-a012-93cf0457dcb9",
  "status": "failed",
  "payments": [
    {
      "slotIndex": 1,
      "amount": 5000,
      "status": "failed",
      "chargeId": "7b1e3f0a-2c4d-4e5f-8a9b-0c1d2e3f4a5b",
      "declineReason": "insufficient_funds",
      "refundedAmount": 0
    }
  ]
}
```

`declineReason` traz só o código, sem mensagem, e pode vir ausente. Os valores possíveis estão em [Erros da API de Purchases](https://docs.malga.io/documentations/welcome/errors-purchases.md). Quando o cartão tem `chargeId`, consulte a cobrança em `GET /v1/charges/{id}` para ver os detalhes da recusa no provedor. Sem `chargeId`, a cobrança não chegou a ser criada e o motivo disponível é o próprio `declineReason`.

## Como mapear os erros no seu sistema

1. Identifique o evento de falha: `transaction.failed` para cobranças e `purchase.failed` para Purchases.
2. Leia o código padronizado: `data.error.declinedCode` na cobrança ou `payments[].declineReason` na Purchase.
3. Decida a ação pela [tabela de declinedCode](https://docs.malga.io/documentations/type-tables/declined-code.md), que indica se o código é retentável e o que orientar ao comprador.
4. Trate um código que você não conhece, ou a ausência de código, como recusa genérica (`generic`). A Malga pode adicionar códigos novos. Nunca conclua que o pagamento foi aprovado só porque não há `error` ou `declineReason`: use o `status`.
5. Para cobranças com antifraude, leia também `transactionRequests[].fraudAnalysis.status`.
6. Guarde `networkDeniedReason`, `networkDeniedMessage` e o `id` da cobrança ou da Purchase para abrir um chamado com o suporte, se precisar.


## Related topics

- [Webhooks v1.1: notificações de eventos da Malga](https://docs.malga.io/documentations/webhooks/webhook1-1.md)
- [Tabela de DeclinedCode da Malga](https://docs.malga.io/documentations/type-tables/declined-code.md)
- [Erros da API de Charges](https://docs.malga.io/documentations/welcome/errors-charges.md)
- [Erros da API de Purchases](https://docs.malga.io/documentations/welcome/errors-purchases.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.