Skip to main content
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

Os três terminam na mesma fatura e no mesmo webhook. A diferença é quanto da experiência é sua.
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.

O caminho do meio, ponta a ponta

Assumindo que você já tem um produto publicado (veja catálogo) e uma chave:
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.

Cobrar, e mostrar o Pix na sua tela

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 link de pagamento 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.

Saber que pagou

Não confie no retorno do charge: ele volta pending. Pagamento é assíncrono.
Quando confirmar, use o invoiceId do evento pra achar o pedido que você guardou no passo 2. Detalhes em webhooks.

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

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.
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 entregar o produto. O lado do comprador — descobrir que pagou, entregar, e os dois polling que ninguém adivinha — está em a página de obrigado.