# Vender com cartão de crédito

URL: https://staging.pagpolar.com/docs/guias/jornadas/vender-com-cartao

> Cobre o cliente no cartão, à vista ou parcelado, e descubra se o pagamento foi aprovado ou recusado.

Use este guia para cobrar **uma vez** no cartão de crédito, à vista ou parcelado. Você envia os dados do cartão, a PagPolar cobra no gateway e avisa o resultado pelo webhook.

Para cobrar por PIX ou boleto, veja [Vender com PIX ou boleto](/docs/guias/jornadas/vender-com-pix-ou-boleto).

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, o cartão é cobrado de verdade.

## Visão geral

O diagrama mostra o caminho de uma venda no cartão. Os números batem com os passos abaixo.

```mermaid
sequenceDiagram
  autonumber
  participant S as Seu servidor
  participant A as API PagPolar
  participant G as Gateway
  participant W as Seu servidor de webhook
  S->>A: POST /payments/credit-card com Idempotency-Key
  alt parcelas acima do máximo da oferta
    A-->>S: 400 invalid_request
  else dados aceitos
    A->>G: cria a cobrança no cartão
    G-->>A: aceita para processar ou recusa
    A-->>S: 201 com transactions
    A-)W: TRANSACTION_CREATED com status PROCESSING ou FAILED
    opt gateway confirma o pagamento
      G-)A: pagamento confirmado
      A-)W: TRANSACTION_PAID
    end
  end
  S->>A: GET /sales/{id}
  A-->>S: 200 com status
```

## Antes de começar

