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

# Cancelando uma tentativa de pagamento

> Guia passo a passo para cancelar um Payment Intent ainda não pago, liberar uma autorização de cartão e tratar com segurança PIX pendente e confirmações tardias.

Cancelar uma tentativa significa encerrar um `payment_intent` que **ainda não
terminou em pagamento concluído**. É a operação certa quando o comprador
abandonou o fluxo, a cobrança foi criada em duplicidade, existe suspeita de
fraude antes da captura ou uma autorização de cartão não deve mais ser
capturada.

O cancelamento não substitui uma devolução. Se o dinheiro já entrou e o
`payment_intent` está `succeeded`, use um [`refund`](/payments/refund-payment).

<Info>
  Cancelamento evita ou encerra uma cobrança que ainda não foi concluída. Refund
  devolve uma cobrança que já foi paga. O `status` atual do Payment Intent
  decide qual operação usar.
</Info>

## Decisão rápida

| Status do `payment_intent` | Pode cancelar?   | Operação recomendada                                                                             |
| -------------------------- | ---------------- | ------------------------------------------------------------------------------------------------ |
| `requires_payment_method`  | Sim              | Cancele se não haverá nova tentativa.                                                            |
| `requires_confirmation`    | Sim              | Cancele antes de confirmar.                                                                      |
| `pending`                  | Sim, com cuidado | Cancele e continue acompanhando pagamentos tardios.                                              |
| `processing`               | Sim, com cuidado | Há uma corrida com a confirmação; continue acompanhando eventos.                                 |
| `requires_capture`         | Sim              | Cancele para desfazer a autorização do cartão.                                                   |
| `failed`                   | Sim              | Cancele para encerrar definitivamente o processo.                                                |
| `succeeded`                | Não              | Crie um refund.                                                                                  |
| `canceled`                 | Não novamente    | Considere a operação concluída; o mesmo request só é repetível pela mesma chave de idempotência. |

| Passo | Condição                                  | Ação                                              |
| ----- | ----------------------------------------- | ------------------------------------------------- |
| 1     | Sempre                                    | Consulte o Payment Intent.                        |
| 2     | `status = succeeded`                      | Crie um refund e encerre o fluxo de cancelamento. |
| 3     | `status = canceled`                       | Não envie outro cancelamento.                     |
| 4     | Qualquer outro status cancelável          | Envie `POST /cancel`.                             |
| 5     | O meio é síncrono e não está `processing` | Trate `payment.intent.canceled`.                  |
| 6     | O meio é assíncrono ou está `processing`  | Continue acompanhando eventos de sucesso.         |
| 7     | O dinheiro entra depois do cancelamento   | Crie um refund.                                   |
| 8     | Nenhum pagamento tardio acontece          | Considere `payment.intent.canceled` o desfecho.   |

## O que exatamente é cancelado

A API cancela o **Payment Intent identificado pelo `pi_*`**. Ela não cancela
automaticamente outros objetos do seu produto.

* O pedido no seu sistema continua sendo responsabilidade da sua aplicação.
* Um payment link reutilizável continua ativo e pode criar novas sessões.
* Uma checkout session pode ter seu próprio estado e precisa ser reconciliada
  pelos eventos de checkout.
* Uma assinatura ou invoice não deve ter seu lifecycle alterado diretamente só
  porque um Payment Intent foi cancelado; use a operação própria do recurso.

Se um payment link gerou várias compras, localize o Payment Intent da compra
correta. Não cancele um `pi_*` apenas porque ele pertence ao mesmo link.

## O que acontece com o dinheiro em cada estado

### Antes da confirmação

Em `requires_payment_method` ou `requires_confirmation`, ainda não existe valor
capturado. O cancelamento encerra o processo na Chargefy e impede novas ações
naquele Payment Intent. Nenhum dinheiro precisa voltar ao comprador.

### Cartão autorizado, mas não capturado

Em `requires_capture`, o cartão passou pela autorização, mas o valor ainda não
foi capturado. Ao cancelar, a Chargefy envia o desfazimento da autorização e
zera `amount_capturable`.

Isso evita a captura. O tempo para o limite aparecer novamente para o comprador
pode variar conforme o emissor do cartão, mesmo que a API já retorne
`status: "canceled"`.

### PIX pendente

Em `pending`, ainda não há dinheiro confirmado. O cancelamento muda o Payment
Intent para `canceled` na Chargefy, mas **não deve ser usado como prova de que um
QR code PIX já emitido ficou instantaneamente inutilizável**.

O comprador ainda pode pagar uma instrução que permaneça válida até sua
expiração. Por isso, mantenha o receiver de webhooks ativo e trate uma
confirmação tardia como dinheiro recebido: localize a charge concluída e crie
um refund.

