Vender com cartão de crédito
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.
Com a chave de Homologação, a cobrança roda no 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.
Antes de começar
- Um token de acesso. Veja Autenticação; os exemplos em Node.js assumem a variável
accessToken. - Uma oferta ativa com cartão ligado. Veja Criar produto e oferta.
- A URL do webhook cadastrada na credencial. Veja Credenciais da API.
- Um servidor seu para chamar a API. 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.
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.
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.
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>"
}'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. |
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. |
customer.phone | Sim | Telefone do cliente com DDD, com ou sem pontuação. Veja o formato em 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. |
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.
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. |
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):
{
"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.
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.
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 e Processar sem duplicar.
| Evento | data.transaction.status | O que fazer |
|---|---|---|
TRANSACTION_CREATED | PROCESSING | O gateway aceitou o cartão para processar. Registre a venda e espere TRANSACTION_PAID. Não libere ainda. |
TRANSACTION_CREATED | FAILED | O gateway recusou o cartão. Não libere. Peça outro cartão ao cliente. |
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.
Exemplo de TRANSACTION_PAID de uma venda parcelada (resumido):
{
"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.
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 "https://api.pagpolar.com/v1/sales/c3d4e5f6-a7b8-4c9d-0e1f-2a3b4c5d6e7f" \
-H "Authorization: Bearer <SEU_TOKEN_DE_ACESSO>"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):
{
"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.
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.
Contrato completo: GET /sales/{identifier}.
Ciclo de vida
O diagrama mostra os status de uma venda no cartão neste fluxo.
| 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.
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, 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. |
| 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. Com price abaixo do valor mínimo, 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. |
| 3 | O cartão foi recusado. | 201, e depois TRANSACTION_CREATED com FAILED | Veja Cartão recusado. |
| 3 | O webhook não chegou. | — | Veja 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:
