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.