Criar produto e oferta

Crie um produto, crie a oferta com preço, meios de pagamento e parcelas, e obtenha o código da oferta para vender.

Toda venda pela API aponta para uma oferta. A oferta pertence a um produto. Por isso, antes da primeira cobrança, você cria os dois.

Use este guia quando o preço é fixo e você quer reaproveitar a mesma oferta em muitas vendas. Se o preço é decidido na hora, como num orçamento, você pode informar a oferta direto na cobrança. Veja Ofertas, planos e ofertas ocultas.

Assinatura segue outro caminho

Para cobrança recorrente, crie um plano com POST /plans e a oferta de plano com POST /plans/{id}/offers. Este guia cobre só o produto avulso.

Visão geral

O diagrama mostra as três chamadas deste guia, na ordem. As mensagens 1 e 2 são o passo 1. As mensagens 3 e 4 são o passo 2. As mensagens 5 e 6 são o passo 3.

Antes de começar

  • Uma chave de API. Se ainda não tem, siga o Início rápido.
  • Um token de acesso. Veja Autenticação; os exemplos em Node.js assumem a variável accessToken.
  • Um terminal com curl, ou Node.js 18 ou mais novo. Salve os exemplos em Node.js em um arquivo .mjs e rode com node arquivo.mjs.

Estas chamadas não têm proteção contra repetição

POST /products e POST /offers não usam Idempotency-Key. Cada chamada cria um registro novo. Se você repetir a chamada, fica com dois produtos ou duas ofertas. Guarde o id retornado antes de tentar de novo.

Passo a passo

Crie o produto

Envie o nome do produto. A descrição é opcional.

curl -X POST "https://api.pagpolar.com/v1/products" \
  -H "Authorization: Bearer <SEU_TOKEN_DE_ACESSO>" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Curso de fotografia",
    "description": "Curso online com 20 aulas"
  }'
const response = await fetch('https://api.pagpolar.com/v1/products', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${accessToken}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    name: 'Curso de fotografia',
    description: 'Curso online com 20 aulas',
  }),
});

console.log(response.status, await response.json());
CampoObrigatórioO que é
nameSimNome do produto, até 255 caracteres.
descriptionNãoDescrição, até 5000 caracteres. Aceita texto vazio ou null.

A rota aceita só esses dois campos. Qualquer outro campo responde 400.

Resposta 201 (resumida):

{
  "data": {
    "id": "c4d5e6f7-a8b9-4c0d-8e2f-3a4b5c6d7e8f",
    "name": "Curso de fotografia",
    "description": "Curso online com 20 aulas",
    "type": "DIGITAL",
    "is_active": true,
    "warranty_time": 7
  }
}

O que a API faz por você:

  • O produto nasce digital (type: DIGITAL) e ativo (is_active: true).
  • warranty_time é o prazo de garantia em dias. Vem da configuração da plataforma. Sem configuração, vale 7.

Produto físico é cadastrado no painel

A API cria só produtos DIGITAL. Produto físico é cadastrado no painel, com peso, dimensões e frete — e aí vende pela API normalmente: veja Vender um produto físico. O envio e o código de rastreio continuam só no painel.

Guarde data.id. Ele é o <ID_DO_PRODUTO> do próximo passo. Contrato completo: POST /products.

Crie a oferta

A oferta define o preço, os meios de pagamento e o máximo de parcelas no cartão.

price vai em centavos, como número inteiro (9700 = R$ 97,00), e volta em reais na resposta (97). Veja Valores nas respostas.

curl -X POST "https://api.pagpolar.com/v1/offers" \
  -H "Authorization: Bearer <SEU_TOKEN_DE_ACESSO>" \
  -H "Content-Type: application/json" \
  -d '{
    "product_id": "<ID_DO_PRODUTO>",
    "title": "Oferta principal",
    "price": 9700,
    "is_enabled_pix": true,
    "is_enabled_billet": true,
    "is_enabled_credit_card": true,
    "max_credit_card_installments": 12
  }'
const response = await fetch('https://api.pagpolar.com/v1/offers', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${accessToken}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    product_id: '<ID_DO_PRODUTO>',
    title: 'Oferta principal',
    price: 9700,
    is_enabled_pix: true,
    is_enabled_billet: true,
    is_enabled_credit_card: true,
    max_credit_card_installments: 12,
  }),
});

