> ## Documentation Index
> Fetch the complete documentation index at: https://docs.beinfi.com/llms.txt
> Use this file to discover all available pages before exploring further.

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

| Fonte                               | Quando                                                                                                                    |
| ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| `productId` do provisionamento      | Vem no JSON de <a href="/inicio-rapido">`POST /public/v1/claimables`</a> — é 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

```ts theme={null}
// 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.

<Warning>
  **Sem versão publicada, 422.** Pular o passo 3 dá isto:

  ```json theme={null}
  {"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/sdk@0.10.0` 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.
</Warning>

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

```ts theme={null}
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):

```ts theme={null}
const { invoice, url } = await infi.checkout({
  productId: product.id,
  customer: { externalId: seuUserId, email: "cliente@empresa.com" },
  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).

<Warning>
  **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/sdk@0.10.1` o `checkout()` repassa:

  ```ts theme={null}
  const { invoice, url } = await infi.checkout({
    slug: "seu-tenant",
    productId: product.id,
    customer: { externalId: seuUserId, email: "cliente@empresa.com", 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_`).
</Warning>

<Info>
  **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.
</Info>

## Próximo passo

<CardGroup cols={2}>
  <Card title="Link de pagamento" href="/link-de-pagamento">
    Com a versão publicada, o link é uma linha.
  </Card>

  <Card title="Entregar o produto" href="/entrega-do-produto">
    Anexe o arquivo ou o link; a entrega sai sozinha quando o pagamento confirma.
  </Card>

  <Card title="Testar no sandbox" href="/testar-no-sandbox">
    Pagar a fatura de teste e ver o status virar `paid`.
  </Card>

  <Card title="Saber que pagou" href="/webhooks">
    Webhook em produção, polling em sandbox.
  </Card>
</CardGroup>
