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

# Sua primeira venda

> Do zero à fatura paga: qual caminho escolher, o que guardar, e o que fazer no clique duplo.

Existem **três** formas de cobrar por um produto, e elas resolvem o mesmo
problema com trabalhos muito diferentes do seu lado. Escolha primeiro, implemente
depois.

## Qual caminho é o seu

|                                   | O que você constrói         | Quando usar                                                                        |
| --------------------------------- | --------------------------- | ---------------------------------------------------------------------------------- |
| **Link de pagamento**             | nada                        | Venda pontual, cobrança por WhatsApp, primeira venda antes de existir app          |
| **`checkout()`**                  | sua página de "obrigado"    | Você tem app e quer o comprador dentro dele, mas não quer montar tela de pagamento |
| **`invoices.createForProduct()`** | a tela de pagamento inteira | Você quer controle total do visual e do fluxo                                      |

Os três terminam na mesma fatura e no mesmo webhook. A diferença é **quanto da
experiência é sua**.

<Info>
  **Na dúvida, comece pelo link.** É o único que não exige nada do seu app. Você troca depois — o produto e o
  catálogo são os mesmos.
</Info>

## O caminho do meio, ponta a ponta

Assumindo que você já tem um produto **publicado** (veja
<a href="/catalogo">catálogo</a>) e uma chave:

```ts theme={null}
// 1. cria cliente + fatura, e devolve a URL hospedada
const { invoice, url } = await infi.checkout({
  slug: "seu-tenant",
  productId,
  customer: {
    externalId: seuUserId,          // o id do SEU usuário
    email: "cliente@empresa.com",
    taxId: "52998224725",           // Pix e boleto exigem CPF/CNPJ
  },
  successUrl: "https://seu-app.com/obrigado",
});

// 2. GUARDE ISSO. É o passo que ninguém documenta e todo mundo esquece.
await db.pedidos.insert({ userId: seuUserId, invoiceId: invoice.id, status: "aberta" });
```

<Warning>
  **Você precisa mapear `invoiceId` → seu usuário.** Nós não sabemos quem é o seu usuário — você passa um `externalId` e nós
  devolvemos um `invoiceId`. Quando o pagamento confirmar, o webhook traz o
  `invoiceId`, **não o seu usuário**. Se você não guardou o par, recebeu dinheiro e
  não sabe de quem.

  É a decisão de arquitetura mais importante desta página e ela cabe em uma linha
  de tabela no seu banco.
</Warning>

## Cobrar, e mostrar o Pix na sua tela

```ts theme={null}
const pay = await infi.pay.charge({ slug, invoiceId: invoice.id, method: "pix" });

pay.pixPayload;   // copia-e-cola EMV — renderize como QR
pay.pixQrImage;   // PNG em base64, já pronto: use se vier
pay.pixExpiresAt; // quando o QR morre
```

<Warning>
  **Hoje só Pix tem artefato pra sua tela.** `boleto` e `card` retornam **apenas** `invoiceUrl` — a página hospedada do
  provedor. Não existe campo de linha digitável nem de código de barras na resposta,
  e `clientSecret`/`publishableKey` (cartão confirmado no navegador) só aparecem
  onde o cartão está habilitado no tenant.

  Como o pagador **não** deve ir pro site do provedor, o caminho hoje para boleto e
  cartão é o <a href="/link-de-pagamento">link de pagamento</a> ou o
  `url` que o `checkout()` devolve — os dois são checkout nosso, com a sua marca de
  merchant. Verifique `cardEnabled` na leitura pública do link antes de oferecer
  cartão.
</Warning>

## Saber que pagou

Não confie no retorno do `charge`: ele volta `pending`. Pagamento é assíncrono.

```ts theme={null}
// produção: webhook assinado
// sandbox: polling, porque registrar webhook responde 503
const pago = await infi.pay.waitForPaid({ slug, invoiceId: invoice.id, timeoutMs: 15000 });
```

Quando confirmar, use o `invoiceId` do evento pra achar o pedido que você guardou
no passo 2. Detalhes em <a href="/webhooks">webhooks</a>.

## O comprador clicou duas vezes em "Comprar"

Todo método que não é `GET` **na API autenticada** exige `Idempotency-Key` (as
rotas públicas de `/pay/*`, que o navegador do comprador chama, não exigem). Isso
não é burocracia: é o
que impede que dois cliques virem duas faturas.

```ts theme={null}
// a MESMA chave para a MESMA intenção de compra
const chave = `pedido-${seuUserId}-${productId}-${new Date().toISOString().slice(0,10)}`;

const { invoiceId } = await infi.checkout({ slug, productId, customer, idempotencyKey: chave });
await infi.pay.charge({ slug, invoiceId, method: "pix", idempotencyKey: `${chave}-pix` });
```

A partir de `@beinfi/sdk@0.10.2` os dois aceitam `idempotencyKey` (e desde a
`0.10.4` o `checkout()` devolve `invoiceId` já tipado como `string`, sem precisar
de `!`). Os métodos de
recurso (`products.create`, `invoices.create`, `coupons.create`, …) já recebiam a
chave como último argumento.

* **Mesma chave, mesmo corpo** → você recebe a resposta original de volta. Uma
  fatura só.
* **Mesma chave, corpo diferente** → `409 idempotency_key_reused`. É proteção:
  quer dizer que você reusou a chave pra outra coisa.
* **Sem chave** → `400 idempotency_key_required`.

O SDK gera uma automaticamente quando você não passa — o que protege contra
*retry de rede*, não contra clique duplo, porque cada chamada nova ganha chave
nova. Para o clique duplo, a chave tem que vir de algo estável na sua intenção,
como no exemplo acima.

<Tip>
  **O mais simples é não deixar clicar duas vezes.** Desabilite o botão no primeiro clique e trate a `Idempotency-Key` como a rede de
  segurança, não como a primeira linha de defesa.
</Tip>

## Antes de vender: o nome que o comprador vê

Seu tenant nasce com um nome de placeholder. Se você não trocar, o checkout e o
link de pagamento dizem literalmente **"New app"** — e ninguém compra de uma loja
chamada New app.

```ts theme={null}
await infi.account.update({ name: "Cafeteria Orvalho" });
// opcional, citado no mandato de pagamento:
await infi.account.update({ termsUrl: "https://cafeteriaorvalho.com/termos" });
```

Vale na hora, sem republicar produto e sem gerar link novo — o mesmo link passa a
mostrar o nome novo. `infi.account.get()` lê de volta. (A partir do
`@beinfi/sdk@0.10.7`; antes disso é `PATCH /account/tenant`.)

## Vendeu. Agora entrega

Se o que você vende é um arquivo ou um acesso, não monte isso à mão: anexe o
entregável ao produto e a Infi manda o link pessoal pro comprador quando o
pagamento confirma — e te devolve o mesmo link pra você mostrar na sua página de
obrigado. Está em
<a href="/entrega-do-produto">entregar o produto</a>.

O lado do comprador — descobrir que pagou, entregar, e os dois polling que ninguém
adivinha — está em <a href="/pagina-de-obrigado">a página de obrigado</a>.