* 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 cartão ligado. Veja [Criar produto e oferta](/docs/guias/jornadas/criar-produto-e-oferta).
* A URL do webhook cadastrada na credencial. Veja [Credenciais da API](/docs/guias/fundamentos/credenciais).
* Um servidor seu para [chamar a API](/docs/guias/fundamentos/ambientes#servidor). Os dados do cartão vão no corpo da requisição: não grave o número do cartão nem o CVV nos seus logs.

1. **Confira as parcelas da oferta**

   Envie o **código da oferta** no campo `offer_identifier`. Na hora da cobrança, a API confere:

       | 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 e não passou da data de expiração.                | `409` com `Oferta inativa` ou `Oferta expirada`                               |
       | O cartão está ligado na oferta (`is_enabled_credit_card`).            | `409` com `Método de pagamento CREDIT_CARD não habilitado para esta oferta`   |
       | `installments` não passa de `max_credit_card_installments` da oferta. | `400` com `Número de parcelas acima do permitido para esta oferta (máximo N)` |

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

2. **Crie a cobrança**

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

   #### cURL

   ```bash
           curl -X POST "https://api.pagpolar.com/v1/payments/credit-card" \
             -H "Authorization: Bearer <SEU_TOKEN_DE_ACESSO>" \
             -H "Idempotency-Key: 9e1b3d5f-7a2c-4e6b-8d0f-1a3c5e7b9d2f" \
             -H "Content-Type: application/json" \
             -d '{
               "offer_identifier": "<CODIGO_DA_OFERTA>",
               "external_reference": "PEDIDO-0004",
               "installments": 3,
               "customer": {
                 "name": "Maria Silva",
                 "email": "cliente@exemplo.com",
                 "document": "<CPF_DO_CLIENTE>",
                 "phone": "<TELEFONE_DO_CLIENTE>"
               },
               "credit_card": {
                 "holder_name": "MARIA SILVA",
                 "holder_document": "<CPF_DO_TITULAR>",
                 "number": "<NUMERO_DO_CARTAO>",
                 "expiration_month": 12,
                 "expiration_year": 2030,
                 "cvv": "<CVV_DO_CARTAO>"
               },
               "buyer_ip": "<IP_DO_CLIENTE>"
             }'
           ```

   #### Node.js

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

           const idempotencyKey = randomUUID();

           const response = await fetch('https://api.pagpolar.com/v1/payments/credit-card', {
             method: 'POST',
             headers: {
               Authorization: `Bearer ${accessToken}`,
               'Idempotency-Key': idempotencyKey,
               'Content-Type': 'application/json',
             },
             body: JSON.stringify({
               offer_identifier: '<CODIGO_DA_OFERTA>',
               external_reference: 'PEDIDO-0004',
               installments: 3,
               customer: {
                 name: 'Maria Silva',
                 email: 'cliente@exemplo.com',
                 document: '<CPF_DO_CLIENTE>',
                 phone: '<TELEFONE_DO_CLIENTE>',
               },
               credit_card: {
                 holder_name: 'MARIA SILVA',
                 holder_document: '<CPF_DO_TITULAR>',
                 number: '<NUMERO_DO_CARTAO>',
                 expiration_month: 12,
                 expiration_year: 2030,
                 cvv: '<CVV_DO_CARTAO>',
               },
               buyer_ip: '<IP_DO_CLIENTE>',
             }),
           });

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

       Campos do corpo:

       | Campo                | Obrigatório     | O que é                                                                                                                                                                                                                      |
       | -------------------- | --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
       | `offer_identifier`   | Sim, ou `offer` | Código da oferta.                                                                                                                                                                                                            |
       | `installments`       | Sim             | Número de parcelas, de `1` a `12`. Não pode passar do máximo 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-0004`. 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). |

       Dados do cartão:

       | Campo                          | Obrigatório | O que é                                                                                                                                                                         |
       | ------------------------------ | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
       | `credit_card.holder_name`      | Sim         | Nome impresso no cartão.                                                                                                                                                        |
       | `credit_card.holder_document`  | Sim         | CPF ou CNPJ do titular do cartão, com ou sem pontuação. Veja o formato em [Documento e telefone](/docs/guias/fundamentos/valores-datas-e-identificadores#documento-e-telefone). |
       | `credit_card.number`           | Sim         | Número do cartão. A API confere se o número é válido antes de enviar.                                                                                                           |
       | `credit_card.expiration_month` | Sim         | Mês de validade, número de `1` a `12`.                                                                                                                                          |
       | `credit_card.expiration_year`  | Sim         | Ano de validade com 4 dígitos, número.                                                                                                                                          |
       | `credit_card.cvv`              | Sim         | Código de segurança, texto com 3 ou 4 caracteres.                                                                                                                               |

       No ambiente de testes, use os cartões de [Comprar no ambiente de testes](/docs/guias/fundamentos/ambientes#dados-de-teste).

       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.                                    |

       Resposta `201` (resumida):

       ```json
       {
         "data": {
           "offer_identifier": "PPP1234567890",
           "transactions": ["c3d4e5f6-a7b8-4c9d-0e1f-2a3b4c5d6e7f"]
         }
       }
       ```

       **Guarde `transactions[0]` junto do seu pedido.** Ele é o `id` da venda.

       Contrato completo: [`POST /payments/credit-card`](/docs/referencia/vendas/create-credit-card-payment).

   > **O 201 não diz se o cartão foi aprovado**
   >
   > A resposta `201` quer dizer que a venda foi registrada. Ela não traz o status. Um cartão recusado também responde `201`. Descubra o resultado pelo webhook (passo 3) ou pela consulta (passo 4).

   > **Para tentar outro cartão, use outra Idempotency-Key**
   >
   > A resposta `201` do cartão recusado fica guardada com a chave. Repetir com a **mesma** chave devolve a mesma resposta e não cobra de novo. Para uma nova tentativa, com o mesmo cartão ou com outro, gere uma chave nova.

3. **Descubra o resultado pelo webhook**

   A PagPolar envia um `POST` para a URL do webhook da sua credencial. 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                                                              | `data.transaction.status` | O que fazer                                                                                                |
       | ------------------------------------------------------------------- | ------------------------- | ---------------------------------------------------------------------------------------------------------- |
       | [`TRANSACTION_CREATED`](/docs/webhooks/eventos/transaction-created) | `PROCESSING`              | O gateway aceitou o cartão para processar. Registre a venda e espere `TRANSACTION_PAID`. Não libere ainda. |
       | [`TRANSACTION_CREATED`](/docs/webhooks/eventos/transaction-created) | `FAILED`                  | O gateway recusou o cartão. Não libere. Peça outro cartão ao cliente.                                      |
       | [`TRANSACTION_PAID`](/docs/webhooks/eventos/transaction-paid)       | `PAID`                    | O pagamento foi confirmado. Libere o que foi vendido.                                                      |

       Decida sempre pelo `status` recebido, que é o [estado da venda no momento do envio](/docs/webhooks/formato-do-evento#estado-no-envio).

       Exemplo de `TRANSACTION_PAID` de uma venda parcelada (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": "c3d4e5f6-a7b8-4c9d-0e1f-2a3b4c5d6e7f",
             "identifier": "PPO9876543211",
             "status": "PAID",
             "payment_method": "CREDIT_CARD",
             "total_amount": "150.0000",
             "net_amount": 150,
             "installment_tax": "0.0000",
             "installments": 3,
             "paid_at": "2026-09-15T14:35:00.000Z"
           },
           "payment_details": {
             "last_credit_card_digits": "4242"
           },
           "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`. Veja todos os campos em [Formato do evento](/docs/webhooks/formato-do-evento).

4. **Consulte a venda**

   Use a consulta quando o webhook não chegou ou quando a venda ficou muito tempo em `PROCESSING`. Envie o `id` que veio em `transactions[0]`:

   #### cURL

   ```bash
           curl "https://api.pagpolar.com/v1/sales/c3d4e5f6-a7b8-4c9d-0e1f-2a3b4c5d6e7f" \
             -H "Authorization: Bearer <SEU_TOKEN_DE_ACESSO>"
           ```

   #### Node.js

   ```js
           const response = await fetch(
             'https://api.pagpolar.com/v1/sales/c3d4e5f6-a7b8-4c9d-0e1f-2a3b4c5d6e7f',
             { headers: { Authorization: `Bearer ${accessToken}` } },
           );

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

       Resposta `200` (resumida):

       ```json
       {
         "data": {
           "id": "c3d4e5f6-a7b8-4c9d-0e1f-2a3b4c5d6e7f",
           "identifier": "PPO9876543211",
           "external_reference": "PEDIDO-0004",
           "status": "PAID",
           "payment_method": "CREDIT_CARD",
           "installments": 3,
           "total_amount": 150,
           "paid_at": "2026-09-15T14:35:00.000Z",
           "payment_details": {
             "last_credit_card_digits": "4242"
           }
         }
       }
       ```

       `total_amount` vem em reais: `150` na API e `"150.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/PPO9876543211`) ou pela sua referência (`GET /sales/PEDIDO-0004`). `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 de uma venda no cartão neste fluxo.

```mermaid
stateDiagram-v2
  [*] --> PROCESSING: gateway aceita o cartão para processar
  [*] --> FAILED: gateway recusa na criação
  PROCESSING --> PAID: gateway confirma o pagamento
  PROCESSING --> FAILED: gateway recusa depois
```

| Status       | O que significa                                        | O que você faz                                                                      |
| ------------ | ------------------------------------------------------ | ----------------------------------------------------------------------------------- |
| `PROCESSING` | O gateway recebeu a cobrança e ainda não confirmou.    | Espere `TRANSACTION_PAID`. Não libere.                                              |
| `PAID`       | O pagamento foi confirmado. `paid_at` fica preenchido. | Libere o que foi vendido.                                                           |
| `FAILED`     | O gateway recusou a cobrança.                          | Não libere. Peça outro cartão e crie uma nova cobrança com outra `Idempotency-Key`. |

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

## Cartão recusado

Não existe evento próprio para recusa. Se o gateway recusa na hora da cobrança, chega `TRANSACTION_CREATED` com `status: FAILED` (passo 3). Se recusa depois da resposta, a venda passa de `PROCESSING` para `FAILED` e **nenhum** evento é enviado: se a venda continuar em `PROCESSING` sem `TRANSACTION_PAID`, consulte `GET /sales/{identifier}` de tempos em tempos (passo 4).

A API não informa o motivo da recusa. Peça ao cliente para conferir os dados ou usar outro cartão.

## 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     | `installments` ausente.                                                                                                                     | `400` com `O campo installments é obrigatório`                                                                                         | Envie o número de parcelas.                                                                                                                                                                                                                                           |
| 2     | `credit_card` ausente.                                                                                                                      | `400` com `O campo credit_card é obrigatório`                                                                                          | Envie os dados do cartão.                                                                                                                                                                                                                                             |
| 2     | `credit_card.holder_document` fora do formato.                                                                                              | `400` com `Documento do titular do cartão inválido: envie o CPF com 11 dígitos ou o CNPJ com 14 dígitos, com ou sem pontuação.`        | Veja [Documento e telefone](/docs/guias/fundamentos/valores-datas-e-identificadores#documento-e-telefone).                                                                                                                                                            |
| 2     | `installments` fora de `1` a `12`, número do cartão inválido ou validade fora do intervalo (mês de `1` a `12`, ano de `2000` a `2100`).     | `400 invalid_request`, em geral com `message` vazia                                                                                    | Confira os campos na tabela do passo 2.                                                                                                                                                                                                                               |
| 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     | A oferta não passa numa das regras conferidas na cobrança: não encontrada, inativa, expirada, cartão desligado ou parcelas acima do máximo. | `404`, `409` ou `400`, conforme a tabela do passo 1                                                                                    | Veja [Regras conferidas em toda cobrança](/docs/guias/conceitos/ofertas-planos-e-ofertas-ocultas#regras-da-cobranca). Com `price` abaixo do [valor mínimo](/docs/guias/jornadas/criar-produto-e-oferta#meios-de-pagamento), o cartão fica desligado mesmo com `true`. |
| 2     | `quantity` acima do permitido pela oferta.                                                                                                  | `400` com `Quantidade acima do limite permitido para esta oferta (máximo N)` ou `Esta oferta não permite compra de múltiplas unidades` | Reduza a quantidade.                                                                                                                                                                                                                                                  |
| 2     | O gateway respondeu com erro ao criar a cobrança.                                                                                           | O status e a mensagem do gateway, ou `500 internal_error`                                                                              | Procure a venda pela sua referência antes de repetir. Veja [Idempotência](/docs/guias/fundamentos/idempotencia#erro-nao-garante).                                                                                                                                     |
| 3     | O cartão foi recusado.                                                                                                                      | `201`, e depois `TRANSACTION_CREATED` com `FAILED`                                                                                     | Veja [Cartão recusado](#cartao-recusado).                                                                                                                                                                                                                             |
| 3     | O webhook não chegou.                                                                                                                       | —                                                                                                                                      | Veja [Entregas e retentativas](/docs/webhooks/entregas-e-retentativas). Enquanto isso, consulte a venda.                                                                                                                                                              |
| 4     | Nenhuma venda com o valor enviado.                                                                                                          | `404` com `Venda não encontrada`                                                                                                       | Confira o `id`, o código ou a `external_reference`.                                                                                                                                                                                                                   |

## Confira no painel

Ao abrir uma venda em **Vendas → Minhas vendas**, a tela **Detalhes da venda** mostra o status, o valor, o cliente e o cartão usado:

Quando o cartão é recusado, a mesma tela mostra o status **Falha** e o bloco **Motivo do erro**:

## Próximos passos

- [Vender com PIX ou boleto](/docs/guias/jornadas/vender-com-pix-ou-boleto) — Cobre por PIX ou boleto e confirme pelo webhook.
- [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.
