Перейти к содержимому
Последнее обновление

Changelog

Все значимые изменения API документируются на этой странице.

[1.12.0] — не выпущено

Добавлено

Покупка USDT за рубли

  • Клиенты партнёра покупают USDT по QR СБП, купленное зачисляется на карту или баланс компании. Подключается отдельно. Эндпоинты: GET /sbp/rate, POST /sbp/customers, GET /sbp/customers/{customerId}, POST /sbp/customers/{customerId}/kyc, POST /sbp/quotes, POST /sbp/orders, GET /sbp/orders, GET /sbp/orders/{id}, POST /sbp/orders/{id}/cancel.
  • Права sbp.read и sbp.create.
  • Вебхуки sbp.customer.kyc_updated и sbp.order.status_changed, тип доставки sbp в журнале. См. Покупка USDT за рубли.
  • Наценка партнёра: partnerFeeBps в POST /sbp/quotes. Удерживается из купленного и остаётся на балансе компании, в котировке, заказе и вебхуке — поле partnerFeeUsdt. См. Ваша наценка.
  • Выпуск карты за рубли: цена карты в рублях в настройках компании (sbpCardPriceRub в PATCH /auth/company/profile, sbp.cardPriceRub в профиле), котировка POST /sbp/quotes с purpose: card_issue. После оплаты USDT зачисляются на баланс компании и карта выпускается сама. Новые поля котировки и заказа: purpose, cardIssueUsdt; заказа и вебхука — cardIssueStatus, issuedCardId, cardRequestId. Ошибки SBP_CARD_PRICE_NOT_SET и SBP_CARD_PRICE_TOO_LOW. См. Выпуск карты за рубли.

Изменено

  • Срок на оплату ST00012 и ГИБДД: 4 минуты после accept вместо 60 секунд, столько же исполнитель получает на такой платёж. Раньше ордер успевал стать failed с Order expired, а через несколько секунд переходил в success. От 50 000 ₽ срок любого ордера на 10 секунд больше.
  • merchantName у оплат ST00012: вместо общей подписи ЖКХ теперь приходит получатель из поля Name платёжки. paymentType остаётся st00012.
  • Отказ passport_patronymic_missing в kycReason: отчество не распознано, паспорт в банк не отправлен. Отказ не окончательный, повтор POST /sbp/customers/{customerId}/kyc выдаёт новую ссылку на проверку.
  • Отказ passport_unreadable в kycReason: данные с разворота паспорта не совпали с машиночитаемой строкой внизу страницы, паспорт в банк не отправлен. Отказ не окончательный, повтор выдаёт новую ссылку. Причина passport_missing_fields больше не возникает.

Исправлено

  • Повтор POST /sbp/customers/{customerId}/kyc после исправимого отказа банка (aura_…, kycTerminal: false) отвечал 422 SBP_PROVIDER_REJECTED. Теперь он просит банк перепроверить клиента.

[1.11.0] — 2026-10-14

Добавлено

Cards API

  • Балансы выбранных карт: POST /cards/balances/query. В теле — cardIds и/или externalIds, до 100 ID суммарно. Элементы ответа — в формате GET /cards/balances, в порядке запроса; ID, которых нет среди карт компании, — в notFound. См. Баланс карты.

[1.10.0] — 2026-10-05

Добавлено

Cards API

  • processorParentId в операциях по картам (GET /cards/:id/transactions, GET /cards/transactions) — общий ID авторизации и её проведения или отмены, в вебхуках это upayParentId. По нему финальная строка связывается с авторизацией, сохранённой из вебхука card.transaction.created, даже если card.transaction.settled не дошёл. См. История транзакций.

[Без изменений в API] — 2026-10-03

Только документация — поведение API не менялось. Документация сверена с текущим кодом API; ниже — что в ней было описано неверно или не описано.

Исправлено в документации

Доступ и ошибки

  • IP-вайтлиста нет. Доступ к API не ограничивается по IP-адресам, регистрировать адреса серверов нигде не нужно. Упоминания whitelist и ошибки 403 IP not whitelisted убраны.
  • Ключи выдаются участникам команды, а не компании целиком, и действуют с правами участника. regenerate-key перевыпускает ключ того участника, от чьего имени сделан запрос. POST /auth/company/login возвращает сессионный токен, а не ключ.
  • Ошибки авторизации: отключённая компания — 401 COMPANY_INACTIVE, а не 403. Реальные 403 — PERMISSION_DENIED (нет права) и CARDS_NOT_ENABLED.
  • Формат ошибок на странице Обработка ошибок приведён к фактическому: errorCode, details, path, timestamp, requestId; requestId приходит и в заголовке X-Request-Id. Добавлен полный список кодов.
  • Ограничения частоты запросов нет, 429 API не отдаёт — описание rate limit убрано.

Ордера и споры

  • Срок на оплату — 60 секунд после accept, а не 5 минут. Не завершённый к paymentUntil ордер становится failed с failureReason: Order expired, а не expired_by_system.
  • Сразу после accept ордер в статусе created, а не in_progress; в ответе есть paymentType.
  • Статусы expired_no_taker и expired_by_system ордерам не присваиваются: ордер, который никто не взял, становится failed, а просроченный исполнителем — disputed с автоматически открытым спором. Вебхука нет на created, in_progress и на спор, открытый вами.
  • Повторный accept без Idempotency-Key отвечает 404 QUOTE_NOT_FOUND, а не 400 Quote already accepted.
  • Повторное открытие спора отвечает 400 DISPUTE_NOT_ALLOWED, а не возвращает уже открытый спор.
  • Тексты ошибок котировок исправлены, в таблицы добавлены QR_AMOUNT_MISSING, ST00012_SUM_*, GIBDD_UIN_INVALID, RATE_UNAVAILABLE, WALLET_BACKEND_ERROR.
  • Штраф ГИБДД по УИН может прийти как обычный платёж СБП (paymentType: nspk) — описаны оба варианта.
  • Частичный возврат по ордеру от платёжной стороны (order_partial_refund) не меняет статус и не сопровождается вебхуком — описан отдельно, а не как исход спора.

Депозиты и баланс

  • Комиссии за пополнение баланса компании нет — зачисляется вся сумма.
  • GET /wallets/balance отдаёт frozenBalance и availableBalance; trxBalance всегда 0.
  • Жизненный цикл депозита компании приведён к фактическому: не прошедшая AML-проверка уходит в pending_retry, а после повторов — в failed с вебхуком deposit.failed; deposit.aml_failed по депозитам компании не приходит.
  • Кошельки пользователей: депозиты не зачисляются на баланс компании, а пересылаются на depositForwardAddress; с баланса компании списывается комиссия за обработку. По ним приходят только deposit.completed, deposit.aml_failed и deposit.failed. Описаны вывод с заблокированного кошелька и статусы депозитов пользователей.
  • История баланса: добавлены типы операций выплат, споров и служебные, для каждого типа указано, что лежит в referenceId.
  • Список диспутов отдаёт суммы строками ("52.63000000"), а не числами.

Карты

  • Типы и статусы операций — значения эквайера как есть: typeName Consumption / Refund / Deactivate, statusName Unposted / Posted / Cancelled / Failed, directionName Pay / Collect. Значений purchase, succeeded, debit не бывает.
  • Вебхуки по картам приходят плоским JSON, без вложенного data. Поправлены поля событий; дедуплицировать нужно по X-Lumo-Delivery-Id.
  • card.assigned приходит и на мгновенную выдачу карты, с requestId: null.
  • Quote пополнения — ourFeeBps, commissionUsdt, totalDebitUsdt; списание — targetAmount + commissionUsdt, комиссии эквайера сверху нет. Сумма — от 10 до 1 000 000 USD. Ошибки пополнения приходят с CARD_RECHARGE_INVALID, а причина — в начале message.
  • Статусы пополнения: ответ на POST /cards/recharge обычно уже итоговый — succeeded или in_progress_manual; refunded означает отмену после ручного разбора, а не возврат успешного пополнения. Сбой эквайера не возвращает деньги сразу: пополнение остаётся pending и досверяется автоматически. Деньги сразу возвращаются только при явном отказе эквайера (422).
  • 3DS-код действует 5 минут, а не 2; приходит сразу, а не опросом раз в 15 секунд. Если кода нет, ответ — пустое тело, а не null. maskedCard — последние цифры номера карты.
  • Баланс карты отдаётся из последнего известного значения и может быть старше 60 секунд — свежесть показывает fetchedAt.
  • Тестовый режим: тестовые суммы пополнения 0.01 / 0.02 недостижимы (минимум — 10), история операций пустая.
  • GET /cards/:id/transactions не принимает from / to — фильтр по периоду есть только у общей ленты GET /cards/transactions.
  • Ошибок BRIDGE_UNAVAILABLE и INSUFFICIENT_FUNDS как errorCode нет — описаны фактические коды.

Вебхуки и выплаты

  • Подпись считается от сырого тела запроса — примеры проверки исправлены. Описано, как получить и сменить секрет подписи.
  • Повторы: попытка ждёт ответа 10 секунд, повторы идут на любой не-2xx ответ, включая 4xx.
  • payout.recharged приходит вместо payout.status_changed, а не в дополнение к нему.
  • Выплаты: часы приёма общие для всех компаний; описаны все failReason и исход спора trader_won.

Было в API, но не попадало в changelog

  • 2026-03-08 — ордер, который исполнитель не подтвердил вовремя, переходит в disputed со спором, открытым платёжной стороной; ордер без исполнителя — в failed.
  • 2026-03-09 — вывод с заблокированного кошелька пользователя: POST /user-wallets/{walletId}/withdraw и GET /user-wallets/withdrawals/status/{requestId}.
  • 2026-04-20 — вход в кабинет больше не перевыпускает API-ключ.
  • 2026-04-23 — просмотр своего ключа POST /auth/company/api-key/reveal, секрет вебхуков: POST /auth/company/webhook-secret/reveal и /rotate, поле webhookSecret в профиле.
  • 2026-04-27 — команды и права: у каждого участника свой ключ и набор прав, роли owner / admin / member, приглашения (/members, /members/invites, /auth/invites/{token}), ошибка 403 PERMISSION_DENIED. См. Команда и права.
  • 2026-04-28 — тестовая отправка POST /webhooks/test и журнал доставок GET /webhooks/deliveries.
  • 2026-05-08 — из quote пополнения убраны поля комиссии эквайера, а из истории операций — строки пополнений.
  • 2026-05-25 — комиссия за пополнение баланса компании отменена.
  • 2026-05-27 — единый формат ошибок с errorCode и requestId.
  • 2026-06-01 — targetAmount пополнения проверяется на входе: от 10 до 1 000 000, не больше двух знаков после запятой; отказ эквайера — 422, а не 502.
  • 2026-06-10 — частичный возврат по исполненному ордеру (order_partial_refund).
  • 2026-07-21 — сбой эквайера при пополнении больше не приводит к немедленному возврату: пополнение остаётся pending и досверяется.
  • 2026-07-22 — состояние карты у эквайера (upayState, upayStateName) в GET /cards и GET /cards/{id}; история пополнений одной карты GET /cards/{id}/recharges.
  • 2026-08-14 — штраф ГИБДД по УИН выставляется как обычный платёж СБП (paymentType: nspk), оплата по реквизитам осталась запасным вариантом.

[1.9.0] — 2026-10-02

Добавлено

Cards API

  • Балансы всех карт одним запросом: GET /cards/balances. До 100 карт на страницу, включая закрытые, отсортированы по cardId; следующая страница — after=meta.nextCursor. Ответ — { "data": [...], "meta": { "limit", "nextCursor" } }, у каждой карты cardId, externalId, balance, currency, fetchedAt.

    balance — строка без округления. Если баланс неизвестен, balance, currency и fetchedAt равны null: null означает «неизвестно», а не ноль. fetchedAt — когда баланс получен от эквайера. См. Баланс карт.

[1.8.3] — 2026-09-23

Исправлено

  • Повторное закрытие спора по ордеру, который уже завершился как failed, больше не меняет баланс и заморозку компании.

[1.8.2] — 2026-09-15

Исправлено

  • GET /cards/{id}/otp/latest отдавал в cardId внутренний идентификатор карты у эквайера, и код выглядел как код чужой карты. Теперь там id карты в нашем API — как в пути запроса и в вебхуке card.otp_received.

[1.8.1] — 2026-09-02

Исправлено

  • Пополнение карты списывает с баланса ровно targetAmount + commissionUsdt. Раньше сумма округлялась до центов, и списание могло на доли цента расходиться с возвратом при неуспешном пополнении.

[1.8.0] — 2026-08-28

