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.
Com a chave de Homologação, a cobrança roda no 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.
Antes de começar
- Uma credencial com a chave de API e a URL do webhook cadastrada. Veja Credenciais da API.
- Um token de acesso. Veja Autenticação; os exemplos em Node.js assumem a variável
accessToken. - Uma oferta ativa com PIX ou boleto ligado. Veja Criar produto e oferta.
- Um servidor seu para chamar a API.
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.
Crie a cobrança
Envie uma Idempotency-Key única para esta cobrança e grave no seu pedido antes de enviar. Veja Idempotência.
O exemplo cria um PIX:
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>"
}
}'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. |
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. |
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. |
Não envie installments. No PIX e no boleto, o único valor aceito é 1.
Resposta 201 do PIX:
{
"data": {
"offer_identifier": "PPP1234567890",
"transactions": ["a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d"],
"pix": {
"qr_code": "00020126580014br.gov.bcb.pix0136a1b2c3d4-e5f6-4a7b-8c9d"
}
}
}Resposta 201 do boleto:
{
"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 e POST /payments/boleto.
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.
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_atquando 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.barcodetraz 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.
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 e Processar sem duplicar.
| Evento | Quando chega | O que fazer |
|---|---|---|
TRANSACTION_CREATED | Logo depois da resposta 201. | Registre a venda. Não libere o produto. |
TRANSACTION_PAID | O gateway confirmou o pagamento. | Libere o que foi vendido. |
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):
{
"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. Veja todos os campos em Formato do evento.
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 "https://api.pagpolar.com/v1/sales/a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d" \
-H "Authorization: Bearer <SEU_TOKEN_DE_ACESSO>"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):
{
"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.
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.
Contrato completo: GET /sales/{identifier}.
Ciclo de vida
O diagrama mostra os status que uma venda por PIX ou boleto percorre neste fluxo.
| 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.
Quando algo dá errado
Além dos erros comuns a todas as rotas, 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. Abaixo do valor mínimo, 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. 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. |
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.
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:
