Pular para o conteúdo

Começar

Catálogo

Produto → versão publicada → link: a corrente que existe antes de você vender qualquer coisa.

Antes de cobrar por algo, esse algo precisa existir no catálogo e estar publicado. São três chamadas. Sem elas, links.create responde 422.

De onde vem o productId

Toda página de cobrança pede um productId. Ele vem de um destes três lugares:

FonteQuando
productId do provisionamentoVem no JSON de POST /public/v1/claimables — é o produto seed, e ele não está publicado
await infi.products.list()Você já criou o produto antes
await infi.products.create({...})Criando agora — o retorno tem .id

A corrente

// 1. produto
const product = await infi.products.create({
  key: "guia-precificacao",       // chave natural do tenant (upsert idempotente)
  name: "Guia de precificação",
  type: "item",                   // "item" (default) ou "agent"
  pricingModel: "one_time",       // subscription | one_time | usage | prepaid
  currency: "BRL",
  basePrice: "49.90",
});
 
// 2. a v1 já vem criada como draft — pegue ela
const [draft] = await infi.products.versions.list(product.id);
 
// 3. publique (é o passo que ninguém adivinha)
await infi.products.versions.publish(product.id, draft.id);
 
// 4. agora sim
const link = await infi.links.create(product.id, { slug: "seu-tenant" });

products.create já devolve a versão 1 em draft — você não cria versão na mão, só lista e publica.

Sem versão publicada, 422

Pular o passo 3 dá isto:

{"error_code":"validation_failed","message":"One or more fields are invalid.",
 "errors":[{"field":"productId",
   "description":"product has no published version; publish it before creating a payment link"}]}

Desde o @beinfi/[email protected] esse detalhe chega até você: InfiError.errors[] carrega { field, description }. Se estiver num SDK anterior, sobe só a mensagem genérica "One or more fields are invalid" — e falta de publish é a primeira suspeita.

Preço: você provavelmente não precisa de prices.add

Para produto avulso de valor fixo, o basePrice do produto é o preço — a fatura e o link já saem com ele. products.prices.add existe para taxa por meter (por token, por request), não para preço flat.

Meter só entra quando você cobra por uso:

await infi.products.meters.create(product.id, {
  name: "tokens",            // a chave que você manda em track()
  displayName: "Tokens",
  unit: "token",             // token | request | unit
  aggregation: "sum",
  valueProperty: "value",    // obrigatório salvo aggregation: "count"
});

Vender da sua própria página: checkout()

Se você não quer mandar link e sim ter um botão "Comprar" no seu app, é uma chamada. Ela cria a fatura e devolve a URL hospedada onde a pessoa paga (Pix, boleto, cartão):

const { invoice, url } = await infi.checkout({
  productId: product.id,
  customer: { externalId: seuUserId, email: "[email protected]" },
  slug: "seu-tenant",
  successUrl: "https://seu-app.com/obrigado",
});
// redirecione a pessoa para `url`

O valor sai do preço publicado do produto — passe amount só para sobrescrever. A pessoa é inscrita no produto no processo, então você recebe uma fatura ligada ao produto (e não uma cobrança solta).

Pix e boleto exigem CPF/CNPJ do pagador

Sem documento, a cobrança para em 422 customer_tax_id_required. Passe taxId junto do cliente — a partir de @beinfi/[email protected] o checkout() repassa:

const { invoice, url } = await infi.checkout({
  slug: "seu-tenant",
  productId: product.id,
  customer: { externalId: seuUserId, email: "[email protected]", taxId: "52998224725" },
});

Use a url que volta — não monte o endereço à mão. Ela já sai no host certo do seu modo (app-sandbox com sk_test_, app com sk_live_).

Chamando via curl

Todo POST/PUT/DELETE da API autenticada exige header Idempotency-Key — sem ele volta 400 idempotency_key_required. O SDK gera um por chamada; no curl você manda o seu.

Próximo passo