Добавлено

Cards API

  • MCC мерчанта в операциях: у транзакций появилось поле merchantMcc — код категории торговой точки (5734, 5816, 4121, …), как его прислал эквайер. Приходит и в GET /cards/{id}/transactions, и в общем GET /cards/transactions.

    Поле есть примерно у трети операций — у покупок, где эквайер передал MCC. У пополнений, закрытий карты и части покупок будет null, поэтому рассчитывать на его наличие в каждой строке не стоит.

Исправлено

  • В колонке mcc выгрузки GET /cards/transactions.csv теперь действительно MCC. Раньше туда попадал ditchCode, а это канал эквайринга — у всех операций там одно и то же значение (straitsx), к категории мерчанта отношения не имеющее.

  • Описание ditchCode в документации исправлено: это не MCC. Поле осталось на месте ради обратной совместимости, но за категорией мерчанта теперь нужно идти в merchantMcc.

[1.7.0] — 2026-08-26

Добавлено

Cards API

  • Отмена заявки на карту: POST /cards/requests/{id}/cancel. Пока карта по заявке не выпущена, заявку можно отменить — резерв (cardOpeningFeeUsdt + cardMinInitialDepositUsdt) возвращается в доступный баланс, а externalId заявки снова освобождается.

    Только для статуса pending: выпущенную карту не отменяют, её закрывают через POST /cards/{id}/retire — иначе придёт CARD_REQUEST_NOT_CANCELABLE. Повторный вызов возвращает ту же заявку и ничего не меняет, поэтому запрос безопасно повторять, если ответ не дошёл.

  • Новый webhook card.request_cancelled — заявку отменила наша сторона, резерв вернулся на баланс. На вашу собственную отмену события нет: результат приходит в ответе на сам запрос.

  • Коды ошибок: CARD_REQUEST_NOT_CANCELABLE.

[1.6.0] — 2026-08-26

Добавлено

Payouts API — выплаты рублей с баланса компании

Обратная сторона приёма по QR: вы создаёте заявку с реквизитом получателя, мы списываем USDT с баланса и передаём заявку исполнителю, который отправляет рубли на карту или по номеру телефона через СБП.

  • GET /payouts/config — лимиты, курс, часы приёма, подключены ли выплаты.
  • GET /payouts/banks — справочник банков СБП; id оттуда идёт в bankId.
  • POST /payouts/quote — сколько USDT спишется, без создания заявки.
  • POST /payouts — создать заявку. Передавайте Idempotency-Key: ретрай с тем же ключом вернёт ту же заявку, а не выплатит второй раз.
  • GET /payouts, GET /payouts/{id} — список и статус; ?search= ищет по вашему externalId или по нашему id.
  • POST /payouts/{id}/cancel — отмена, пока заявку не взял исполнитель.
  • POST /payouts/{id}/dispute — спор с вложениями (multipart, до 3 файлов).

Списание происходит при создании заявки, а не при исполнении: иначе заявка могла бы жить у исполнителя без списания. Провал возвращает средства автоматически и ровно один раз — признаком служит поле refundedAt.

Комиссия зашита в курс, отдельной строкой её нет. Курс фиксируется при создании заявки, движение рынка после этого на выплату не влияет.

Ограничения, о которых стоит знать заранее: приём заявок только в рабочие часы (по умолчанию 08:00–22:00 МСК, см. withinWorkingHours), одна выплата на пару «номер телефона + банк» раз в 72 часа и лимит одновременно активных заявок. Подробности — в разделе Выплаты в рублях.

Выплаты подключаются отдельно и по умолчанию выключены.

Webhooks

  • payout.status_changed — на каждую смену статуса выплаты.
  • payout.recharged — заявка вернулась в success после возврата средств, и сумма списана повторно. Отдельное событие потому, что из status этого не видно.

Коды ошибок

Добавлены PAYOUTS_NOT_ENABLED, PAYOUT_NOT_FOUND, PAYOUT_REQUISITE_INVALID, PAYOUT_BANK_REQUIRED, PAYOUT_BANK_UNKNOWN, PAYOUT_ACTIVE_LIMIT, PAYOUT_REQUISITE_COOLDOWN, PAYOUT_OUTSIDE_WORKING_HOURS, PAYOUT_NOT_CANCELABLE, PAYOUT_DISPUTE_NOT_ALLOWED, PAYOUT_SERVICE_REJECTED, PAYOUT_SERVICE_UNAVAILABLE.

