Sesiones
Una CheckoutSession es con lo que interactúa el comprador: un objeto con TTL, de un solo uso, que posee la URL del checkout alojado. Es la más liviana de las tres entidades centrales; el trabajo pesado ocurre en Órdenes y los Payment Intents (ver abajo).
El modelo de datos de tres entidades
CheckoutSession ← 1:1 → Order ← 1:N → PaymentIntent
(comprador) (catálogo) (cada intento de pago)| Entidad | Propósito | Vida útil |
|---|---|---|
| CheckoutSession | De cara al comprador: tiene session_key, checkout_url, TTL | Minutos (por defecto 30) |
| Order | Estado de tu catálogo: line items, totales, reembolsos | Registro permanente |
| PaymentIntent | Un intento de pago en una cadena/activo | Horas; liquida o expira |
Creas una sesión y una orden juntas (vía
POST /b2b/v1/checkout-sessions/quick). Cada vez que el comprador
elige un activo en la página de checkout, se abre un PaymentIntent
fresco contra la cadena correcta. Si cambian de activo a mitad de
checkout, el intent anterior va a EXPIRED y empieza uno nuevo.
Identificador
Una sesión se identifica por su session_key:
cst_G-SO92J7HNWkwMHEHjD4oO1ZURL-safe, ~24 caracteres tras el prefijo (18 bytes aleatorios
codificados en base64url, sin padding). La página de checkout
alojada es https://checkout.infraio.xyz/<session_key>: trata la
session key como una credencial bearer para ese único checkout.
Ciclo de vida — CheckoutSession
| Estado | Significa |
|---|---|
ACTIVE | Sesión creada y abierta. La URL del checkout es usable. |
COMPLETED | Un PaymentIntent de esta sesión liquidó. La Order ahora es PAID (o PARTIAL_PAID si pagaron de menos). |
EXPIRED | expires_at pasó sin liquidación. El cleanup worker cambió el estado y canceló cualquier Order abierta. |
CANCELED | Cancelación explícita: o el comprador pulsó “cancelar” o tú llamaste al endpoint de cancelación. |
Los tres estados terminales son mutuamente excluyentes y finales. Se puede crear una nueva CheckoutSession contra la misma Order si quieres reintentar (p. ej., tras un pago insuficiente).
TTL
- Por defecto: 30 minutos (configurable vía el campo
expires_inal crear, en segundos). - Límites: No hay min/max duro aplicado en el lado del servidor. Usa valores sensatos: menos de 60 segundos arriesga que compradores legítimos se queden sin tiempo; más de 7 días retiene capacidad en un token que casi con certeza está abandonado. Elige un número que coincida con la ventana de decisión esperada de tu comprador.
- Por defecto por comerciante: Configurable vía dashboard, pero
solo la ruta heredada
POST /b2b/v1/checkout-sessions(dos pasos) lo honra. La rutaPOST /b2b/v1/checkout-sessions/quicksiempre cae a 30 minutos si se omiteexpires_in, independientemente del ajuste por comerciante. Si necesitas un valor por defecto distinto en la ruta quick, envíaexpires_inexplícitamente en cada llamada. - Aplicación: Lazy al leer + un cleanup worker periódico. Una
sesión cuyo
expires_atha pasado se trata comoEXPIREDaunque el campo de estado aún no se haya escrito, así que no dependas de leer el estado vía API en el momento exacto de la expiración.
Pago insuficiente
Si un comprador envía menos que el importe de la sesión, el
PaymentIntent aún liquida por el importe parcial y la Order
transiciona a PARTIAL_PAID. La CheckoutSession se mueve a
COMPLETED (un PaymentIntent liquidado), así que ya no es
reutilizable.
Para aceptar el déficit como pago completo, la orden puede
resolverse a PAID: ver Conceptos → Órdenes
(no hay API pública de resolve hoy; para un flujo self-serve, cobra
el remanente en su lugar). Para cobrar el remanente, crea una
nueva CheckoutSession contra la misma Order con el importe
residual.
Sobrepago
Si el comprador envía más que el importe de la sesión (raro pero ocurre con transferencias manuales), el escáner on-chain captura el sobrepago en 24 horas y emite una alerta al comerciante. No hay reembolso automático: emite uno manualmente vía la API de reembolso o el dashboard.
Pagos con activo equivocado
La dirección de depósito se genera por tupla (sesión, cadena, activo). Si un comprador envía el activo equivocado a la dirección,
el matcher on-chain no lo reconoce y el PaymentIntent permanece
abierto hasta la expiración del TTL. Podemos recuperar los fondos
pero es un flujo de soporte, no automático: instruye a los
compradores para que envíen el activo exacto mostrado en la página
de checkout.
Idempotencia al crear
POST /b2b/v1/checkout-sessions/quick acepta un campo
idempotency_key en el body de la petición (nota: campo del body,
no cabecera HTTP). Auto-genera un UUID para él si tu cliente no
tiene una clave natural: el SDK lo hace por defecto.
La clave deduplica la Order, no la CheckoutSession. En un
reintento con la misma clave, /quick devuelve la orden original
(order_id es estable) pero emite una CheckoutSession fresca:
una nueva session_key y checkout_url cada vez. Eso es
intencional: una Order puede respaldar varios intentos de checkout
(ver Órdenes), así que un /quick
reintentado entrega al comprador una sesión limpia sin duplicar la
orden.
Dos comportamientos difieren de una capa de idempotencia al estilo Stripe: no te pillen desprevenido:
- El body no se hashea ni compara. Reutilizar una clave con un
body distinto no devuelve
409: el servidor devuelve silenciosamente la orden ya almacenada bajo esa clave e ignora el nuevo body. Así que trata unidempotency_keycomo un token de un solo uso para una sola orden lógica; nunca lo recicles entre distintos carritos. - Solo la Order se deduplica, no la sesión. Si necesitas la
misma URL de checkout de vuelta, persiste
session_key/checkout_urlde la primera respuesta: llamar a/quickde nuevo no devolverá la antigua. Para enumerar cada sesión emitida contra una orden, usaGET /b2b/v1/checkout-sessions/by-order/:order_id.
Endpoints de la API
| Método | Ruta | Notas |
|---|---|---|
POST | /b2b/v1/checkout-sessions/quick | Crea order + session en una llamada |
POST | /b2b/v1/checkout-sessions | Crea sesión contra una orden existente |
GET | /b2b/v1/checkout-sessions/by-order/:order_id | Lista todas las sesiones de una orden (para historial de reintentos) |
GET | /checkout/:session_key | Público: lo que pega el navegador del comprador |
Consulta el Inicio rápido para el body completo de la petición de creación y la firma.
Qué sigue
- Conceptos → Órdenes: la entidad Order (la que tratas como fuente de verdad para fulfillment).
- Conceptos → Cadenas y activos: redes soportadas y supuestos de finalidad por cadena.
- Webhooks → Resumen: qué eventos se disparan en cada transición de estado de sesión.