# Idempotência

URL: https://staging.pagpolar.com/docs/guias/fundamentos/idempotencia

> Envie o header Idempotency-Key e repita uma cobrança sem cobrar o cliente duas vezes.

## Por que usar

A rede falha. Às vezes você envia uma cobrança e não recebe a resposta. Você não sabe se a cobrança foi criada.

Se você repetir a requisição com a **mesma** `Idempotency-Key`, a API reconhece a repetição e devolve a resposta da primeira vez, sem criar outra cobrança.

## Rotas que exigem `Idempotency-Key`

| Rota                                   | O que faz                        |
| -------------------------------------- | -------------------------------- |
| `POST /payments/pix`                   | Cria uma venda PIX.              |
| `POST /payments/boleto`                | Cria uma venda por boleto.       |
| `POST /payments/credit-card`           | Cria uma venda no cartão.        |
| `POST /plans/offer/{id}/subscribe`     | Cria uma assinatura.             |
| `POST /subscriptions/{id}/plan-change` | Troca o plano de uma assinatura. |
| `POST /refunds`                        | Reembolsa uma venda.             |

Nessas rotas, o header é **obrigatório** e aceita até 255 caracteres. Sem ele, vazio ou maior que isso, a resposta é `400`. As mensagens estão em [Erros comuns a todas as rotas](/docs/guias/fundamentos/erros#erros-comuns).

As outras rotas ignoram o header. `POST /products`, `POST /offers`, `POST /plans` e `POST /plans/{id}/offers` criam um registro novo a cada chamada.

## Como gerar a chave

* Gere **uma chave por operação de negócio**. Exemplo: uma chave para "cobrar o pedido 1234 no PIX".
* Use um UUID. Em Node.js: `crypto.randomUUID()`.
* **Grave a chave no seu banco antes de enviar a requisição.** Assim, depois de uma queda, você repete com a mesma chave.
* Não gere uma chave nova para repetir a mesma cobrança. Chave nova é cobrança nova.

A chave vale por credencial. A mesma chave usada em outra credencial é tratada como outra chave.

Os exemplos abaixo usam um token de acesso. Veja [Autenticação](/docs/guias/fundamentos/autenticacao#obter-o-token).

#### cURL

```bash
    curl -X POST "https://api.pagpolar.com/v1/payments/pix" \
      -H "Authorization: Bearer <SEU_TOKEN_DE_ACESSO>" \
      -H "Idempotency-Key: 2f1c4d2e-8f4a-4c1e-9f7b-6a2d1e3c5b90" \
      -H "Content-Type: application/json" \
      -d '{
        "offer_identifier": "<CODIGO_DA_OFERTA>",
        "external_reference": "PEDIDO-1234",
        "customer": {
          "name": "Maria Silva",
          "email": "cliente@exemplo.com",
          "document": "<CPF_DO_CLIENTE>",
          "phone": "<TELEFONE_DO_CLIENTE>"
        }
      }'
    ```

#### Node.js

```js
    import { randomUUID } from 'node:crypto';

    const idempotencyKey = randomUUID();

    const response = await fetch('https://api.pagpolar.com/v1/payments/pix', {
      method: 'POST',
      headers: {
        Authorization: `Bearer ${accessToken}`,
        'Idempotency-Key': idempotencyKey,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        offer_identifier: '<CODIGO_DA_OFERTA>',
        external_reference: 'PEDIDO-1234',
        customer: {
          name: 'Maria Silva',
          email: 'cliente@exemplo.com',
          document: '<CPF_DO_CLIENTE>',
          phone: '<TELEFONE_DO_CLIENTE>',
        },
      }),
    });

    console.log(
      response.status,
      response.headers.get('Idempotency-Replayed'),
      await response.json(),
    );
    ```

## O que acontece ao repetir

O diagrama mostra o caminho de uma requisição com `Idempotency-Key`.

```mermaid
flowchart TD
  A[Requisição com Idempotency-Key] --> B{Dentro do limite de requisições?}
  B -->|Não| B1[429 e a chave não é registrada]
  B -->|Sim| C{Corpo válido e header presente?}
  C -->|Não| C1[400 e a chave não é registrada]
  C -->|Sim| D{Esta credencial já usou a chave?}
  D -->|Não| E[A API processa a requisição]
  D -->|Sim, ainda em processamento| F[409 conflict]
  D -->|Sim, terminou com 2xx nas últimas 24 horas| G[Mesma resposta de antes com o header Idempotency-Replayed]
  E --> H{A resposta foi 2xx?}
  H -->|Sim| I[Resposta guardada por 24 horas]
  H -->|Não| J[Chave liberada para uma nova tentativa]
```

| Situação da chave                               | O que a API faz                                                                                                                |
| ----------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| Nunca usada                                     | Processa normalmente.                                                                                                          |
| Em processamento                                | Responde `409` com `Uma requisição com este Idempotency-Key já está em processamento`. Espere alguns segundos e repita.        |
| Terminou com sucesso (2xx) há menos de 24 horas | Devolve o mesmo status e o mesmo corpo da primeira resposta, com o header `Idempotency-Replayed: true`. Nada é criado de novo. |
| Terminou com erro (qualquer status fora de 2xx) | A chave é liberada. A próxima requisição com a mesma chave é processada de novo.                                               |
| Usada há mais de 24 horas                       | Vira uma chave nova. A requisição é processada de novo.                                                                        |

A marca de "em processamento" dura até 60 segundos.

> **O corpo não é comparado**
>
> A API olha só a chave. Se você repetir a chave com um corpo diferente dentro de 24 horas, recebe a resposta da **primeira** requisição, e o corpo novo é ignorado. Para uma cobrança diferente, use uma chave diferente.

## Erro não garante que nada foi criado

Numa rota de cobrança, a venda pode ficar registrada mesmo quando a resposta é um erro, como `500`, ou quando a resposta não chega. Como a chave é liberada depois de um erro, repetir com a mesma chave processa a cobrança de novo.

Antes de repetir uma cobrança que falhou, procure a venda pela sua referência:

1. Envie `external_reference` com o código do seu pedido em toda cobrança.
2. Depois de um erro, consulte `GET /sales?external_reference=PEDIDO-1234`.
3. Se a venda já existe, não repita a cobrança.

## Próximos passos

- [Erros](/docs/guias/fundamentos/erros) — Saiba quais erros é seguro repetir.
- [Limites de requisição](/docs/guias/fundamentos/limites-de-requisicao) — Veja o limite por minuto e o 503 das rotas que movimentam dinheiro.
