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:

RegraSe 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:

CampoObrigatórioO que é
offer_identifierSim, ou offerCódigo da oferta.
installmentsSimNúmero de parcelas, de 1 a 12. Não pode passar do máximo da oferta.
quantityNãoQuantidade de unidades. Padrão 1. Mais de 1 só se a oferta permitir.
external_referenceNãoCó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:

CampoObrigatórioO que é
customer.nameSimNome do cliente, até 255 caracteres.
customer.emailSimE-mail válido do cliente.
customer.documentSimCPF ou CNPJ do cliente, com ou sem pontuação. Veja o formato em Documento e telefone.
customer.phoneSimTelefone do cliente com DDD, com ou sem pontuação. Veja o formato em Documento e telefone.

Dados do cartão:

CampoObrigatórioO que é
credit_card.holder_nameSimNome impresso no cartão.
credit_card.holder_documentSimCPF ou CNPJ do titular do cartão, com ou sem pontuação. Veja o formato em Documento e telefone.
credit_card.numberSimNúmero do cartão. A API confere se o número é válido antes de enviar.
credit_card.expiration_monthSimMês de validade, número de 1 a 12.
credit_card.expiration_yearSimAno de validade com 4 dígitos, número.
credit_card.cvvSimCó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:

CampoObrigatórioO que é
addressNãoEndereço do cliente. Se enviar, street, number, neighborhood, city, state e postal_code são obrigatórios. complement é opcional.
affiliate_identifierNãoCódigo do afiliado que indicou a venda. Veja Vender com afiliado.
buyer_ipNãoIP do cliente. Se não enviar, a API usa o IP de quem chamou, ou seja, o do seu servidor.
buyer_user_agentNãoNavegador 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.

Eventodata.transaction.statusO que fazer
TRANSACTION_CREATEDPROCESSINGO gateway aceitou o cartão para processar. Registre a venda e espere TRANSACTION_PAID. Não libere ainda.
TRANSACTION_CREATEDFAILEDO gateway recusou o cartão. Não libere. Peça outro cartão ao cliente.
TRANSACTION_PAIDPAIDO 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.

StatusO que significaO que você faz
PROCESSINGO gateway recebeu a cobrança e ainda não confirmou.Espere TRANSACTION_PAID. Não libere.
PAIDO pagamento foi confirmado. paid_at fica preenchido.Libere o que foi vendido.
FAILEDO 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:

PassoSituaçãoRespostaComo resolver
2installments ausente.400 com O campo installments é obrigatórioEnvie o número de parcelas.
2credit_card ausente.400 com O campo credit_card é obrigatórioEnvie os dados do cartão.
2credit_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.
2installments 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 vaziaConfira os campos na tabela do passo 2.
2offer_identifier e offer juntos, ou nenhum dos dois.400 com Envie offer_identifier ou offer, nunca os dois ou Envie offer_identifier ou offerEnvie só um.
2A 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 1Veja Regras conferidas em toda cobrança. Com price abaixo do valor mínimo, o cartão fica desligado mesmo com true.
2quantity 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 unidadesReduza a quantidade.
2O gateway respondeu com erro ao criar a cobrança.O status e a mensagem do gateway, ou 500 internal_errorProcure a venda pela sua referência antes de repetir. Veja Idempotência.
3O cartão foi recusado.201, e depois TRANSACTION_CREATED com FAILEDVeja Cartão recusado.
3O webhook não chegou.—Veja Entregas e retentativas. Enquanto isso, consulte a venda.
4Nenhuma venda com o valor enviado.404 com Venda não encontradaConfira 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:

Tela Detalhes da venda com uma venda no cartão de crédito paga, mostrando o resumo, o cliente e a forma de pagamento

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

Tela Detalhes da venda com uma venda no cartão de crédito com status Falha e o bloco Motivo do erro

Próximos passos