Две последних различайте внимательно: PAYOUT_SERVICE_REJECTED — заявки нет и деньги вернулись, PAYOUT_SERVICE_UNAVAILABLE — заявка принята и средства не возвращены, повторять запрос можно только с тем же Idempotency-Key.

[1.5.0] — 2026-08-15

Добавлено

Orders API

  • Поиск ордера по идентификатору: GET /orders?search=.... Находит по вашему externalOrderId — достаточно части, поэтому 387057 найдёт transaction_387057 — либо по нашему id ордера, целиком или по первым символам. Полный UUID ищется точным совпадением.

Disputes API

  • GET /disputes принимает search (по ордеру диспута — те же правила, что в /orders), resolution, limit и offset. Без limit поведение прежнее: вся история одним массивом. При постраничной выдаче общее число приходит в заголовке X-Total-Count.

[Без изменений в API] — 2026-08-15

Только документация — поведение API не менялось.

Исправлено в документации

  • refundAmount у диспутов описывался неверно. Было сказано, что поле заполняется только при partial_refund, а при полном refund равно null. На самом деле при refund в нём лежит полная сумма ордера; null бывает только при confirm. Если вы полагались на прежнее описание при сверке — перепроверьте логику.
  • refundAmount — это не «зачислено на баланс». Поле показывает, какая часть ордера отменена. Если средства ещё не были списаны, решение по диспуту снимает заморозку, и баланс не растёт. Реальное движение — в истории баланса по referenceId = orderId.
  • Исход диспута лежит в resolution, а не в status. Выигранный и проигранный диспут одинаково получают status: resolved; confirm означает отказ по диспуту. Добавлена таблица соответствия резолюции и итогового статуса ордера.
  • Статус ордера после диспута. Было написано, что ордер остаётся disputed — на самом деле он переходит в failed при возврате и в success при отказе.
  • Статусы in_review и rejected описывались как этапы рассмотрения. Они существуют в перечислении, но не выставляются — помечены как зарезервированные.

Добавлено в документацию

  • Страница История баланса и эндпоинты GET /wallets/balance-history и GET /wallets/balance-history.csv в OpenAPI — раньше не были описаны нигде.
  • В схему Dispute добавлен вложенный объект order: он всегда приходил в ответе, но в документации его не было, из-за чего за суммой ордера делали лишний запрос.

[1.4.0] — 2026-08-14

Добавлено

Cards API

  • Сумма в валюте мерчанта: у операций появились originalAmount и originalCurrency. Покупка на 910 ₺ теперь видна как таковая, а не только как списание 19.6248 USD. Поля есть и в выдаче, и в вебхуках операций; null там, где конвертации не было (пополнение, закрытие карты).
  • Операции по всем картам сразу: GET /cards/transactions — одна лента по всем картам компании с фильтрами from/to, вместо запроса на каждую карту.
  • Выгрузка в CSV: GET /cards/transactions.csv и GET /cards/:id/transactions.csv — операции и пополнения одним файлом (колонка type их различает), с фильтром по периоду.

Webhooks

  • card.status_changed — карта заморожена / заблокирована / деактивирована на стороне эквайера. Это не наш status карты: она остаётся assigned, будучи замороженной у эквайера.
  • card.transaction.settled — ранее пришедшая авторизация провелась. Приходит отдельной строкой в среднем через 29 часов, с тем же upayParentId. Связывайте по нему, иначе один платёж посчитается дважды.

Исправлено

  • GET /cards/:id/transactions отдавал в поле cardId внутренний идентификатор карты у эквайера — тот, который на вашей стороне получить неоткуда. Теперь там cardId карты в нашем API, как и в вебхуках.
  • Некорректная дата в query-параметрах возвращает 400, а не 500.

[1.3.0] — 2026-07-05

Добавлено

Cards API

  • Закрытие карты: POST /cards/:id/retire теперь полноценно закрывает карту. Появились статусы closing → closed; остаток на карте за вычетом комиссии cardClosureFeeUsdt возвращается на баланс компании; отправляется новый webhook card.closed. См. Закрытие карты.
  • Новый параметр компании cardClosureFeeUsdt — комиссия за закрытие карты, удерживается из возвращаемого остатка.