<Warning>
  Para PIX pendente, `payment.intent.canceled` confirma o estado do Payment
  Intent na Chargefy; não garante, sozinho, a invalidação imediata do QR code.
  Continue processando eventos de sucesso e conciliando a charge até a expiração
  da instrução.
</Warning>

O mesmo cuidado vale para outros meios assíncronos, como boleto: concluir o
cancelamento no seu sistema não elimina a necessidade de observar uma
liquidação tardia.

### Pagamento em processamento

`processing` representa uma corrida: a tentativa já foi iniciada, mas o
resultado final ainda pode chegar. A API aceita o cancelamento, porém sua
integração deve continuar acompanhando eventos. Se uma charge terminar paga,
devolva o valor com um refund.

## Antes de começar

Você precisa de:

* uma API key com permissão de escrita;
* o ID do Payment Intent (`pi_*`);
* o status mais recente do objeto;
* um motivo de cancelamento, quando disponível;
* uma chave de idempotência única para a operação.

Para plataformas, envie também o header `Organization` da organização conectada
dona do Payment Intent.

## Passo a passo

<Steps>
  <Step title="Consulte o estado mais recente">
    Faça um GET imediatamente antes de decidir. Não use um status salvo há
    vários minutos: cartão e PIX podem mudar de estado enquanto o comprador
    conclui o pagamento.

    ```bash theme={"theme":"css-variables"}
    curl -X GET "https://api.chargefy.io/v1/payment-intents/pi_gK376rADQTFKc5xM" \
      -H "Authorization: Bearer {{API_KEY}}"
    ```

    Se o retorno já estiver `succeeded`, pare e crie um refund. Se estiver
    `canceled`, não envie uma nova operação de cancelamento.
  </Step>

  <Step title="Interrompa novas ações no seu produto">
    Remova o botão de pagar, feche a etapa de checkout ou marque o pedido como
    cancelamento solicitado. Isso reduz a chance de o comprador confirmar a
    cobrança enquanto seu backend envia o cancelamento.

    Não apague os IDs financeiros: você ainda precisa deles para auditoria,
    webhooks e eventual refund.
  </Step>

  <Step title="Envie o cancelamento com idempotência">
    Faça `POST /v1/payment-intents/{id}/cancel`. Envie `cancellation_reason` no
    corpo e uma chave única no header `Idempotency-Key`.
  </Step>

  <Step title="Atualize o pedido com a resposta completa">
    A resposta é o Payment Intent completo, agora com `status: "canceled"`,
    `canceled_at` preenchido e `cancellation_reason` registrado.

    Guarde esse objeto e separe o estado comercial do pedido do estado
    financeiro da tentativa.
  </Step>

  <Step title="Processe o webhook de cancelamento">
    Trate `payment.intent.canceled` de forma idempotente. Ele permite que outros
    serviços do seu sistema cheguem ao mesmo estado mesmo quando não fizeram a
    chamada diretamente.
  </Step>

  <Step title="Cubra pagamentos tardios">
    Para PIX, boleto e qualquer tentativa em `processing`, continue tratando
    eventos de sucesso. Se uma charge for confirmada depois do cancelamento do
    pedido, crie um refund em vez de tentar cancelar novamente.
  </Step>
</Steps>

## Payload do cancelamento

```bash theme={"theme":"css-variables"}
curl -X POST "https://api.chargefy.io/v1/payment-intents/pi_gK376rADQTFKc5xM/cancel" \
  -H "Authorization: Bearer {{API_KEY}}" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 550e8400-e29b-41d4-a716-446655440003" \
  -d '{
    "cancellation_reason": "requested_by_customer"
  }'
```

Os motivos aceitos são:

| `cancellation_reason`   | Quando usar                                                             |
| ----------------------- | ----------------------------------------------------------------------- |
| `abandoned`             | O comprador saiu do fluxo e a tentativa não deve mais ser usada.        |
| `duplicate`             | Outro Payment Intent representa a compra correta.                       |
| `fraudulent`            | A tentativa foi interrompida por suspeita de fraude antes da conclusão. |
| `requested_by_customer` | O comprador pediu para não continuar com o pagamento.                   |

O campo é opcional, mas registrá-lo melhora auditoria, suporte e análise de
conversão. Ele descreve por que a tentativa foi encerrada; não altera a regra
financeira da operação.

Existe um segundo conjunto de motivos — `automatic`, `expired`,
`failed_invoice` e `void_invoice` — que a Chargefy escreve sozinha e você só
recebe. Enviar um deles na requisição responde `400`. A diferença é de
autoridade: `abandoned` afirma que o comprador desistiu, e essa é a sua leitura
do negócio; `expired` afirma que o prazo acabou, e esse fato é nosso.

## Exemplo de resposta

