Referência da API
Criar oferta
Cria uma Offer vinculada a um Product. O tipo (one-time vs recurring) é decidido pelo campo `billingCycle`: ausente ou `null` = pagamento único; preenchido com enum = cobrança recorrente. Valor em **centavos** (100 = R$ 1,00). Veja a seção 'Produtos e Ofertas' para a tabela completa de billing cycles. **PDF de entrega:** este endpoint **não aceita** `deliveryPdfUrl` no corpo. Crie a oferta primeiro e depois envie o PDF em [POST /v2/offers/:id/delivery-pdf](/docs/api/upload-offer-pdf).
/v2/offersdeliveryPdfUrl Enviar `deliveryPdfUrl` aqui retorna 400. O PDF é hospedado no nosso S3 e enviado via multipart em `POST /v2/offers/:id/delivery-pdf`. Quando consultado depois, vem como signed URL temporária (1h).Autenticação
HTTP Basic Auth. Envie sua secret key no header:
Authorization: Basic {base64(secret:SUA_SECRET_KEY)}Parâmetros
productIdstring (UUID)obrigatórioUUID do Product ao qual essa Offer pertence. Precisa pertencer à sua conta.
Exemplo: prd_111aaa-bbb-ccc
namestringobrigatórioNome da oferta, exibido no checkout (ex: 'Plano anual com desconto').
Exemplo: Mensal 12x
descriptionstringopcionalDescrição da oferta.
Exemplo: Acesso por 12 meses
amountnumber (integer, centavos)obrigatórioValor cobrado **por ciclo** em centavos. 100 = R$ 1,00. R$ 49 = 4900. Range: 100 a 5.000.000.
Exemplo: 4900
externalIdstringopcionalSua referência interna. Único por conta.
Exemplo: curso-mkt-mensal
billingCycleenum | nullopcional`null` ou omitido = one-time. Valores recurring: `DAILY`, `WEEKLY`, `MONTHLY`, `QUARTERLY`, `SEMIANNUAL`, `YEARLY`.
Exemplo: MONTHLY
billingCycleCountnumberopcionalQuantas unidades do `billingCycle` entre cobranças. Default 1. Ex: `MONTHLY` + count=3 = cobra a cada 3 meses. Ignorado em one-time.
Exemplo: 1
maxCyclesnumber | nullopcionalTotal máximo de cobranças antes da Subscription expirar. `null` = infinito. Ignorado em one-time. Ex: MONTHLY × max=12 = anual parcelado em 12.
Exemplo: 12
trialDaysnumberopcionalDias grátis antes da primeira cobrança. Default 0. Ignorado em one-time. Range: 0 ao máximo configurado no servidor.
Exemplo: 7
metadataobjectopcionalObjeto JSON arbitrário.
Exemplo: { "tier": "premium" }
Body da requisição
Content-Type: application/json
// Exemplo one-time:
{
"productId": "prd_111aaa-bbb-ccc",
"name": "Pagamento único",
"amount": 49700,
"externalId": "curso-mkt-onetime"
}
// Exemplo recurring com trial:
{
"productId": "prd_111aaa-bbb-ccc",
"name": "Mensal com trial de 7 dias",
"amount": 490,
"billingCycle": "MONTHLY",
"billingCycleCount": 1,
"maxCycles": null,
"trialDays": 7
}
// Exemplo recurring com fim definido:
{
"productId": "prd_111aaa-bbb-ccc",
"name": "Anual em 12x mensais",
"amount": 990,
"billingCycle": "MONTHLY",
"maxCycles": 12,
"trialDays": 0
}Respostas
Oferta criada (sem PDF — deliveryPdfUrl: null). Em one-time, campos como maxCycles/trialDays voltam aos defaults (null/0). Pra anexar PDF, use POST /v2/offers/:id/delivery-pdf em seguida.
{
"id": "off_xyz789",
"createdByUserId": "u-1234",
"productId": "prd_111aaa-bbb-ccc",
"externalId": "curso-mkt-mensal",
"name": "Mensal 12x",
"description": "Acesso por 12 meses",
"amount": 4900,
"billingCycle": "MONTHLY",
"billingCycleCount": 1,
"maxCycles": 12,
"trialDays": 7,
"deliveryPdfUrl": null,
"active": true,
"metadata": null,
"deletedAt": null,
"createdAt": "2026-05-26T14:38:00.000Z",
"updatedAt": "2026-05-26T14:38:00.000Z"
}Validação falhou, externalId já existe ou deliveryPdfUrl enviado (use endpoint separado).
{ "status": 400, "error": "billingCycle invalido" }Product não encontrado.
{ "status": 404, "error": "Produto nao encontrado" }Exemplos
const token = Buffer.from("secret:" + process.env.PAGNOVO_SECRET_KEY).toString("base64");
// Mensal R$ 49 com 7 dias de trial, sem limite de ciclos
const offer = await fetch("https://api.pagnovo.com/v2/offers", {
method: "POST",
headers: { Authorization: `Basic ${token}`, "Content-Type": "application/json" },
body: JSON.stringify({
productId: "prd_111aaa-bbb-ccc",
name: "Plano Mensal",
amount: 4900, // R$ 49 em centavos
billingCycle: "MONTHLY",
billingCycleCount: 1,
trialDays: 7,
}),
}).then(r => r.json());
console.log("offer criada:", offer.id);