# Vender com PIX ou boleto

URL: https://staging.pagpolar.com/docs/guias/jornadas/vender-com-pix-ou-boleto

> Cobre o cliente por PIX ou boleto, mostre o código de pagamento e confirme o pagamento pelo webhook.

Use este guia para cobrar **uma vez** por PIX ou por boleto. O cliente recebe um código, paga no banco dele e a PagPolar avisa você quando o pagamento for confirmado.

Para cobrar no cartão, veja [Vender com cartão de crédito](/docs/guias/jornadas/vender-com-cartao).

Com a chave de Homologação, a cobrança roda no [ambiente de testes](/docs/guias/fundamentos/ambientes#ambiente-de-testes); com a chave de Produção, gera uma cobrança real.

## Visão geral

O diagrama mostra o caminho completo de uma venda por PIX ou boleto. Os números batem com os passos abaixo.

```mermaid
sequenceDiagram
  autonumber
  participant S as Seu servidor
  participant A as API PagPolar
  participant C as Cliente
  participant W as Seu servidor de webhook
  S->>A: POST /payments/pix ou /payments/boleto com Idempotency-Key
  A-->>S: 201 com transactions e o PIX ou o boleto
  A-)W: TRANSACTION_CREATED
  S->>C: mostra o código do PIX ou o link do boleto
  alt cliente paga
    C->>A: paga no banco e o gateway confirma
    A-)W: TRANSACTION_PAID
  else prazo vence sem pagamento
    A-)W: TRANSACTION_EXPIRED
  end
  S->>A: GET /sales/{id}
  A-->>S: 200 com status e paid_at
```

## Antes de começar

* Uma credencial com a chave de API e a URL do webhook cadastrada. Veja [Credenciais da API](/docs/guias/fundamentos/credenciais).
* Um token de acesso. Veja [Autenticação](/docs/guias/fundamentos/autenticacao#obter-o-token); os exemplos em Node.js assumem a variável `accessToken`.
* Uma oferta ativa com PIX ou boleto ligado. Veja [Criar produto e oferta](/docs/guias/jornadas/criar-produto-e-oferta).
* Um servidor seu para [chamar a API](/docs/guias/fundamentos/ambientes#servidor).

1. **Separe o código da oferta**

   A cobrança precisa de uma oferta. Envie o **código da oferta** no campo `offer_identifier`. É o `identifier` que voltou quando você criou a oferta.

       Na hora da cobrança, a API confere a oferta:

       | Regra                                        | Se não for cumprida                                                               |
       | -------------------------------------------- | --------------------------------------------------------------------------------- |
       | A oferta existe na sua conta e não é oculta. | `404` com `Oferta não encontrada`                                                 |
       | A oferta está ativa.                         | `409` com `Oferta inativa`                                                        |
       | A oferta não passou da data de expiração.    | `409` com `Oferta expirada`                                                       |
       | O meio de pagamento está ligado na oferta.   | `409` com `Método de pagamento PIX não habilitado para esta oferta` (ou `BOLETO`) |

       Também dá para informar a oferta na hora, com o campo `offer` no lugar de `offer_identifier`. Nunca envie os dois. Veja [Ofertas, planos e ofertas ocultas](/docs/guias/conceitos/ofertas-planos-e-ofertas-ocultas).

2. **Crie a cobrança**

   Envie uma `Idempotency-Key` única para esta cobrança e **grave no seu pedido antes de enviar**. Veja [Idempotência](/docs/guias/fundamentos/idempotencia).

       O exemplo cria um PIX:

   #### cURL

   ```bash
           curl -X POST "https://api.pagpolar.com/v1/payments/pix" \
             -H "Authorization: Bearer <SEU_TOKEN_DE_ACESSO>" \
             -H "Idempotency-Key: 3c8e1f7a-2b4d-4e6f-9a1c-5d7e9f0a1b2c" \
             -H "Content-Type: application/json" \
             -d '{
               "offer_identifier": "<CODIGO_DA_OFERTA>",
               "external_reference": "PEDIDO-0002",
               "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-0002',
               customer: {
                 name: 'Maria Silva',
                 email: 'cliente@exemplo.com',
                 document: '<CPF_DO_CLIENTE>',
                 phone: '<TELEFONE_DO_CLIENTE>',
               },
             }),
           });

           console.log(response.status, await response.json());
           ```

       Para o **boleto**, o corpo é o mesmo. Só a rota muda: `POST /payments/boleto`.

       Campos do corpo:

       | Campo                | Obrigatório     | O que é                                                                                                                                                                                                                                                       |
       | -------------------- | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
       | `offer_identifier`   | Sim, ou `offer` | Código da oferta.                                                                                                                                                                                                                                             |
       | `quantity`           | Não             | Quantidade de unidades. Padrão `1`. Mais de `1` só se a oferta permitir.                                                                                                                                                                                      |
       | `external_reference` | Não             | Código do **seu** pedido, até 255 caracteres, como `PEDIDO-0002`. Serve para achar a venda depois. Não use o formato do código da venda. Veja [Como a venda é encontrada](/docs/guias/fundamentos/valores-datas-e-identificadores#como-a-venda-e-encontrada). |

       Dados do cliente:

       | Campo               | Obrigatório | O que é                                                                                                                                                                    |
       | ------------------- | ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
       | `customer.name`     | Sim         | Nome do cliente, até 255 caracteres.                                                                                                                                       |
       | `customer.email`    | Sim         | E-mail válido do cliente.                                                                                                                                                  |
       | `customer.document` | Sim         | CPF ou CNPJ do cliente, com ou sem pontuação. Veja o formato em [Documento e telefone](/docs/guias/fundamentos/valores-datas-e-identificadores#documento-e-telefone).      |
       | `customer.phone`    | Sim         | Telefone do cliente com DDD, com ou sem pontuação. Veja o formato em [Documento e telefone](/docs/guias/fundamentos/valores-datas-e-identificadores#documento-e-telefone). |

       Campos opcionais:

       | Campo                  | Obrigatório | O que é                                                                                                                                        |
       | ---------------------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
       | `address`              | Não         | Endereço do cliente. Se enviar, `street`, `number`, `neighborhood`, `city`, `state` e `postal_code` são obrigatórios. `complement` é opcional. |
       | `affiliate_identifier` | Não         | Código do afiliado que indicou a venda. Veja [Vender com afiliado](/docs/guias/jornadas/vender-com-afiliado).                                  |
       | `buyer_ip`             | Não         | IP do cliente. Se não enviar, a API usa o IP de quem chamou, ou seja, o do seu servidor.                                                       |
       | `buyer_user_agent`     | Não         | Navegador do cliente, até 512 caracteres. Se não enviar, a API usa o header `User-Agent` da sua requisição.                                    |

       Não envie `installments`. No PIX e no boleto, o único valor aceito é `1`.

       Resposta `201` do PIX:

       ```json
       {
         "data": {
           "offer_identifier": "PPP1234567890",
           "transactions": ["a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d"],
           "pix": {
             "qr_code": "00020126580014br.gov.bcb.pix0136a1b2c3d4-e5f6-4a7b-8c9d"
           }
         }
       }
       ```

       Resposta `201` do boleto:

       ```json
       {
         "data": {
           "offer_identifier": "PPP1234567890",
           "transactions": ["b2c3d4e5-f6a7-4b8c-9d0e-1f2a3b4c5d6e"],
           "boleto": {
             "barcode": "34191.79001 01043.510047 91020.150008 1 96610000015000",
             "pdf_link": "https://boletos.pagpolar.com/a1b2c3d4.pdf"
           }
         }
       }
       ```

       As duas respostas estão resumidas. Contrato completo: [`POST /payments/pix`](/docs/referencia/vendas/create-pix-payment) e [`POST /payments/boleto`](/docs/referencia/vendas/create-boleto-payment).

       **Guarde `transactions[0]` junto do seu pedido.** Ele é o `id` da venda. Você vai usar esse valor para ligar o webhook ao pedido e para consultar a venda.

3. **Mostre o PIX ou o boleto ao cliente**

   **PIX.** Mostre `pix.qr_code` como código "copia e cola". Se quiser mostrar a imagem do QR Code, gere a imagem a partir desse texto.

       * O PIX é criado com validade de **5 horas**.
       * A data e a hora exatas do vencimento aparecem em `payment_details.qr_code_expires_at` quando você consulta a venda (passo 5).

       **Boleto.** Mostre o link `boleto.pdf_link` para o cliente abrir e pagar.

       * O boleto é criado com vencimento em **5 dias**.
       * `boleto.barcode` traz o código do boleto como o gateway devolveu.

   > **O código do boleto na consulta pode ser outro campo**
   >
   > Na consulta da venda, `payment_details.billet_barcode` vem de outro campo do gateway. O formato pode ser diferente do `boleto.barcode` da resposta de criação. Guarde os dois se for mostrar o código ao cliente mais tarde.

4. **Espere o webhook**

   A PagPolar envia um `POST` para a URL do webhook da sua credencial a cada mudança importante. Autentique a requisição e descarte repetidos: veja [Autenticar requisições](/docs/webhooks/autenticar-requisicoes) e [Processar sem duplicar](/docs/webhooks/processar-sem-duplicar).

       | Evento                                                              | Quando chega                            | O que fazer                                                                                     |
       | ------------------------------------------------------------------- | --------------------------------------- | ----------------------------------------------------------------------------------------------- |
       | [`TRANSACTION_CREATED`](/docs/webhooks/eventos/transaction-created) | Logo depois da resposta `201`.          | Registre a venda. **Não** libere o produto.                                                     |
       | [`TRANSACTION_PAID`](/docs/webhooks/eventos/transaction-paid)       | O gateway confirmou o pagamento.        | Libere o que foi vendido.                                                                       |
       | [`TRANSACTION_EXPIRED`](/docs/webhooks/eventos/transaction-expired) | O PIX ou o boleto venceu sem pagamento. | Não libere. Se o cliente ainda quiser comprar, crie outra cobrança com outra `Idempotency-Key`. |

       Exemplo de `TRANSACTION_PAID` de um PIX (resumido):

       ```json
       {
         "id": "550e8400-e29b-41d4-a716-446655440000",
         "event": "TRANSACTION_PAID",
         "creation_date": "2026-09-15T14:35:10.000Z",
         "version": "1.0.0",
         "data": {
           "transaction": {
             "id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
             "identifier": "PPO9876543210",
             "status": "PAID",
             "payment_method": "PIX",
             "total_amount": "10.0000",
             "net_amount": 10,
             "paid_at": "2026-09-15T14:35:00.000Z"
           },
           "source": {
             "channel": "API",
             "api_credential_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7"
           }
         }
       }
       ```

       Use `data.transaction.id`, o mesmo valor de `transactions[0]`, para achar o seu pedido: o webhook **não** traz a `external_reference`. Decida pelo `data.transaction.status`, que é o [estado da venda no momento do envio](/docs/webhooks/formato-do-evento#estado-no-envio). Veja todos os campos em [Formato do evento](/docs/webhooks/formato-do-evento).

5. **Consulte a venda**

   Use a consulta quando precisar do status atual: o webhook atrasou, o seu servidor ficou fora do ar ou você quer conferir antes de liberar.

       Envie o `id` que veio em `transactions[0]`:

   #### cURL

   ```bash
           curl "https://api.pagpolar.com/v1/sales/a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d" \
             -H "Authorization: Bearer <SEU_TOKEN_DE_ACESSO>"
           ```

   #### Node.js

   ```js
           const response = await fetch(
             'https://api.pagpolar.com/v1/sales/a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d',
             { headers: { Authorization: `Bearer ${accessToken}` } },
           );

           console.log(response.status, await response.json());
           ```

       Resposta `200` (resumida):

       ```json
       {
         "data": {
           "id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
           "identifier": "PPO9876543210",
           "external_reference": "PEDIDO-0002",
           "status": "PAID",
           "payment_method": "PIX",
           "total_amount": 10,
           "paid_at": "2026-09-15T14:35:00.000Z",
           "payment_details": {
             "qr_code": "00020126580014br.gov.bcb.pix0136a1b2c3d4-e5f6-4a7b-8c9d",
             "qr_code_expires_at": "2026-09-15T19:30:00.000Z",
             "billet_barcode": null,
             "billet_link": null,
             "last_credit_card_digits": null
           }
         }
       }
       ```

       `total_amount` vem em reais: `10` na API e `"10.0000"`, como texto, no webhook. Veja [Valores nas respostas](/docs/guias/fundamentos/valores-datas-e-identificadores#valores-nas-respostas).

       Você também pode consultar pelo código da venda (`GET /sales/PPO9876543210`) ou pela sua referência (`GET /sales/PEDIDO-0002`). `GET /payments/{identifier}` faz a mesma consulta. Veja [Como a venda é encontrada](/docs/guias/fundamentos/valores-datas-e-identificadores#como-a-venda-e-encontrada).

       Contrato completo: [`GET /sales/{identifier}`](/docs/referencia/vendas/get-sale).

## Ciclo de vida

O diagrama mostra os status que uma venda por PIX ou boleto percorre neste fluxo.

```mermaid
stateDiagram-v2
  [*] --> PROCESSING: POST cria a cobrança
  PROCESSING --> PAID: gateway confirma o pagamento
  PROCESSING --> EXPIRED: PIX ou boleto venceu
  EXPIRED --> PAID: pagamento confirmado depois do vencimento
```

| Status       | O que significa                                                                                     | O que você faz                                      |
| ------------ | --------------------------------------------------------------------------------------------------- | --------------------------------------------------- |
| `PROCESSING` | O PIX ou o boleto foi gerado e espera o pagamento. É o status que você vê depois da resposta `201`. | Mostre o código ao cliente e espere.                |
| `PAID`       | O pagamento foi confirmado. `paid_at` fica preenchido.                                              | Libere o que foi vendido.                           |
| `EXPIRED`    | O prazo passou sem pagamento.                                                                       | Não libere. Crie outra cobrança se o cliente pedir. |

**O vencimento não é avisado na hora.** A PagPolar confere os vencimentos a cada 3 horas. O PIX vence quando passa do `qr_code_expires_at`. O boleto vence 5 dias depois de criado. Por isso `EXPIRED` e o evento `TRANSACTION_EXPIRED` podem chegar algumas horas depois do prazo.

**`EXPIRED` não é definitivo.** Se o gateway confirmar um pagamento depois do vencimento, a venda passa para `PAID`. Se chegar `TRANSACTION_PAID` depois de `TRANSACTION_EXPIRED`, libere o produto.

Reembolso, cancelamento e chargeback estão em [Ciclo de vida da venda](/docs/guias/conceitos/ciclo-de-vida-da-venda).

## Quando algo dá errado

Além dos [erros comuns a todas as rotas](/docs/guias/fundamentos/erros#erros-comuns), este fluxo pode responder:

| Passo | Situação                                                                                                                  | Resposta                                                                                        | Como resolver                                                                                                                                                                                                                                                                        |
| ----- | ------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| 2     | `offer_identifier` e `offer` juntos, ou nenhum dos dois.                                                                  | `400` com `Envie offer_identifier ou offer, nunca os dois` ou `Envie offer_identifier ou offer` | Envie só um.                                                                                                                                                                                                                                                                         |
| 2     | Campo obrigatório do cliente faltando.                                                                                    | `400` com `O campo customer.email é obrigatório` (muda conforme o campo)                        | Complete o `customer`. A mensagem mostra um campo por vez.                                                                                                                                                                                                                           |
| 2     | A oferta não passa numa das regras conferidas na cobrança: não encontrada, inativa, expirada, ou PIX ou boleto desligado. | `404` ou `409`, conforme a tabela do passo 1                                                    | Veja [Regras conferidas em toda cobrança](/docs/guias/conceitos/ofertas-planos-e-ofertas-ocultas#regras-da-cobranca). Abaixo do [valor mínimo](/docs/guias/jornadas/criar-produto-e-oferta#meios-de-pagamento), o meio fica desligado mesmo com `true`.                              |
| 2     | `quantity` maior que o limite da oferta.                                                                                  | `400` com `Quantidade acima do limite permitido para esta oferta (máximo N)`                    | Reduza a quantidade.                                                                                                                                                                                                                                                                 |
| 2     | `quantity` maior que `1` numa oferta que não aceita.                                                                      | `400` com `Esta oferta não permite compra de múltiplas unidades`                                | Envie `quantity: 1` ou não envie o campo.                                                                                                                                                                                                                                            |
| 2     | `installments` diferente de `1`.                                                                                          | `400` com `Para o campo installments os valores permitidos são [1]`                             | Não envie o campo.                                                                                                                                                                                                                                                                   |
| 2     | O gateway não conseguiu gerar o PIX ou o boleto.                                                                          | `400` com a mensagem do gateway, ou `Erro ao criar pedido no gateway`                           | Veja o aviso abaixo antes de repetir.                                                                                                                                                                                                                                                |
| 4     | O webhook não chegou.                                                                                                     | —                                                                                               | Confira a URL e os eventos da credencial. Veja [Entregas e retentativas](/docs/webhooks/entregas-e-retentativas). Enquanto isso, consulte a venda.                                                                                                                                   |
| 5     | Nenhuma venda com o valor enviado.                                                                                        | `404` com `Venda não encontrada`                                                                | Confira o `id`, o código ou a `external_reference`.                                                                                                                                                                                                                                  |
| 5     | A `external_reference` tem o formato do código da venda e bate com o código de outra venda.                               | `200` com a venda errada                                                                        | Consulte pelo `id`, ou por `GET /sales?external_reference=`, que só procura pela referência. Nas próximas cobranças, não use o formato do código na referência. Veja [Como a venda é encontrada](/docs/guias/fundamentos/valores-datas-e-identificadores#como-a-venda-e-encontrada). |

> **Erro na geração não garante que nada foi criado**
>
> Quando o gateway não gera o PIX ou o boleto, a resposta é um erro, mas a venda pode ficar registrada sem código de pagamento. Nesse caso, `TRANSACTION_CREATED` não é enviado. Mais tarde a venda vence e chega `TRANSACTION_EXPIRED`.
>
>   Antes de repetir, procure pela sua referência: `GET /sales/PEDIDO-0002`. Se a venda existir sem código de pagamento, crie uma nova cobrança com outra `external_reference` e outra `Idempotency-Key`. Veja [Idempotência](/docs/guias/fundamentos/idempotencia).

## Confira no painel

A venda aparece em **Vendas → Minhas vendas**, com código, cliente, produto, valor recebido e status:

Ao abrir a venda, a tela **Detalhes da venda** mostra o status, os valores, o cliente e a forma de pagamento:

## Próximos passos

- [Vender com cartão de crédito](/docs/guias/jornadas/vender-com-cartao) — Cobre no cartão, à vista ou parcelado.
- [Processar eventos sem duplicar](/docs/webhooks/processar-sem-duplicar) — Trate repetições e eventos fora de ordem.
- [Ciclo de vida da venda](/docs/guias/conceitos/ciclo-de-vida-da-venda) — Todos os status da venda, inclusive reembolso e chargeback.
