Skip to Content
КонцепцииСессии
View as Markdown

Сессии

CheckoutSession — это то, с чем взаимодействует покупатель: одноразовый объект с ограниченным временем жизни, владеющий URL размещённого checkout. Самая лёгкая из трёх ключевых сущностей. Большая часть вашей логики работает с Заказами и Payment Intent’ами (см. ниже).

Модель данных из трёх сущностей

CheckoutSession ← 1:1 → Order ← 1:N → PaymentIntent (покупатель) (каталог) (каждая попытка оплаты)
СущностьНазначениеВремя жизни
CheckoutSessionОбращённая к покупателю — есть session_key, checkout_url, TTLМинуты (по умолчанию 30)
OrderСостояние вашего каталога — позиции, суммы, возвратыПостоянная запись
PaymentIntentОдна попытка оплаты на одной сети/активеЧасы; рассчитывается или истекает

Вы создаёте сессию и заказ вместе (через POST /b2b/v1/checkout-sessions/quick). Каждый раз, когда покупатель выбирает актив на странице checkout, открывается свежий PaymentIntent для соответствующей сети. Если он переключает активы посреди checkout, предыдущий intent переходит в EXPIRED, и стартует новый.

Идентификатор

Сессия идентифицируется своим session_key:

cst_G-SO92J7HNWkwMHEHjD4oO1Z

URL-безопасный, около 24 символов после префикса. Размещённая страница checkout — это https://checkout.infraio.xyz/<session_key> — рассматривайте session_key как bearer-credential для именно этого checkout.

Жизненный цикл — CheckoutSession

СостояниеЗначит
ACTIVEСессия создана и открыта. URL checkout работает.
COMPLETEDPaymentIntent на этой сессии рассчитан. Order теперь PAID (или PARTIAL_PAID при недоплате).
EXPIREDexpires_at прошло без расчёта. Все открытые Order’ы отменяются.
CANCELEDЯвная отмена — либо покупатель нажал «cancel», либо вы вызвали endpoint отмены.

Три терминальных состояния взаимоисключающие и финальные. Новая CheckoutSession против того же Order может быть создана, если вы хотите повторить (например, после недоплаты).

TTL

  • По умолчанию: 30 минут (настраивается через поле expires_in при создании, в секундах).
  • Границы: Минимум и максимум не ограничены. Выбирайте значение, соответствующее ожидаемому окну принятия решения покупателем: менее 60 секунд рискует выйти за тайминги для легитимных покупателей, а сессия, остающаяся открытой более 7 дней, почти наверняка заброшена.
  • Дефолт per-merchant: Можно задать в панели, но соблюдает его только POST /b2b/v1/checkout-sessions (двухшаговый). POST /b2b/v1/checkout-sessions/quick использует 30 минут, если expires_in опущен, независимо от настройки в панели. Чтобы на /quick использовать другой дефолт, отправляйте expires_in при каждом вызове.
  • Проверка: Сессия, у которой expires_at прошло, трактуется как EXPIRED, даже если её состояние ещё не обновилось, поэтому не полагайтесь на значение состояния в точный момент истечения.

Недоплата

Если покупатель отправляет меньше суммы сессии, PaymentIntent всё равно рассчитывается на частичную сумму, а Order переходит в PARTIAL_PAID. CheckoutSession переходит в COMPLETED (один PaymentIntent рассчитан), поэтому она больше не пригодна к повторному использованию.

Чтобы принять недоплату как полную оплату, заказ можно разрешить в PAID См. Концепции → Заказы (разрешение недоступно через API; чтобы остаться в self-serve, вместо этого собирайте остаток). Чтобы собрать остаток, создайте новую CheckoutSession против того же Order на остаточную сумму.

Переплата

Если покупатель отправляет больше суммы сессии (редко, но случается при ручных переводах), InfraIO Pay обнаруживает переплату в течение 24 часов и уведомляет вас. Автоматически она не возвращается. Выпустите возврат через API возвратов или панель.

Платежи неверным активом

Депозитный адрес генерируется для одной сессии, сети и актива. Если покупатель отправит на него другой актив, платёж не будет сопоставлен, и PaymentIntent останется открытым до истечения сессии. Поддержка может помочь восстановить средства, но это не автоматика. Говорите покупателям отправлять ровно тот актив, который показан на странице checkout.

В TRON, Solana и TON нет депозитного адреса, поэтому это относится только к EVM-сетям: покупатель платит напрямую на ваш кошелёк. См. Сети с оплатой напрямую на кошелёк.

Идемпотентность при создании

POST /b2b/v1/checkout-sessions/quick принимает поле idempotency_key в теле запроса (заметьте: поле тела, а не HTTP-заголовок). Сгенерируйте UUID, если у вас нет естественного ключа.

Ключ дедуплицирует Order, а не CheckoutSession. При повторе с тем же ключом /quick возвращает оригинальный заказ (order_id стабилен), но создаёт свежую CheckoutSession — новый session_key и checkout_url каждый раз. Это намеренно: один Order может стоять за несколькими попытками checkout (см. Заказы), поэтому повторный /quick отдаёт покупателю чистую сессию без дублирования заказа.

Два поведения, о которых нужно знать:

  • Тело не хэшируется и не сравнивается. Повторное использование ключа с другим телом не возвращает 409 — сервер молча возвращает заказ, уже сохранённый под этим ключом, и игнорирует новое тело. Поэтому рассматривайте idempotency_key как одноразовый токен для одного логического заказа; никогда не переиспользуйте его между разными корзинами.
  • Дедуплицируется только Order, не сессия. Если вам нужен тот же URL checkout, сохраните session_key / checkout_url из первого ответа — повторный вызов /quick не вернёт старый. Чтобы перечислить каждую сессию, выпущенную против заказа, используйте GET /b2b/v1/checkout-sessions/by-order/:order_id.

Endpoint’ы API

МетодПутьЗаметки
POST/b2b/v1/checkout-sessions/quickСоздание заказа + сессии одним вызовом
POST/b2b/v1/checkout-sessionsСоздание сессии против существующего заказа
GET/b2b/v1/checkout-sessions/by-order/:order_idСписок всех сессий для заказа (история повторов)

См. Быстрый старт для полного тела запроса создания и подписания.

Что дальше