Sessões
Uma CheckoutSession é com o que o comprador interage — um objeto com TTL, de uso único, que é dono da URL do checkout hospedado. É a mais enxuta das três entidades centrais; o trabalho pesado acontece em Orders e em Payment Intents (veja abaixo).
O modelo de dados de três entidades
CheckoutSession ← 1:1 → Order ← 1:N → PaymentIntent
(comprador) (catálogo) (cada tentativa de pagamento)| Entidade | Propósito | Tempo de vida |
|---|---|---|
| CheckoutSession | Voltado ao comprador — tem session_key, checkout_url, TTL | Minutos (padrão 30) |
| Order | Seu estado de catálogo — itens, totais, reembolsos | Registro permanente |
| PaymentIntent | Uma tentativa de pagamento em uma rede/ativo | Horas; liquida ou expira |
Você cria uma sessão e um pedido juntos (via POST /b2b/v1/checkout-sessions/quick).
Cada vez que o comprador escolhe um ativo na página de checkout, um
PaymentIntent novo é aberto na rede certa. Se ele trocar de ativo no
meio do checkout, o intent anterior vai para EXPIRED e um novo começa.
Identificador
Uma sessão é identificada pelo seu session_key:
cst_G-SO92J7HNWkwMHEHjD4oO1ZURL-safe, com ~24 caracteres depois do prefixo (18 bytes aleatórios
codificados em base64url, sem padding). A página de checkout hospedada
é https://checkout.infraio.xyz/<session_key> — trate o session key
como uma credencial bearer para aquele único checkout.
Ciclo de vida — CheckoutSession
| Estado | Significa |
|---|---|
ACTIVE | Sessão criada e aberta. A URL do checkout está utilizável. |
COMPLETED | Um PaymentIntent dessa sessão foi liquidado. O Order agora está PAID (ou PARTIAL_PAID se foi pagamento insuficiente). |
EXPIRED | expires_at passou sem liquidação. O worker de limpeza mudou o estado e cancelou qualquer Order aberto. |
CANCELED | Cancelamento explícito — o comprador clicou em “cancelar” ou você chamou o endpoint de cancel. |
Os três estados terminais são mutuamente exclusivos e finais. Uma nova CheckoutSession contra o mesmo Order pode ser criada se você quiser tentar de novo (por exemplo, depois de um pagamento insuficiente).
TTL
- Padrão: 30 minutos (configurável pelo campo
expires_inna criação, em segundos). - Limites: Não existe um min/max rígido aplicado pelo servidor. Use valores sensatos — menos de 60 segundos arrisca expirar compradores legítimos; mais de 7 dias segura capacidade em um token que provavelmente foi abandonado. Escolha um número que combine com a janela de decisão esperada do seu comprador.
- Padrão por lojista: Configurável via dashboard, mas só o
endpoint legado
POST /b2b/v1/checkout-sessions(em dois passos) honra. O endpointPOST /b2b/v1/checkout-sessions/quicksempre cai no fallback de 30 minutos seexpires_infor omitido, independentemente da configuração por lojista. Se você precisa de um padrão diferente no quick path, envieexpires_inexplicitamente em toda chamada. - Aplicação: Preguiçoso na leitura + um worker periódico de
limpeza. Uma sessão cujo
expires_atjá passou é tratada comoEXPIREDmesmo que o campo de estado ainda não tenha sido escrito, então não dependa de ler o estado via API no instante exato da expiração.
Pagamento insuficiente
Se o comprador envia menos do que o valor da sessão, o PaymentIntent
ainda liquida pelo valor parcial e o Order transita para
PARTIAL_PAID. A CheckoutSession vai para COMPLETED (um
PaymentIntent liquidou), então deixa de ser reaproveitável.
Para aceitar o déficit como pagamento total, o pedido pode ser
resolvido para PAID — veja Conceitos → Pedidos
(não há API pública de resolve hoje; para um fluxo self-service,
prefira cobrar o restante). Para cobrar o restante, crie uma nova
CheckoutSession contra o mesmo Order com o valor residual.
Pagamento excedente
Se o comprador envia mais do que o valor da sessão (raro, mas acontece com transferências manuais), o scanner on-chain captura o excedente dentro de 24 horas e dispara um alerta para o lojista. Não tem reembolso automático — emita um manualmente pela API de reembolsos ou pelo dashboard.
Pagamentos com ativo errado
O endereço de depósito é gerado por tupla (session, chain, asset).
Se um comprador envia o ativo errado para o endereço, o matcher
on-chain não reconhece e o PaymentIntent fica aberto até a expiração
do TTL. A gente consegue recuperar os fundos, mas é um fluxo de
suporte, não automático — oriente os compradores a enviar exatamente
o ativo mostrado na página de checkout.
Idempotência na criação
POST /b2b/v1/checkout-sessions/quick aceita um campo
idempotency_key no body da requisição (atenção: campo do body, não
header HTTP). Gere um UUID automaticamente se o seu cliente não tiver
uma chave natural — o SDK faz isso por padrão.
A chave deduplica o Order, não a CheckoutSession. Em uma
retentativa com a mesma chave, /quick retorna o pedido original
(order_id é estável), mas cria uma CheckoutSession nova — um
session_key e uma checkout_url novos a cada vez. Isso é
intencional: um Order pode dar suporte a várias tentativas de
checkout (veja Pedidos), então um /quick
em retry entrega ao comprador uma sessão limpa sem duplicar o pedido.
Dois comportamentos diferem de uma camada de idempotência estilo Stripe — não se deixe pegar:
- O body não é hasheado nem comparado. Reusar uma chave com um
body diferente não retorna
409— o servidor silenciosamente retorna o pedido já armazenado sob aquela chave e ignora o body novo. Então trate umaidempotency_keycomo um token de uso único para um único pedido lógico; nunca reaproveite uma entre carrinhos diferentes. - Só o Order é deduplicado, não a sessão. Se você precisa da
mesma URL de checkout de volta, persista
session_key/checkout_urlda primeira resposta — chamar/quickde novo não vai retornar a antiga. Para enumerar cada sessão criada contra um pedido, useGET /b2b/v1/checkout-sessions/by-order/:order_id.
Endpoints da API
| Método | Path | Notas |
|---|---|---|
POST | /b2b/v1/checkout-sessions/quick | Cria order + sessão em uma chamada |
POST | /b2b/v1/checkout-sessions | Cria sessão contra um order existente |
GET | /b2b/v1/checkout-sessions/by-order/:order_id | Lista todas as sessões de um pedido (para histórico de retries) |
GET | /checkout/:session_key | Público — o que o navegador do comprador acessa |
Veja o Início rápido para o body completo de criação e a assinatura.
Próximos passos
- Conceitos → Pedidos — a entidade Order (a que você trata como fonte da verdade para a entrega).
- Conceitos → Redes e ativos — redes suportadas e premissas de finalidade por rede.
- Webhooks → Visão geral — quais eventos disparam em cada transição de estado da sessão.