Skip to Content
КонцепцииЗаказы

Заказы

Если CheckoutSession — это то, что видит покупатель, то Order — это то, что важно вам. Это постоянная запись о:

  • Что покупалось (позиции)
  • Сколько было к оплате и сколько фактически оплачено
  • Возвраты в работе и применённые возвраты
  • Ваша внешняя ссылка (external_ref) — обычно ваш собственный ID заказа, хранится на Order и возвращается на GET /b2b/v1/orders/{id} (в payload’ах webhook не отзеркаливается — см. ниже)

CheckoutSession умирает после того, как один из её PaymentIntent рассчитан, либо после истечения TTL. Order живёт всегда.

Когда создаётся Order

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

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

СостояниеЗначит
DRAFTЗарезервировано для будущего drafts-потока. Ни один код-путь сегодня не создаёт заказы DRAFT — каждый заказ создаётся сразу PENDING, так что вы не увидите это состояние.
PENDINGCheckoutSession активна и не разрешена.
PAIDПолная сумма рассчитана. Webhook payment.settled срабатывает здесь. Безопасно начинать обработку заказа.
PARTIAL_PAIDДеньги пришли, но меньше общей суммы. См. «Недоплата» ниже.
CANCELEDСессия истекла или мерчант отменил. metadata.canceled_reason объясняет почему (payment_timeout, merchant_canceled, …).
REFUNDEDВся оплаченная сумма возвращена.
PARTIALLY_REFUNDEDЧасть возврата исполнена, остаток остаётся оплаченным.

Состояние, по которому переключается ваша логика обработки заказа, — PAID, а не COMPLETED у CheckoutSession. Webhook payment.settled — канонический сигнал.

Поле external_ref

При создании сессии вы можете включить external_ref (любая строка до 255 символов — обычно ваш собственный ID заказа). Он проходит через весь pipeline:

  • Хранится на Order
  • Виден в панели мерчанта для поиска при поддержке
  • Возвращается на GET /b2b/v1/orders/{id}, чтобы обработчик webhook мог получить его после получения payment.settled

Payload’ы webhook не отзеркаливают external_ref напрямую сегодня — ранние черновики этой документации утверждали, что data.external_ref течёт в каждое событие, и это было неверно. Чтобы сопоставить webhook payment.* с вашей строкой в БД, возьмите order_id из payload’а и запросите заказ. Нативное поле external_ref в payload’ах webhook — в roadmap.

Недоплата

Если on-chain перевод покупателя прошёл на меньшую сумму, чем общая сумма заказа, Order переходит в PARTIAL_PAID. У вас три варианта:

  1. Принять и разрешить. Переводит заказ в PAID и отправляет order.resolved. Это не публичный REST-endpoint — разрешение сегодня внутреннее/операционное действие, поэтому для self-serve потока предпочитайте вариант 2 (собрать остаток).
  2. Ждать остатка. Создайте новую CheckoutSession против того же Order с amount_due = остаток. Покупатель доплачивает разницу; когда она рассчитается, Order перейдёт в PAID.
  3. Отменить и вернуть. Верните частичную сумму и отмените Order. Покупатель отвечает за любые chain-комиссии.

У продукта тут нет рекомендации — разные мерчанты хотят разные политики. Выберите одну и закрепите в своей админке.

Возвраты

Возвраты — это отдельный API-уровень и отдельная страница концепции. См. Концепции → Возвраты.

Endpoint’ы API

МетодПутьЗаметки
POST/b2b/v1/ordersСоздание Order без сессии (редко)
GET/b2b/v1/orders/:order_idЧтение полного заказа с позициями + историей платежей
PATCH/b2b/v1/orders/:order_id/cancelОтмена неоплаченного заказа
PATCH/b2b/v1/orders/:order_id/reopenПереоткрытие авто-отменённого заказа (payment_timeout)

Что дальше