console.log(response.status, await response.json());
CampoObrigatórioSe você não enviarO que é
product_idSim—id do produto criado no passo 1.
priceSim—Preço em centavos, número inteiro a partir de 0.
titleNãoFica sem títuloNome da oferta, até 255 caracteres.
is_enabled_pixNãotrueAceita PIX. Veja o valor mínimo.
is_enabled_billetNãotrueAceita boleto. Veja o valor mínimo.
is_enabled_credit_cardNãotrueAceita cartão de crédito. Veja o valor mínimo.
max_credit_card_installmentsNão12Máximo de parcelas no cartão. Número inteiro a partir de 1. Veja a parcela mínima.
is_activeNãotrueOferta ativa. Uma oferta inativa não vende.

Meios de pagamento e valor mínimo

Os três meios de pagamento começam ligados. Cada um tem um valor mínimo, conferido ao salvar a oferta:

MeioValor mínimoEm price (centavos)
PIXR$ 5,00500
Cartão de créditoR$ 5,00500
BoletoR$ 10,001000
  • Abaixo do mínimo, a API desliga o meio, mesmo que você envie true.
  • A partir do mínimo, o meio fica ligado, a não ser que você envie false.
  • A resposta mostra o resultado em payment_methods (pix, credit_card e billet). Confira sempre.

Exemplos, com max_credit_card_installments: 1 e sem enviar is_enabled_*:

priceMeios ligados em payment_methods
300 (R$ 3,00)Nenhum meio passa do mínimo. Na oferta avulsa, a criação responde 400 pela parcela mínima. Numa oferta de plano, que não tem parcela mínima, a oferta é criada com os três meios desligados.
700 (R$ 7,00)PIX e cartão. O boleto fica desligado.
1500 (R$ 15,00)PIX, cartão e boleto.

Ao editar a oferta com PATCH /offers/{id}, a regra roda de novo:

Você enviaO que acontece com os meios
priceOs três meios são recalculados com o preço novo. Um meio desligado só por causa do preço volta a ligar se o preço chegar ao mínimo. Para manter um meio desligado, envie false na mesma chamada.
Só is_enabled_*, sem priceSó os campos enviados são recalculados, com o preço atual da oferta.
Nem price nem is_enabled_*Os meios não mudam.

A regra da parcela mínima

A API converte price para reais, dividindo por 100, e divide o resultado por max_credit_card_installments. O que sobra é o valor de cada parcela. Por padrão, cada parcela precisa valer pelo menos R$ 5,00.

Ao contrário do valor mínimo do meio, que só desliga o meio, a parcela mínima recusa a oferta: abaixo dela, a resposta é 400, e a mensagem mostra o valor da parcela e o mínimo em vigor. A regra roda ao criar e ao editar a oferta, mesmo com o cartão desligado.

pricemax_credit_card_installmentsParcelaResultado
970012R$ 8,08Criada
600012R$ 5,00Criada
4990não enviado (vale 12)R$ 4,16400
49909R$ 5,54Criada
100012R$ 0,83400
0qualquerR$ 0,00400

Sem max_credit_card_installments, a conta usa 12 parcelas: todo price abaixo de 6000 recusa a criação. Para uma oferta barata, envie max_credit_card_installments: 1. Mesmo assim, um price abaixo de 500 não passa.

Resposta 201 (resumida):

{
  "data": {
    "id": "d5e6f7a8-b9c0-4d1e-8f3a-4b5c6d7e8f9a",
    "identifier": "PPP1234567890",
    "title": "Oferta principal",
    "price": 97,
    "is_active": true,
    "product_id": "c4d5e6f7-a8b9-4c0d-8e2f-3a4b5c6d7e8f",
    "payment_methods": {
      "pix": true,
      "credit_card": true,
      "billet": true
    },
    "max_credit_card_installments": 12
  }
}
CampoO que fazer com ele
identifierÉ o código da oferta: PPP seguido de 10 dígitos. Guarde. É o <CODIGO_DA_OFERTA> que você envia em offer_identifier nas cobranças.
idId interno da oferta (uuid). Use para editar a oferta com PATCH /offers/{id}.
payment_methodsOs meios de pagamento ligados. billet é o boleto.

