# Трансграничный перевод — проект расширения Статус: **Проектируемая возможность, требуется согласование**. Сверено с `82b3e33`, 18.10.2026. Ничего из нижеописанного не является действующим маршрутом или разрешённым полем Merchant API. В рабочий OpenAPI и примеры эти поля не добавляются. ## Текущее ограничение `orders.Request` и `payouts.Create` содержат одну пару `amount/currency`; магазин и терминал выбираются по направлению и методу/валюте. Валюта `UZS` в валидаторе не доказывает RU → UZ. FX текущей денежной цепочки выражает fiat за USDT и фиксируется для операции. Он не описывает самостоятельную конвертацию RUB → UZS. Канонические банки и gateway mappings уже разделены; их нельзя заменить новым строковым названием коридора. ## Предлагаемая семантика По уточнению пользователя `cross_border` проектируется как самостоятельный метод «Трансграничный перевод» с отдельным числовым `method_id`. Метод не заменяет детализацию доставки: тип реквизита, карта/счёт/телефон, платёжная система и используемый rail задаются отдельно. Для сценария «плательщик из России → получатель в Узбекистане» сначала выбирается продукт: приём в пользу магазина либо выплата клиенту мерчанта. Нельзя молча выполнить обе денежные операции одним прежним запросом. По прямому согласованию пользователя за `cross_border` закреплён **`method_id: 5`**. Остальные предлагаемые имена полей ниже предварительные. Текущий серверный справочник содержит только 1 = SBP, 2 = CARD, 3 = QR, 4 = MOBILE, а валидатор и ограничения БД разрешают диапазон 1–4. Поэтому согласованный ID 5 пока не принимается рабочим API. Миграции и серверная поддержка требуют отдельной реализации и проверки. У выплат сейчас строковый `method`; переход или совместимое расширение для отдельного `method_id` требует явного решения без изменения старых запросов. | Группа | Предлагаемые данные | Правило | |---|---|---| | Метод | `method_id`, код `cross_border` | Отдельный метод; согласованный `method_id: 5`, серверная реализация ожидается | | Направление | `operation_direction` | Приём или выплата задаётся выбранным продуктом; метод не смешивает эти операции | | География | `source_country`, `destination_country`, `corridor_id` | ISO-коды стран, например RU и UZ; коридор задаёт сервер, не выводится из currency | | Доставка | `transfer_rail`, `recipient_type`, `payment_system` | Тип реквизита и система отдельно; карта/телефон/счёт по проверенному адаптеру | | Отправитель | `source_amount`, `source_currency` | Точные decimal-строка и код; RUB отдельно от UZS | | Получатель | `destination_amount`, `destination_currency` | Точные decimal-строка и код; сумма гарантируется только при явном договоре | | Гарантия | `amount_mode`, `guarantee_party`, `conversion_party` | Зафиксирована сумма отправителя либо получателя; гарантирующая сторона и выполняющий конвертацию определены явно | | Котировка | `quote_id`, `quoted_at`, `expires_at`, источник и версия | Снимок неизменен; устаревшая котировка не отправляется, новый выбор требует нового явного согласия | | Курсы | `destination_per_source`, отдельные fiat-per-USDT settlement rates | Первый курс — UZS за 1 RUB; расчётный курс — RUB или UZS за 1 USDT; не взаимозаменяемы | | Комиссии | сумма, валюта, плательщик, включена/сверху, округление | Каждый компонент отдельно, без скрытого включения в курс | | Расчёт | `merchant_settlement_currency`, `executor_settlement_currency` | Договорные валюты расчёта; текущий Ledger USDT сохраняется, новая валюта Ledger требует отдельного проекта | Неплатёжный концептуальный пример: отправитель платит 10 000 RUB, получатель получает 1 500 000 UZS при 150 UZS/RUB. При 100 RUB/USDT исходная стоимость без комиссий — 100 USDT. Курс UZS/USDT для исполнителя должен иметь собственный источник и снимок; нельзя вычислить гарантированную себестоимость только из этих двух чисел без договора. Комиссии и правила округления требуют отдельного согласования. ## Терминалы и каскад Добавить серверные, выключенные по умолчанию capabilities терминала: направление, страны и коридор, отдельный `method_id` трансграничного перевода, rail и тип реквизита, система, обе валюты, допустимый режим гарантии, лимиты каждой суммы, источник котировки, TTL, settlement currency, callback/lookup возможности и версия условий. Наличие секретов или enum не активирует capability. Реальный провайдер допускается только после проверки подписи, сопоставлений банков и неопределённого результата. Каскад фильтрует кандидатов по всей согласованной комбинации до отправки. Неизвестная страна, отсутствующее банковское соответствие или истёкшая котировка означают отказ, без молчаливой подмены метода/валюты. Снимок маршрута сохраняет коридор, quote, обе суммы, комиссии и условия. После возможной отправки повторное направление на другой терминал запрещено до доказанного отсутствия перевода; восстановление выполняет lookup исходной попытки. Каскад приёма не превращается в автоматический payout-каскад без отдельного решения. ## Совместимость и этапы 1. Согласовать денежный продукт, гарантию сумм, ответственность при разнице курса, комиссии, precision/rounding, возвраты, частичное исполнение и позднее подтверждение с координатором денежной цепочки. 2. Добавить согласованный числовой ID `5` метода `cross_border` в серверный справочник и согласовать совместимое представление для payout API со строковым `method`. Расширить валидаторы, ограничения БД, формы настроек и терминалов только после согласования. Существующие ID 1–4 не переименовывать и не переиспользовать. Новые запросы выбранного метода требуют отдельного объекта условий двух валют; старые запросы сохраняют текущую семантику одной amount/currency. Не домысливать географию старых операций и не менять их статусы. 3. Добавить миграции неизменяемых снимков, ограничения, резерв и Ledger; для выплаты резерв учитывать гарантированную стоимость и комиссии. Не пересчитывать принятые операции настройками нового терминала. 4. Реализовать получение/принятие котировки и capabilities лишь после согласования точных маршрутов. В этой версии маршруты не назначаются. 5. Расширить адаптер и его signed callback/lookup: строгая корреляция исходной попытки, двух сумм и валют, банков, quote и provider identity. Не считать сообщение «отправлено» финальной выплатой. 6. Добавить тесты истечения quote и гонок, повторов, timeout до/после отправки, неоднозначного mapping, двух валют/разрядностей, округления частей, частичного успеха, возвратов и однократного Ledger/webhook. Старые контрактные тесты должны оставаться неизменными. 7. Опубликовать отдельную проверенную capability только после приёмки конкретного провайдера и окружения. Затем генерировать OpenAPI, Postman и примеры из принятого контракта. Открытые решения: гарантия source/destination; этап и срок фиксации quote; fee payer; правила отмены/возврата при конвертации; предел допустимого изменения подтверждённой суммы; правила разделения частей; расчётная валюта исполнителя; соответствие канонического банка платёжной системе и стране. Этот проект не утверждает ответы за владельца продукта. ## Основание проверки ID `developer-portal/reference/methods.json` содержит только IDs 1–4. `backend/internal/orders/request.go` отклоняет method_id вне 1–4; `backend/migrations/00003_order_reservations.sql` содержит соответствующие CHECK. `backend/internal/payouts/validation.go` принимает только sbp/card/account. Согласованный ID 5 в проверенной серверной базе пока отсутствует.