[1.2.0] — 2026-05-01

Изменено

Orders API

  • POST /orders/prepare теперь принимает QR-ссылки от шести банков и автоматически нормализует их в формат qr.nspk.ru перед обработкой: Райффайзен, T-Bank/Тинькофф, Газпромбанк, ПСБ, UniCredit, Экспобанк. Прямые ссылки qr.nspk.ru, multiqr.ru и platiqr.ru работают как раньше. Дополнительно есть общий fallback на последний сегмент пути, совпадающий с паттерном qrcId (XX[A-Z0-9]{18,}).

Добавлено

Rates API

  • GET /rates/current — актуальный курс USDT/RUB. В ответе помимо rate/baseRate теперь приходят effectiveRate, offsetBps, minAmountRub, maxAmountRub. rate уже содержит per-company комиссию (см. ниже) — именно по нему создаётся следующий ордер.

Cards API

  • GET /cards/{id}/balance — live-баланс карты, проксируется в мост (~60-секундный кэш на стороне bridge). В cardsTestMode возвращает синтетический ответ.

[1.1.0] — 2026-04-23

Добавлено

Cards API

Полная программа виртуальных VISA-карт с выпуском через API.

  • POST /cards/request — выпуск (синхронный при наличии стока, иначе асинхронный с webhook card.assigned). Обязателен Idempotency-Key.
  • GET /cards и GET /cards/{id} — список и детали карт компании.
  • POST /cards/{id}/retire — закрытие карты.
  • GET /cards/{id}/sensitive — одноразовое раскрытие полного номера и CVC (без кэша, логируется).
  • GET /cards/{id}/otp/latest — последний 3DS OTP из почты эквайера.
  • GET /cards/{id}/transactions — история операций по карте, cursor-пагинация через before.

Card Recharges API

  • POST /cards/recharge/quote — расчёт totalDebitUsdt = userCharge + commission.
  • POST /cards/recharge — выполнение пополнения (обязателен Idempotency-Key). Автоматический возврат средств при ошибке моста или при переходе в failed / refunded.
  • GET /cards/recharges — история пополнений компании.

Webhooks для карт

  • card.assigned, card.otp_received, card.transaction.created, card.recharge.{succeeded,failed,refunded,in_progress_manual}.

Guides

  • Раздел Карты в документации: обзор программы, выпуск, пополнение, PAN+CVC, 3DS OTP, история транзакций, webhooks.

[1.0.0] — 2026-02-01

Добавлено

Orders API

  • POST /orders/prepare — создание котировки из QR-кода СБП
  • POST /orders/accept/{id} — подтверждение и создание ордера
  • GET /orders — список ордеров с фильтрацией
  • GET /orders/{id} — детали ордера
  • Поддержка Idempotency-Key для accept

Disputes API

  • POST /orders/{id}/disputes — открытие диспута
  • GET /disputes — список диспутов компании

Company Wallet API

  • GET /wallets — получение адреса кошелька компании
  • GET /wallets/balance — баланс USDT и TRX
  • GET /wallets/deposits — история депозитов

User Wallets API

  • POST /user-wallets — создание кошелька для пользователя
  • GET /user-wallets — список кошельков
  • GET /user-wallets/blocked — заблокированные кошельки
  • POST /user-wallets/{id}/block — блокировка
  • POST /user-wallets/{id}/replace — замена кошелька
  • GET /user-wallets/deposits — депозиты пользователей

Webhooks

  • События ордеров: order.status_changed
  • События депозитов: deposit.created, deposit.completed, deposit.failed, deposit.aml_*
  • HMAC-SHA256 подпись (X-Lumo-Signature)
  • Автоматические ретраи (до 4 попыток)

Authentication

  • POST /auth/company/login — логин и получение API-ключа
  • GET /auth/company/profile — профиль компании
  • PATCH /auth/company/profile — обновление профиля
  • POST /auth/company/regenerate-key — ротация ключа

Безопасность

  • Аутентификация через X-API-Key
  • AML-проверки входящих депозитов

Планы

В разработке

  • SDK для JavaScript/TypeScript
  • Расширенная аналитика в личном кабинете
  • Поддержка дополнительных сетей (Solana, TON)

Рассматривается

  • GraphQL API
  • Batch-операции