Contrato completo: POST /offers.

Consulte a oferta

Antes de vender, confira se a oferta está como você espera. Envie o código da oferta ou o id.

curl "https://api.pagpolar.com/v1/offers/<CODIGO_DA_OFERTA>" \
  -H "Authorization: Bearer <SEU_TOKEN_DE_ACESSO>"
const response = await fetch('https://api.pagpolar.com/v1/offers/<CODIGO_DA_OFERTA>', {
  headers: { Authorization: `Bearer ${accessToken}` },
});

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

O caminho aceita três formatos:

Você enviaComo a API procura
Um uuidPelo id da oferta.
O código, com ou sem o prefixo, como PPP1234567890 ou 1234567890Pelo identifier.
Um link que termina com o códigoUsa só os números do último pedaço do link.

A resposta 200 traz os mesmos campos da criação.

Confira três coisas antes de vender:

CampoO que precisa estar certo
is_activetrue. A consulta também devolve ofertas inativas, mas uma cobrança com oferta inativa responde 409 com Oferta inativa.
payment_methodsO meio que você vai cobrar está true.
max_credit_card_installmentsCobre o número de parcelas que você vai oferecer no cartão.

Contrato completo: GET /offers/{identifier}. Para ver todas as ofertas de um produto, use GET /offers/by-product/{id}.

Confira no painel

O produto e a oferta criados pela API aparecem no painel da sua conta.

Em Meus produtos → Produtos, cada produto aparece com o tipo, o status e a quantidade de ofertas:

Tela Meus produtos, Produtos, com a lista de produtos, o tipo, o status, a categoria e a quantidade de ofertas de cada um

Ao abrir o produto, a aba Ofertas e Configurações lista as ofertas com o código (o mesmo usado em offer_identifier), o preço, os meios de pagamento e as parcelas:

Tela de configuração do produto, aba Ofertas e Configurações, com as ofertas, o código de cada uma, o preço, os meios de pagamento e as parcelas

Eventos de webhook deste fluxo

Nenhum. Criar ou consultar produto e oferta não envia webhook. Os eventos começam quando você cria uma cobrança.

Quando algo dá errado

Além dos erros comuns a todas as rotas, este fluxo pode responder:

PassoSituaçãoRespostaComo resolver
1Faltou name.400 invalid_request com O campo nome é obrigatórioEnvie name.
1name com mais de 255 caracteres.400 invalid_request com O campo nome deve ter no máximo 20 caracteresO limite real é 255. Encurte o nome.
1Campo que a rota não aceita, como type ou price.400 invalid_request com O campo type não e permitidoEnvie só name e description. O preço vai na oferta.
2Faltou product_id ou price.400 invalid_request com O campo product_id é obrigatório ou O campo price é obrigatórioEnvie os dois campos.
2product_id não é um uuid.400 invalid_request com O campo product_id deve ser um UUID válidoUse o data.id do passo 1, não o nome do produto.
2price com texto que não é número.400 invalid_request com O campo price deve ser um númeroEnvie um número em centavos, como 9700.
2price com casas decimais, como 49.9.400 invalid_requestprice é em centavos e só aceita inteiro. Envie 4990.
2price negativo, ou max_credit_card_installments igual a 0 ou com casas decimais.400 invalid_request com message vaziaEnvie price inteiro a partir de 0 e parcelas como número inteiro a partir de 1.
2O produto não existe, foi removido ou é de outra conta.404 not_found com Produto não encontradoConfira o product_id. A chave precisa ser da mesma conta que criou o produto.
2Parcela abaixo do mínimo.400 invalid_request com O valor da parcela (R$ 4.16) fica abaixo do mínimo permitido (R$ 5.00). Reduza o número de parcelas ou aumente o preço da oferta.Diminua max_credit_card_installments ou aumente price. Veja a regra da parcela mínima.
3Código errado, oferta removida, de outra conta ou oferta oculta.404 not_found com Oferta não encontradaUse o identifier do passo 2. Oferta oculta não abre por código.

Próximos passos