Requer
@beinfi/sdk@0.10.4. invoices.deliverable(), o invoiceId que o checkout() devolve e o presign
com tipos estreitados entraram na 0.10.4. Em versão anterior, as rotas HTTP já
existem — chame direto. (A 0.10.3 foi publicada com bundle velho e não tem
nada disso; não use.)Só em produto de compra única
O entregável existe apenas em produtotype: "item" com
pricingModel: "one_time". Qualquer outra combinação:
subscription, não download.
Anexar
Duas formas. Um produto tem um entregável: salvar de novo substitui o anterior.Um link (o caminho mais curto)
Serve pra Notion, Drive, um vídeo no Vimeo, sua própria área de membros:Um arquivo
Três passos, porque os bytes vão direto do seu processo pro storage sem passar pela nossa API:objectKey: "uploaded object was not found; upload before saving". E ele
preenche sizeBytes/contentType sozinho se você omitir: subir um PDF sem
declarar nada devolve contentType: "application/pdf" e o tamanho real.
A uploadUrl vale 15 minutos. Ela é só pra escrever aquele objeto, então dá
pra mandar direto do navegador do seu admin sem passar a sua sk_ pra frente.
Se o ambiente não tiver storage,
presign responde 503. 503 storage_unconfigured quer dizer que aquele ambiente não tem storage de
objeto configurado — não que você errou a chamada. Nesse caso use kind: "link":
o resto do fluxo (grant, e-mail, download) é idêntico nos dois casos.O que acontece quando o pagamento confirma
Nessa ordem, e sem você fazer nada:- A Infi resolve o comprador e o entregável daquela fatura.
- Cria um grant: um token único pra aquele pagamento.
- Manda o e-mail, assunto
Seu acesso / Your download is ready, com o link.
UNIQUE (payment_id, deliverable_id)),
não na sorte.
Produto sem entregável não é erro: a entrega simplesmente não faz nada.
Servir você mesmo (recomendado)
Não dependa da caixa de entrada do comprador. Você tem o link:200 { "grants": [] } — lista
vazia, nunca 404. Isso é de propósito: “ainda não entreguei” é um estado
real que você fica consultando, e um 404 não daria pra distinguir de id
errado. Então é seguro colocar num loop de polling, ao lado do
pay.waitForPaid.
Três motivos pra preferir esse caminho ao e-mail:
- O e-mail pode simplesmente não sair, e o
emailSentAté como você sabe. Ele fica nulo quando o envio não aconteceu — e o caso que mais pega gente testando é endereço que não existe de verdade. Medido:@example.com(domínio reservado, nenhum provedor entrega) →emailSentAtnulo pra sempre; endereço real → preenchido em ~8s. O grant nasce nos dois casos, então a venda está entregável mesmo quando o e-mail não foi. - Comprador sem e-mail nenhum também gera grant. Sem essa chamada, a venda fica entregue pela metade e você não sabe.
- O e-mail pode cair em spam. A sua página de obrigado, não.
O link de download
302:
Token desconhecido responde
404. No SDK, se você já tem o token,
infi.pay.downloadUrl(slug, token) monta essa URL.
A URL assinada de download é curta de propósito (5 min) porque ela é gerada a
cada clique: quem compartilhar o link assinado compartilha algo que expira. O
que não expira é o token — veja abaixo.
Trocar e remover
delete também apaga o arquivo do storage. Grants já emitidos deixam de
resolver — o comprador de ontem perde o acesso, então troque com save em vez
de deletar quando a ideia é publicar uma versão nova.
Fluxo completo
taxId não é opcional pra Pix, e o idempotencyKey evita cobrar duas vezes
no clique duplo — os dois estão explicados em
primeira venda.
E se você estornar?
O grant é uma capacidade sem prazo: quem tem o token baixa. Um estorno total desliga ele — o link passa a responder410 e o grant volta com revokedAt —
e um estorno parcial não. A regra inteira, incluindo como sobrescrever, está em
reembolso.
Isso vale só pro arquivo. Se o seu produto dá acesso a outra coisa (área de
membros, cargo no Discord, chave de API), quem corta é você: assine
payment.refunded e leia accessRevoked.