O endpoint retorna `200 OK` com o mesmo shape completo de
[`GET /v1/payment-intents/{id}`](/api-reference/payment-intents/get). Este é um
recorte dos campos mais importantes:

```json theme={"theme":"css-variables"}
{
  "id": "pi_gK376rADQTFKc5xM",
  "object": "payment_intent",
  "...": "demais campos do Payment Intent",
  "amount_capturable": 0,
  "canceled_at": "2026-07-17T15:00:00Z",
  "cancellation_reason": "requested_by_customer",
  "status": "canceled",
  "updated_at": "2026-07-17T15:00:00Z"
}
```

### O que a resposta confirma

* O Payment Intent foi encerrado na Chargefy.
* Ele não pode ser confirmado ou capturado novamente.
* Em `requires_capture`, a autorização foi desfeita antes de a resposta de
  sucesso ser retornada.
* O motivo e o horário do cancelamento foram registrados.

### O que a resposta não confirma

* Que o pedido comercial foi cancelado no seu sistema.
* Que um payment link reutilizável foi desativado.
* Que um QR code PIX já emitido ficou imediatamente inválido.
* Que não haverá confirmação tardia de uma tentativa que estava `pending` ou
  `processing`.
* Que um pagamento já concluído foi devolvido.

## Webhooks e reconciliação

O evento principal é `payment.intent.canceled`:

```json theme={"theme":"css-variables"}
{
  "id": "evt_BR4H9ewrJvgc11Jn",
  "object": "event",
  "...": "demais campos do evento",
  "data": {
    "object": {
      "id": "pi_gK376rADQTFKc5xM",
      "object": "payment_intent",
      "...": "demais campos do Payment Intent",
      "cancellation_reason": "requested_by_customer",
      "status": "canceled"
    },
    "previous_attributes": {
      "status": "pending"
    }
  },
  "type": "payment.intent.canceled"
}
```

No receiver:

1. valide a assinatura;
2. deduplique pelo `event.id`;
3. atualize a tentativa por `data.object.id`;
4. preserve `charge`, `latest_charge` e referências do pedido;
5. continue aceitando eventos financeiros de sucesso para meios assíncronos;
6. se o dinheiro entrar depois, abra o fluxo de refund.

Se você usa Checkout Sessions, trate também
`checkout.session.async.payment.succeeded`. Para integrações diretas, mantenha
o tratamento dos eventos `payment.intent.*` e `charge.*`. Numa corrida de
estado, reconcilie a charge paga antes de decidir pelo refund; não confie apenas
no status comercial do pedido.

## Cenários comuns

### O comprador abandonou antes de informar um cartão

O Payment Intent está `requires_payment_method`. Cancele com
`cancellation_reason: "abandoned"`. Nenhum dinheiro foi movimentado e nenhum
refund deve ser criado.

Se essa tentativa nasceu de um checkout, o caminho é outro — veja o cenário
abaixo.

### A tentativa nasceu de uma sessão de checkout

A sessão é a dona do ciclo de vida do Payment Intent dela, então o cancelamento
direto responde `409` com
`code: "payment_intent_owned_by_checkout_session"` e o `message` diz qual sessão
expirar. Use
[`POST /v1/checkout-sessions/{id}/expire`](/api-reference/checkout-sessions/expire):
a sessão vira `expired` e o intent é cancelado com
`cancellation_reason: "expired"`.

Isso não é uma restrição arbitrária. Enquanto a sessão está aberta, o comprador
pode voltar ao link, trocar de meio de pagamento ou pedir um novo código PIX — e
é o intent aberto que sustenta essas três coisas. Fechar o intent por baixo
deixaria a sessão viva apontando para uma tentativa morta.

A exceção é `requires_capture`: existe valor autorizado no cartão do comprador
para liberar, e essa liberação é uma operação do pagamento. Nesse estado o
cancelamento direto funciona normalmente.

### Seu backend criou duas tentativas para o mesmo pedido

Escolha qual Payment Intent continuará válido. Cancele o outro com
`cancellation_reason: "duplicate"`. Antes, confira se nenhum deles já está
`succeeded`; uma tentativa paga precisa de refund, não de cancelamento.

### A análise antifraude interrompeu a compra antes da captura

Se o Payment Intent ainda não está pago, cancele com
`cancellation_reason: "fraudulent"`. Se a cobrança já concluiu, a decisão de
devolver deve seguir o fluxo de refund e a política de risco da organização.

### O cartão foi autorizado para captura manual

O status é `requires_capture` e `amount_capturable` é maior que zero. Cancele o
Payment Intent para desfazer a autorização. Não crie um refund, porque ainda não
existe valor capturado para devolver.

### O pedido foi cancelado enquanto o PIX aguardava pagamento

Envie o cancelamento e pare de apresentar o QR code no seu produto. Mesmo
assim, mantenha a conciliação ativa até a expiração. Se chegar uma confirmação
de pagamento, localize a charge e crie um refund total.

### A resposta da API se perdeu

Repita exatamente o mesmo request com o mesmo `Idempotency-Key`. Se a primeira
chamada terminou com sucesso, a API devolve a resposta original com o header
`Idempotent-Replayed: true`.

Sem a mesma chave, uma segunda chamada pode encontrar o Payment Intent já
`canceled` e retornar conflito, mesmo que a primeira tenha funcionado.

### O cancelamento perdeu a corrida para o pagamento

Se a API retornar `409` porque o Payment Intent já está `succeeded`, não tente
forçar o cancelamento. Crie um refund. Se o sucesso chegar por webhook depois de
uma resposta de cancelamento em estado assíncrono, siga a mesma regra: dinheiro
confirmado exige devolução.

## Erros comuns da API

| Status | Situação                                                                              | Como corrigir                                                                                                                       |
| ------ | ------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| `400`  | `cancellation_reason` não é um valor aceito.                                          | Use `abandoned`, `duplicate`, `fraudulent` ou `requested_by_customer`. Os motivos gerados pela Chargefy não são aceitos na entrada. |
| `404`  | O Payment Intent não existe no escopo autenticado.                                    | Confira ID, ambiente, API key e header `Organization`.                                                                              |
| `409`  | O objeto já está `succeeded` ou `canceled`.                                           | Em `succeeded`, crie refund; em `canceled`, reconcilie a operação anterior.                                                         |
| `409`  | O Payment Intent pertence a uma sessão de checkout e não está em `requires_capture`.  | Expire a sessão indicada no `message` com `POST /v1/checkout-sessions/{id}/expire`.                                                 |
| `409`  | O cartão deveria ter uma autorização, mas não existe charge autorizada para cancelar. | Consulte o Payment Intent e não repita a operação às cegas.                                                                         |
| `422`  | A autorização não pode ser cancelada automaticamente.                                 | Preserve o estado, consulte novamente e acione o suporte.                                                                           |
| `5xx`  | Houve falha transitória ao concluir ou registrar o cancelamento.                      | Consulte o Payment Intent e repita com a mesma chave de idempotência.                                                               |

Exemplo de conflito quando o pagamento já foi concluído:

```json theme={"theme":"css-variables"}
{
  "error": {
    "code": "resource_state_conflict",
    "message": "Payment intent cannot be canceled in its current status.",
    "type": "invalid_request_error"
  }
}
```

## Modele os estados separadamente

Evite um único campo `canceled` para representar tudo. No seu sistema, separe:

| Estado do seu produto   | Significado                                                         |
| ----------------------- | ------------------------------------------------------------------- |
| `cancel_requested`      | O comprador ou operador pediu para interromper a compra.            |
| `payment_canceled`      | O Payment Intent foi cancelado.                                     |
| `late_payment_received` | Uma confirmação financeira chegou depois do cancelamento comercial. |
| `refund_pending`        | A devolução do pagamento tardio foi iniciada.                       |
| `refunded`              | O refund chegou a `succeeded`.                                      |

Essa separação evita dois erros comuns: liberar um pedido só porque houve
redirecionamento de sucesso e afirmar que o dinheiro foi devolvido só porque o
pedido foi cancelado.

## Checklist para produção

* [ ] Consultar o Payment Intent imediatamente antes de cancelar.
* [ ] Usar refund quando o status já for `succeeded`.
* [ ] Enviar `Idempotency-Key` e repetir a mesma chave em retries.
* [ ] Registrar `cancellation_reason` quando conhecido.
* [ ] Processar `payment.intent.canceled` de forma idempotente.
* [ ] Continuar observando sucesso tardio para PIX, boleto e `processing`.
* [ ] Em captura manual, confirmar que `amount_capturable` foi zerado.
* [ ] Preservar IDs financeiros mesmo depois de cancelar o pedido.
* [ ] Ter um fluxo automático ou operacional para refund de pagamento tardio.

## Próximos passos

<CardGroup cols={2}>
  <Card title="Cancelar Payment Intent" icon="ban" href="/api-reference/payment-intents/cancel">
    Contrato completo do `POST /v1/payment-intents/{id}/cancel`.
  </Card>

  <Card title="Devolver um pagamento" icon="rotate-left" href="/payments/refund-payment">
    Crie e acompanhe o refund quando o dinheiro já entrou.
  </Card>

  <Card title="Payment Intents" icon="bullseye" href="/payments/payment-intents">
    Entenda os estados e o ciclo completo de uma cobrança.
  </Card>

  <Card title="Idempotência" icon="fingerprint" href="/api-reference/idempotency">
    Repita mutações com segurança quando uma resposta se perder.
  </Card>
</CardGroup>
