История изменений (Changelog)
2026-09-09
[FIX] V1-адаптер приведён к легаси-спеке (итоги аудита V1-контура)
Compat-адаптер /v1/* сведён с легаси-спекой (swagger_formatted.json):
все расхождения контракта закрыты. Изменения касаются только V1-контура,
V2 API не затронут.
- Крипто-вывод (
POST /v1/merchant/withdraw): обязательное поле спеки —wallet(алиасaddressпринят; при заполнении обоих выигрываетwallet). Адрес валидируется по формату mainnet Base58Check TRON (T+ 33 base58-символа), иначе400 INVALID_ARGUMENT. Ручка идемпотентна поrequestId: повтор с тем жеrequestIdвозвращает существующий вывод без второго резерва баланса. Ответ create/get/list — единый профиль из 19 полей (id,withdrawId,userId,status,requestId,blockchain,currency,amount,wallet,comment,isBalanceCommission,exchangeRate,sentAmount,commissionAmount,transactionHash,callbackUrl,createdAt,lastModifiedAt,sentAt). - Статистика (
POST /v1/payments/incoming/statistics,POST /v1/payments/outgoing/statistics): ответ —{"statistics": [...]}с массивом записей по каждому методу (14 полей для incoming, 12 для outgoing), а не{successCount, totalAmount}. Тело запроса — необязательныеstartDate/endDate(RFC3339). - Диспуты: create/get — полный профиль из 17 полей (
receiptType,receiptUrl,description,clientComment,merchantComment,adminComment,finalizedAt,lastModifiedAtи другие); list — сокращённый из 11. Create читаетpaymentId(обязателен),receiptType,receiptUrl,description,clientComment,merchantCommentи возвращает их эхом. - Банки (
POST /v1/banks/list): элемент списка —BankProfile:id,country,bankName,methodNames,currencies(вместоdisplayName/supportedMethods). - Вебхук PayOut (критично):
PROCESSING→ код40,FAILED/EXPIRED→ код30— ранее оба состояния приходили кодом1(WaitingProcessing), и мерчант не узнавал об ошибке выплаты. Теперь отказ доставляется вебхуком:40обрабатывайте как промежуточный,30— как терминальный отказ. - GET
/v1/payments/incoming/{id}: сделка вREFUND_PENDINGвозвращает статус32(RollingBack); вебхук на той же стадии шлёт16(Returned). Расхождение контуров осознанное и закреплено тестом. Уточнение к записи от 2026-09-08: «32 фактически не выдаётся» устарело — код выдаётся GET-контуром. - Изоляция: GET-ручки (
/payments/incoming|outgoing/{id},/merchant/withdraw/{id},/disputs/{id}) на сущность чужого мерчанта отвечают404 NOT_FOUND— факт существования не раскрывается. - Валюта: неизвестный числовой код в create PayIn/PayOut отвечает
400 INVALID_ARGUMENT(unknown currency code: N); тихая подстановка RUB отключена. - List-фильтры: ручки
withdraw/list,payments/incoming/list,payments/outgoing/list,disputs/listпринимают body-фильтр:status(числовой V1-код),skip,take,startDate,endDate;incoming/listдополнительно —id(UUID).
Инструкция по миграции: интеграциям, написанным по легаси-спеке,
действий не требуется — адаптер вернулся к исходному контракту. Проверьте
парсинг полей статистики/диспутов/банков по спискам выше и заведите ветки
обработки для вебхука PayOut с кодами 40 и 30.
[DOC] Контракты адаптера в Migration guide, вебхук-контур в реестре кодов
- Migration guide дополнен разделом «Контракты
V1-адаптера»: поля withdraw (
wallet+ алиасaddress), идемпотентность поrequestId, полные формы ответов (вывод, статистика, диспуты, банки), list-фильтры, правила изоляции и валюты. - Реестр кодов V1 явно покрывает вебхук-контур: исходящие
40/30в вебхуке PayOut; входящий32(GET) против16(вебхук) на стадии REFUND_PENDING.
2026-09-08
[DOC] Полный реестр числовых кодов V1 (закрывает вопрос интегратора по статусу 50)
Интегратор V1-контура получил от платформы статус 50 (PayingRightNow) по
выплате и не нашёл его в своей копии документации. Проверили: сводного реестра
числовых кодов на сайте не было — коды жили только справочной колонкой в
таблицах V2-статусов, часть значений не показывалась числами вовсе.
- Страница Statuses дополнена секцией «Полный реестр числовых кодов V1»: исходящие (1/40/50 → 10/20/30), входящие (1/31/2/32/21 → 11/12/13/14/15/16, 1000), крипто-выводы (1/2/3/4) — с пометками финальности и перечнем внутренних V2-статусов, которые в каждый код транслируются.
- Колонки «V1 compat» в таблицах PayIn/PayOut заполнены полностью (прочерки
—заменены фактическими кодами: MATCHED/UNASSIGNED →1, EXPIRED-выплата →30, ESCROW_LOCKED →1, PAYMENT_VERIFIED →11, SOFT_DISPUTED →21). - Справка по 50: PayingRightNow — трейдер осуществляет перевод,
промежуточный; исход —
10(успех) или30(отказ);sentAt/sentAmountзаполняются в финальном статусе.
Инструкция по миграции: не требуется. V1-интеграторам — завести у себя весь реестр, чтобы операции не зависали на незнакомых кодах.
[DOC] Уточнения по кодам 20 / 16 / 32 (ответы на вопросы интегратора)
- 20 PaidPartially (исходящие) — легаси-код: текущим движком НЕ выдаётся.
В V2 у выплат нет частичных статусов; финалы — только
10или30. Колонка FAILED в V2-таблице исправлена (было «30/20», стало «30»). - 16 Returned (входящие) — отдаётся вебхук-контуром на стадии REFUND_PENDING (инициация возврата). Не безусловный финал: после возврата сделка может вернуться в рабочий цикл.
- 32 RollingBack — в текущем движке доменный статус не эмитируется, фактически не выдаётся.
- Подтверждение: по исходящим коды
2/13/14/16/21не приходят ни в каком случае (их нет в payout-маппере).
2026-09-08
[FIX] Контракт вебхуков и терминальные исходы — закрытие живого прогона интеграции
Три изменения по итогам полного партнёрского прогона на стейдже:
- Все int64 в телах вебхуков теперь передаются строками — тот же канон,
что и в REST-ответах (proto3 JSON):
"amount": "330000","amount_version": "2". Ранееamountшёл голым JSON-числом — парсер, написанный по образцу REST, мог молча промахиваться. Обратите внимание при десериализации: если ваш приёмник ждал число — обновите тип на строку (или гибкий parse). V1-конверт не затронут (легаси-формат). - Повторный
notify-paymentна сделке вPAYMENT_NOTIFIEDотвечает400 FAILED_PRECONDITION(ранее500): состояние сделки корректно, ретраить не нужно (см. [Retry-матрицу](./errors#retry-матрица-когда- повторять-запрос-безопасно)). - Резолв апелляции
REJECTEDдоводит сделку до терминала: возврат эскроу (order-level и все per-match холды) и переход вCANCELLEDс финальным вебхукомdeal.cancelled(ранее сделка оставалась в промежуточном возврате неограниченно долго).SATISFIED, как и раньше, завершает живую сделку вCOMPLETED.
Инструкция по миграции: для вебхук-приёмников — проверить парсинг сумм (строки); ретраи notify завершать по 4xx; терминальные статусы сделок после резолва обрабатывать как раньше (события аддитивны).
2026-09-04
[FEATURE] Баланс: прозрачность «средств в пути» (pending_credits)
Каждый кошелёк в GET /api/v1/p2p/merchant/balance теперь всегда несёт поле
pending_credits — сумму нетто-зачислений завершённых сделок, ожидающих
фонового распределения комиссий. Раньше между COMPLETED сделки и появлением
нетто в available существовало «окно невидимости»: деньги уже заработаны, но
ни в одной цифре баланса их не было. Канон — Stripe available/pending: обе
цифры отдаются всегда, включая нули. Поле additive; кабинет отображает его
как «В пути». Подробности и жизненный цикл — Балансы → Средства в
пути.
Инструкция по миграции: действий не требуется — новое поле просто появилось в ответе; обрабатывайте по «игнорируй неизвестное», если не нужно.
[FIX] V1-конверт: инфраструктурные сбои больше не маскируются под 401/404/400
Внутренний рефакторинг p2p-engine (доступ к данным за одной дверью) закрыл класс мисклассификации в Legacy V1-конверте: при сбое инфраструктуры (недоступность БД и т.п.) endpoint'ы аутентификации и чтения раньше отвечали клиентским кодом ошибки — как будто мерчант не найден или запрос неверен. Теперь границы строгие:
401 UNAUTHORIZED "merchant not found"— только когда мерчант действительно не существует/не аутентифицирован. Инфра-сбой →500INTERNAL_ERROR(лог + метрика на нашей стороне).404 NOT_FOUND "merchant not found"/"withdrawal not found"— только реальное отсутствие ресурса. Инфра-сбой →500 INTERNAL_ERROR.400 INVALID_ARGUMENT(отсутствующий метод оплаты / незарегистрированный slug) — только ошибки запроса. Инфра-сбой →500 INTERNAL_ERROR.
Инструкция по миграции: соответствует уже задокументированной
Retry-матрице:
4xx — не ретраить, 500 INTERNAL_ERROR — ретраить с backoff. Если ваша
V1-интеграция трактует 401/404 как терминальные — поведение корректно и
раньше; изменилось только то, что транзитные сбои теперь видны как 500
и подлежат ретраю, а не выглядят как «мерчант исчез». Форматы тел ошибок и
все остальные коды не менялись. V2 API не затронут. Вебхуки (типы событий,
payload'ы, доставка) не менялись.
2026-09-03
[FEATURE] Изменение суммы сделки (amend) + зачёт просроченного платежа (settle-as-received)
Закрыт фундаментальный раскол кошельков: изменение суммы в кабинете
(POST /deals/{id}/amount) раньше меняло только цифры в БД — эскроу-холды
оставались на старую сумму, комплит подтверждал чужой остаток, книги
расходились. Теперь:
- Amend (живая сделка): разрешён ТОЛЬКО до
PAYMENT_VERIFIED(статусыINITIALIZED/ESCROW_LOCKED/PAYMENT_NOTIFIED/SOFT_DISPUTED— канон Stripe: amount меняем до авторизации). Атомарно в одной транзакции: новые цифры (USDT — по курсу самой сделки), пересоздание ВСЕХ холдов (order-level + per-match, ключи от(deal_id, amount_version)), append-only аудит-строкаp2p_deal_amount_changes(причина, оператор, ключ), событиеp2p.deal.amount_changedв outbox. - Оптимистичная блокировка: поле сделки
amount_version(стартует с 1); запрос amend принимаетexpected_amount_version(Stripe If-Match): два оператора, редактирующие одновременно — второй получает409и перечитывает. Идемпотентность оператора:idempotency_key(UNIQUE в аудите) — повтор = replay, другое тело =409. - Новое событие вебхука
deal.amount_changed(V2-only!):old_amount, новаяamount,amount_version. Legacy V1-конверт не имеетcallbackTypeпод него — V1-мерчантам событие не доставляется (контрактно; как и события каталога). Прочие события не менялись. - Settle-as-received (EXPIRED + received_amount>0): истёкшая сделка
никогда не оживает; по резолву апелляции оператор создаёт НОВУЮ
сделку-сеттлмент
POST /api/v1/p2p/appeals/{appeal_id}/settlement— сумма =received_amountоригинала (или обоснованный override), курс — новый на момент резолва, полный стандартный путь (эскроу → verify → complete), связиparent_deal_id/origin_appeal_id(UNIQUE: одна апелляция → максимум один сеттлмент, повтор — replay). Оригинал остаётсяEXPIREDнавсегда. По сеттлменту приходит обычный набор вебхуковdeal.created…deal.completed(обе версии API). - Кабинет: модалка amend показывает пересчитанный USDT до подтверждения, причина обязательна; в карточке EXPIRED-сделки с полученным платежом — панель «зачесть по факту» (сумма из данных; ручное переопределение — второй шаг подтверждения + причина); листинги помечают сеттлменты и их родителей.
Дока: PayIn → amend и
settle-as-received,
Disputes → сеттлмент,
Callbacks → deal.amount_changed,
Статусы → поля суммы.
Инструкция по миграции: действий мерчанта не требуется. Новые поля
(amount_version, parent_deal_id, origin_appeal_id) — additive; событие
deal.amount_changed обрабатывайте по best-practice «игнорируй неизвестное»,
если изменение суммы вам не значимо. V1-мерчанты новых событий не получают.
Миграции БД: 000017, 000018 (bridge-инкременты, идут с релизом
p2p-engine; для контуров с уже применённой 000005-сквошей — идемпотентны).
2026-09-01
[FIX] Возврат к канону конверта списков: data (откат регресса доки от 08-29)
Регресс документации: ночная правка 2026-08-29 переставила примеры листингов
на внутренние прото-имена полей ({"deals": [...]}, {"payment_methods": [...]}, total_count) — по ошибке: за источник истины был взят proto, а не
фактический HTTP-контракт. Фактическое поведение платформы не менялось с
2026-08-24 (см. запись 2026-08-24: канонический конверт data):
egress-маршалер шлюза отдаёт ВСЕ листинги merchant-контура как
{"data": [...], "next_page_token": ""} и не выносит на HTTP ничего сверх
этого (total_count существует только во внутреннем gRPC-контракте).
- Исправлены все страницы и примеры (index, deals, callbacks, banks, wallet,
disputes, turnover) и
openapi.yaml(схемы и примеры листингов). - Канон подтверждён живыми запросами на стейдже по каждому листингу:
/deals,/callbacks,/appeals,/passes,/banks,/payment-methods,/currencies,/wallet/deposits,/wallet/withdrawals,/deals/turnover— все отвечают{"data": [...], "next_page_token": ...}. - Напоминание канона: единичный ресурс — напрямую (
{"deal": {...}}); списки — всегдаdata;GET /balance— исключение (не листинг):{"wallets": [...]}. - Сопутствующая находка (ответ интеграторам): в живых каталогах тенантов
мобильного метода (
mobcom_rub) сейчас нет — ни на стейдже, ни на проде; актуальный набор методов мерчанта возвращаетGET /payment-methods.
Инструкция по миграции: не требуется — платформа всегда отвечала
data-конвертом; правилась только документация. Если ваш код уже читает
data — всё верно. Если ориентировались на вчерашние (29.08) примеры с
deals/total_count — замените чтение поля на data и уберите зависимость
от total_count.
[DOC] Канон домена платёжной страницы — checkout.syncra.money
- Канонический вид
payment_url:https://checkout.syncra.money/pay/{hash}(это же — компилируемый дефолт платформы в резолвереDB checkout_base_url → env CHECKOUT_BASE_URL → default). - Из документации вычищен второй домен (
pay.syncra.money/{hash}из Hosted Checkout/Quickstart иopenapi.yaml) — оба источника теперь указывают один канон.
Инструкция по миграции: не требуется — значение payment_url берите из
ответа создания сделки как есть, не конструируйте домен самостоятельно.
2026-08-29
[FIX] Ночная сверка №2: код догоняет доку (вебхуки, rate-limit-заголовки, идемпотентность per-merchant)
Аудит «дока ↔ proto ↔ код» второй волны. Здесь, в отличие от 2026-08-28,
правился и код платформы (ветка feature/docs-consistency-audit), потому
что дока обещала поведение, которого в коде не было. Обратная совместимость
сохранена: ничего не удалялось и не сужалось — только аддитивные события,
заголовки и защита изоляции.
[FEATURE] [callbacks] — Недостающие webhook-события реализованы в коде
deal.createdдля PayOut — теперь эмитится при создании выплаты (ранее — только у PayIn; status несётMATCHED/UNASSIGNEDна момент ответа создания). Повтор идемпотентного создания не шлёт второй вебхук.deal.expiredдля PayOut — эмитится при EXPIRED-переходе выплаты (в т.ч. по SLA изUNASSIGNED); холд возвращён.p2p.finance.withdrawal_failed(status: CANCELLED) — эмитится при отмене вывода оператором/до broadcast. Ранее событие было задокументировано, но не эмитилось.- Обработчики вебхуков обязаны игнорировать неизвестные типы событий
(best practice добавлена в Callbacks) — с выхода этих
событий мерчанты начнут получать новые
event-типы.
[FIX] [ratelimit] — Заголовки X-RateLimit-* действительно выставляются
- Дока обещала
X-RateLimit-Limit/X-RateLimit-Remaining/X-RateLimit-Reset(Unix-секунды сброса UTC-минуты) на каждом ответе HMAC-контура — код их не ставил. Теперь ставит: и на успешных ответах, и на429(Stripe-канон). Это аддитивное изменение — клиенты, не читающие заголовки, не затронуты.
[SECURITY] [idempotency] — Ключ идемпотентности скоупится по мерчанту
- PayOut: детерминистичный ключ выплаты теперь выводится из
(tenant, merchant, idempotency_key). Ранее формула не включала мерчанта, а replay-поиск был глобальным — два мерчанта с одинаковой строкой ключа могли сойтись на одной выплате, и второй получал чужую сделку в ответе (утечкаtarget_requisite). Теперь чужая строка под ключом →409(idempotency_key is already used by another merchant), replay — только своей сделки (легаси-нескоупленные ключи по-прежнему резолвятся для незавершённых ретраев). - PayIn: replay через idem-кэш и recovery-путь проверяют владельца найденной сделки (внутри тенанта); чужая сделка больше не возвращается.
- Обещание Идемпотентности («одинаковые ключи у разных мерчантов не конфликтуют») теперь — фактическое поведение платформы.
[DOC] [callbacks] — Точная математика ретраев доставки
- При
max_retries=5(умолчание) доставка пробуется 5 раз суммарно (исходная + 4 повтора, паузы 5s/30s/5m/15m); ступень 1h достижима при повышенном per-merchantmax_retries. Прежний текст «до 5 повторов после исходной» и утверждение про «паузу ≤ 5 минут» были неверны — удалены. - Успех доставки = любой ответ < 400 (включая 3xx), а не только 2xx.
response_bodyв истории доставок обрезается до 2048 байт.
[DOC] [deals] — Пагинация и фильтры листинга по факту
page_size: умолчание 50 (не 20), максимум 250.created_before— включительно (inclusive), как иcreated_after.total_countсчитает фильтрыdeal_type/statuses, но не дата-фильтры — исторический контракт, теперь задокументирован явно.- Листинг апелляций (
GET /appeals) — пагинирован (AIP-158, умолчание 20, максимум 100); прежняя пометка «параметры не применяются» устарела.
[DOC] [migration] — Реальные маршруты V1 compat-слоя
- Таблица сигнатур V1 указывала несуществующие маршруты
(
/v1/merchant/payin|payout|dispute). Исправлено на фактические:POST /v1/payments/incoming,POST /v1/payments/outgoing,POST /v1/merchant/withdraw,POST /v1/disputs/create,POST /v1/banks/list.
[DOC] [misc] — Прочие сверки
GET /wallet/deposit-address: в ответе естьupdated_at; 404-пример приведён к фактическому problem+json (detail — вложенный gRPC-JSON).POST /api-keysпомечен admin-only (ротация — dual-homed).GET /my-merchant— dual-homed (JWT или HMAC); PATCH — только JWT.- Replay-окно подписи: 5 минут назад / 60 секунд вперёд (не «±300 с»); у V1 replay-защита есть (300 с / +60 с), а не «нет».
reasonапелляции: обязательный минимум 10 символов (не «рекомендуется»); текст ошибки актуализирован.- CSV-экспорт:
counterparty=client_idдля PAYIN (пусто, если не передан),target_requisiteдля PAYOUT. - SDK-примеры §1: добавлен обязательный
payment_method_idво все 4 языка (пример без него получал 400); quickstart — «минимально 5 полей». - openapi.yaml: суммы int64 в примерах — строками;
wallet_id— UUID (TRC-адрес убран из примера баланса); kill-switch — bodyless toggle; статусы листинга принимают оба набора (OrderStatus | PayOutStatus); добавлены вебхукиp2p.finance.withdrawal_failedиpayment_methods.updated(каталог-конверт), статусwithdrawal_completed-примера —APPROVED;EmptyResponse— пустой объект; пер-endpointpage_size(deals 50/250, компакт-листинги 20/100).
Инструкция по миграции: не требуется. Новые события вебхуков — additive:
добавьте в фильтр deal.created/deal.expired (PayOut) и
p2p.finance.withdrawal_failed, если хотите на них реагировать; неизвестные
event просто логируйте. Единственное наблюдаемое изменение ошибок —
409 при коллизии idempotency_key между мерчантами (ранее такой запрос
мог вернуть чужую сделку — это был баг).
2026-08-28
[DOC] Ночная сверка контрактов: дока ↔ proto ↔ код (Stripe Grade)
Полный аудит публичной документации против фактического поведения платформы
(proto platform.p2p.v1 + p2p-engine). Изменения API-контракта — нет:
все правки приводят документацию, openapi.yaml и proto-комментарии к уже
работающему коду. Ничего удаляться не должно — обратная совместимость
сохранена полностью.
[DOC] [payout] — Унифицированная ссылка на метод: UUID и слаг на обеих ногах
POST /deals/payoutpayment_methodпринимает слаг ИЛИ UUID (ранее дока описывала только слаг) — оба значения резолвятся в один и тот же метод, как и в PayInpayment_method_id.- Задокументирован currency cross-check: метод чужой валюты
(
card_rubприcurrency: "TRY") →400 INVALID_ARGUMENT«payment method currency does not match the deal currency». - Неизвестная ссылка →
400со списком допустимых слагов (живой пример добавлен в Коды ошибок).
[DOC] [wallet] — Правда о выводе USDT: статусы, комиссии, идемпотентность
- Синхронный ответ
POST /wallet/withdraw: статус —COMPLETED(авто-проведение) илиPENDING_MANUAL(очередь ручного одобрения), а неAPPROVED/PENDING, как писала дока. Доменные статусы заявки (PENDING/APPROVED/CANCELLED) — отдельная поверхность (листинги и вебхуки); прежний WARNING «COMPLETEDне используется» был неверен и удалён. - Добавлены поля ответа
fee_usdt_cents/net_usdt_cents(USDT-центы). idempotency_keyвывода: поле контракта, но не требуется и не валидируется — идемпотентность гарантируется платформой (детерминированный серверный ключ по мерчант+адрес+сумма+комиссия).- Задокументированы WAVE-эндпоинты кошелька, отсутствовавшие на странице:
GET /wallet/withdraw-fee(квота комиссии до заявки),GET /wallet/deposits(TRC-20 депозиты с custodial-статусами),GET /wallet/withdrawals(история выводов: очередь ручных одобрений, смёрженная с ledger-списаниями).
[DOC] [payin] — amount_match_status: ровно три значения
- Значение
underpaidне существует: канонический набор —full/partial(= поступило меньше) /overpaid, строго lowercase. Исправлено в Deals и proto-комментарииMerchantDealInfo(вместе с регенерациейpb.go).
[DOC] [passes] — Required-поля создания pass'а
- Обязательное поле одно —
amount.currency_id,requisite_type,payment_method_id,provider_id— опциональные фильтры (пусто = «любой»).payment_method_idна pass-ветке принимает только UUID (слаг не резолвится — в отличие от ног сделки). Прежняя версия страницы требовалаcurrency_id+requisite_type— неверна. 409 Conflictзакреплён как единственный в API: конкурентный резерв pass'а (gRPCABORTED, «pass was concurrently reserved»); errors.mdx раньше категорично заявлял «409 не используется».
[DOC] [general] — Kill-switch, export-путь, V1-маппинг, мелкие фиксы
- Kill-switch (
POST /p2p/merchants/{id}/kill-switch): это toggle без тела (никакихactive/reason) и admin-only (не self-service мерчанта; кода ошибкиMERCHANT_DISABLEDне существует — фактически403 merchant is disabled). То же про/disable//enable. - CSV-экспорт: канонический путь теперь
/api/v1/p2p/merchant/deals/export; корневое зеркало/api/v1/p2p/deals/exportпродолжает работать и помечено deprecated (обратная совместимость сохранена). - V1-маппинг PayIn-кода
12— этоCANCELLED(иSPAM_REJECTEDтоже транслируется в12); migration-guide исправлен (12 → SPAM_REJECTEDбыло неверно). - migration-guide: конверт ответов V2 — proto-поля верхнего уровня (никакой
обёртки
{data});payment_method_id— REQUIRED (не optional). - Слаги каталога канонизированы по всей доке:
card_rub/sbp_rub/mobcom_rub(устаревшиеcard/sbp/card2cardубраны из примеров). - balance.mdx: фантомные «типы балансов» MAIN/INSURANCE/DEPOSIT убраны —
GET /balanceвозвращает только фактические кошельки;wallet_id— UUID кошелька, а не TRC-20 адрес. - api-reference: идемпотентность — поле
idempotency_keyв теле (заголовокIdempotency-Keyв Merchant API не используется). - openapi.yaml: добавлены отсутствовавшие пути (
/currencies,/deals/export,/deals/turnover,/callbacks/{id}/retry,/wallet/withdraw-fee,/wallet/deposits,/wallet/withdrawals,/my-merchant), исправлены схемы (withdraw в целых USDT, required-набор CreatePayInRequest, int64-строки в примерах),402заменён на канон400 FAILED_PRECONDITION.
Инструкция по миграции: не требуется — контракты не менялись, менялась
только документация. Если вы полагались на строку APPROVED в синхронном
ответе вывода — проверьте обработчик: фактическое поведение платформы
(COMPLETED/PENDING_MANUAL) не менялось с момента релиза WAVE 3.
2026-08-26
[FEATURE] PayIn: статус CANCELLED — явная отмена сделки игроком или мерчем
- Новый терминальный статус
CANCELLEDдля депозитных (PayIn) сделок: отличается отEXPIRED(таймаут) — теперь «игрок активно отменил» и «время вышло» различаются. - Разрешён переход из
INITIALIZED,ESCROW_LOCKED,PAYMENT_NOTIFIED(до подтверждения платежа). Эскроу-холды снимаются автоматически, комиссия обнуляется, матчи →FAILED. - Новые эндпоинты:
POST /api/v1/p2p/merchant/deals/{deal_id}/cancel— отмена мерчем (HMAC), тело{"reason": "..."}опционально; повтор на уже-CANCELLEDсделке → 200 идемпотентно; не-PayIn или нелегальный статус → 400.POST /api/v1/p2p/checkout/{hash}/cancel— отмена игроком на hosted-checkout (по deal hash); терминальная сделка → 409.
- Новое webhook-событие
deal.cancelled(payload идентиченdeal.expired,status: "CANCELLED"). Мерчи, фильтрующие поdeal.completed, не затронуты. - V1-адаптер:
CANCELLED→ код12(Cancelled), фильтр листингаGET /deals?statuses=принимаетCANCELLED.
Инструкция по миграции: ничего ломать не нужно — изменение additive.
Рекомендуем добавить CANCELLED в списки неуспешных статусов и обработчик
deal.cancelled, если хотите отличать отмены от таймаутов.
2026-08-24
[FIX] PayIn: payment_method_id обязателен
- Ранее: без
payment_method_id→ 500 "payment method is required for order matching" + создавалась "мусорная" заявка со статусом EXPIRED. - Теперь: 400 INVALID_ARGUMENT с подсказкой
GET /payment-methods. Заявка не создаётся вообще. payment_method_id— REQUIRED поле. Получите UUID из каталога методов перед созданием PayIn.
Журнал изменений (Changelog)
В данном разделе публикуется официальный список изменений и обновлений Syncra Merchant API. Мы фиксируем все новые функции (features), исправления ошибок (bugfixes), объявления об устаревании (deprecations) и обратно-несовместимые изменения (breaking changes).
Формат записей
Каждая запись в changelog имеет стандартизированную структуру:
- Заголовок: Дата релиза (в формате YYYY-MM-DD) и краткое резюме.
- Тип изменения:
[FEATURE]— Добавление нового функционала или эндпоинта.[FIX]— Исправление ошибок в логике работы API.[DEPRECATION]— Предупреждение об устаревании функционала и планируемом отключении.[BREAKING]— Обратно-несовместимые изменения, требующие обновления вашего кода.
- Категория: Сфера влияния изменения (
payin,payout,auth,callbacks,disputes,balance,general). - Описание: Детальное объяснение изменений и инструкции по обновлению (Migration Path).
Актуальная история версий
2026-08-23 — Волны 7/8: кабинетные эндпоинты и сверка доки с живым стейджем
Все примеры в документации приведены к фактическим ответам стейджа
(api-stage.syncra.money, живые curl). Новые страницы: CSV-экспорт,
Обороты, Профиль и лимиты.
[FEATURE] [general] — CSV-экспорт сделок
GET /api/v1/p2p/deals/export (путь вне merchant-префикса): UNION-выгрузка
PayIn+PayOut, фильтры листинга, Accept: text/csv → сырой RFC 4180-документ
(Content-Disposition: attachment; filename="deals-YYYYMMDD.csv"), без Accept —
JSON-конверт csv/file_name/row_count/truncated. Cap 10 000 строк.
[FEATURE] [general] — Обороты сделок
GET /api/v1/p2p/merchant/deals/turnover?date_from&date_to (RFC3339,
обязательные, окно ≤ 92 дней, deal_type опционален) → rows[]
(date,deal_type,amount_minor,currency); исключены
EXPIRED/SPAM_REJECTED/FAILED.
[FEATURE] [callbacks] — История доставок и ручной retry
GET /callbacks (keyset-пагинация page_token/next_page_token) —
статусы PENDING/SUCCESS/RETRY/ERROR, response_code, retry_count,
next_retry_at. POST /callbacks/{id}/retry: только ERROR/RETRY
(иначе 400), cooldown 60 с (иначе 429), чужой — 403, неизвестный — 404.
[FEATURE] [general] — Лимиты мерчанта и kill_switch_reason
GET/PATCH /api/v1/p2p/my-merchant (кабинетный JWT):
deal_min_amount/deal_max_amount/daily_deal_amount_limit (int64 копейки;
отсутствует = не менять, 0 = снять, >0 = установить); нарушения при создании
сделок: min/max → 400 INVALID_ARGUMENT, daily → 400 FAILED_PRECONDITION.
GET my-merchant отдаёт kill_switch + kill_switch_reason (баннер кабинета).
[FIX] [general] — Сериализация int64 и формат ошибок
Зафиксировано в доках: значения int64 в JSON-ответах передаются строками
("amount": "100000"); ошибки — RFC 9457 problem+json c type: "about:blank",
вложенными gRPC-деталями в detail и instance upstream-сервиса; канон
«неверное состояние → 400» (не 409).
2026-08-22 — Неделя интеграции: приведение контрактов к фактическому поведению платформы
Волна фиксов 2026-08-21/22 (проверена живым E2E на стейдже). Все изменения ниже отражены в соответствующих разделах документации.
[BREAKING] [general]
Убрана обещанная обёртка data в успешных ответах. grpc-gateway
отдаёт proto-поля верхнего уровня (создание и получение PayIn/PayOut,
листинг, баланс, пропуска, апелляции):
{"deal": {"deal_id": "..."}}
{"deals": [], "next_page_token": "", "total_count": 0}
{"wallets": []}Схемы и примеры openapi.yaml исправлены соответственно.
Инструкция по миграции:
- const { payment_url } = response.data
+ const { payment_url } = response.deal[BREAKING] [general]
Формат всех ошибок — RFC 9457 problem+json. Edge-gateway переписывает
все non-2xx ответы в application/problem+json
({"type","title","status","detail","instance"}); старый конверт
{"error":{"code","message","details"}} больше не возвращается. gRPC-/
doc-коды (INVALID_ARGUMENT, UNAUTHENTICATED, ...) остаются
семантикой (определяют HTTP-статус и текст detail), но полем code в
теле не передаются. См. Коды ошибок.
[FIX] [general]
Новые HTTP-коды вместо «зонтичного» 500:
404 Not Found— сделка не найдена вGET /deals/{deal_id}(ранее500).503 Service Unavailable— «no matching trader available, retry later» при исчерпании каскада (ранее500); retry с backoff.
[FIX] [auth]
Auth hardening недели интеграции (кратко):
- Rotate grace period теперь реален: 15-минутное dual-key окно после
ротации; валидна только целиком старая пара (старый токен + старый
секрет), смешанные комбинации —
401; исходящие вебхуки подписываются новым секретом немедленно; окно настраивается черезMERCHANT_KEY_GRACE_PERIOD(0= off). Поля ответа issue/rotate —token/secret(НЕapi_token/webhook_secret). См. Управление API-ключами. merchant_idв запросе — advisory при HMAC (claims-win): значение (в т.ч. невалидного формата или чужое) молча игнорируется, реальный скоуп — из подписанного токена; запрос возвращает200. Исключение — cabinet-JWT: там несоответствиеmerchant_id→403.
[FIX] [callbacks]
- Per-deal
callback_urlреально override'ит доставку (PayIn): иерархия per-dealcallback_url→merchant.webhook_url; оба пусты — колбэк не создаётся. Для PayOut per-deal override не поддерживается (поля в запросе нет) — толькоmerchant.webhook_url. - Подпись
X-Signatureвебхука считается от байтов тела ровно в том виде, в котором они доставляются (фикс 2026-08-22): подпись и тело гарантированно разделяют один байтовый источник, HMAC мерчанта по полученному телу совпадает. См. Callbacks → Подпись запроса.
[FIX] [payout]
Статусная модель после создания приведена к фактической: синхронный
авто-матчинг каскада возвращает MATCHED (есть свободный трейдер),
иначе UNASSIGNED — retry-воркер продолжает мэтчинг до SLA, по
истечении которого выплата переходит в терминальный EXPIRED (холд
возвращён). deal_type=PAYOUT-сделки видны в GET /deals и
GET /deals/{deal_id}. wallet_id в запросе — USDT-кошелёк списания
(холд в USDT по SELL-курсу), а не fiat-кошелёк; currency в ответе — эхо
ISO-кода fiat-валюты выплаты. См. PayOut.
[FIX] [balance]
GET /balance возвращает реальные кошельки мерчанта из money-сервиса —
одна строка на фактический кошелёк со своей валютой и wallet_id
(синтетических строк нет); frozen отражает активные холды. См.
Балансы.
[FIX] [payin]
GET /deals задокументирован как объединение PAYIN (p2p_orders) и
PAYOUT (p2p_payouts) в единый листинг: payment_url присутствует только
у PAYIN, target_requisite (эхо, без маскировки) — только у PAYOUT;
фильтр deal_type=PAYIN|PAYOUT. См. Deals.
[FIX] [general]
Идемпотентность: формат idempotency_key фактически не валидируется
(любая непустая строка; рекомендуемый формат — UUID v4); повторный вызов с
тем же ключом возвращает ту же сделку без дубля. Убрано обещание лимита в
128 символов / restrictions на символы. См.
Идемпотентность.
[NEW] [balance]
Deposit address — две операции. TRC-20 адрес для зачисления USDT-обеспечения (collateral) на операционный баланс мерчанта (выплаты, крипто-выводы, комиссии; игроки в PayIn платят по реквизитам трейдеров, НЕ на этот адрес):
GET /wallet/deposit-address— read-only текущий активный адрес;404 problem+json(«deposit address not provisioned yet — POST /wallet/deposit-address to generate one»), если адрес ещё не сгенерирован.POST /wallet/deposit-address— генерация/ротация: каноничный путь безmerchant_id(скоуп — из токена). Ротация немедленно заменяет адрес в строке мерчанта, при этом все ранее выпущенные адреса остаются в постоянном polling-наборе — USDT на старый адрес не теряются. Legacy-путьPOST /merchants/{merchant_id}/deposit-addressостаётся рабочим для admin-impersonation.
См. Кошелёк → TRC-20 адрес для пополнения.
[BREAKING] [general]
trace_id / traceId удалены из тел problem+json. Тело ошибки — строго RFC
9457 поля (type, title, status, detail, instance); идентификатор
трассировки передаётся заголовком X-Trace-Id на каждом ответе с ошибкой
(Stripe-канон; генерируется gateway'ем, если upstream не предоставил). Именно
его указывайте в обращениях в поддержку. Для браузерных клиентов заголовок
экспонируется через CORS (Access-Control-Expose-Headers). См. Коды ошибок →
Идентификатор
трассировки.
Инструкция по миграции:
- const traceId = response.body.trace_id
+ const traceId = response.headers.get('X-Trace-Id')[DOCS] [payout]
Lifecycle PayOut выпрямлен в Migration Guide и
Справочнике статусов (приведён к PayOut):
синхронный авто-матч каскада при создании возвращает сразу MATCHED либо
UNASSIGNED (retry-воркер перематчивает; по SLA — EXPIRED с возвратом
холда); INITIALIZED — стартовый статус стейт-машины (граничные случаи:
провайдер-ветка/гонки); далее MATCHED → PROCESSING → COMPLETED |
FAILED. В statuses добавлена FSM-диаграмма PayOut.
2026-08-21 — Документация PayIn: единый контракт методов, мобильная коммерция (SIM), пример deal.expired
[FEATURE] [payin]
Явная фиксация принципа единого контракта: POST /deals/payin принимает один и
тот же набор полей для любого метода оплаты — метод-специфичных параметров в
запросе не существует, выбор метода задаётся только payment_method_id.
Специфика канала (тип реквизита, формат отображения, инструкция для плательщика)
инкапсулирована на стороне платформы и показывается на платёжной странице. См.
Прием платежей → Поддерживаемые методы
оплаты.
- В список типовых методов добавлены методы мобильной коммерции
(
RequisiteType: SIM): реквизит для плательщика — номер телефона оператора связи, название оператора отображается как «банк получателя». Номер телефона самого плательщика (MSISDN) не требуется и не передаётся. - Поле
phone_numberвCheckoutViewдокументировано дляSBPиSIM(ранее — толькоSBP).
[FEATURE] [callbacks]
Добавлен пример payload deal.expired — терминального неуспешного исхода
PayIn (истечение payment_timeout_at без поступления средств): поля
received_amount и amount_match_status в нём отсутствуют, сверка сумм не
выполняется. См. Callbacks → Примеры payload по
событиям.
2026-07-12 — Запуск Merchant API V2 и Адаптера V1
[FEATURE] [general]
Официальный запуск Merchant API V2. Новая архитектура предоставляет повышенную стабильность, единый формат интеграции и улучшенные показатели безопасности.
Основные нововведения:
- HMAC-SHA256 подписи: Внедрена унифицированная схема подписи
X-Signatureот тела запроса для всех эндпоинтов вместо разрозненных формул в V1. - Строковые перечисления статусов: Переход с числовых кодов состояний на
строковые String Enums
UPPER_SNAKE_CASE(например, код1→INITIALIZED, код11→COMPLETED), что повышает читаемость логов и кода. Полная таблица соответствия кодов V1 и статусов V2 — в Справочнике статусов. - Суммы в минимальных единицах (копейках): Суммы больше не передаются в виде
строк с точкой (
"1500.00"). Теперь используется целочисленный форматint64(копейки, центы:150000). Это защищает от ошибок округления чисел с плавающей запятой. - OpenAPI-спецификация: Документация теперь содержит полную OpenAPI-схему
(
openapi.yaml) с возможностью импорта в Postman/Insomnia и навигацией по эндпоинтам в боковой панели.
[FEATURE] [general]
Внедрение V1 Compatibility Adapter (Адаптера совместимости).
- Позволяет существующим клиентам, интегрированным с API V1, переключиться на новую инфраструктуру Syncra V2 без изменения своего исходного кода.
- Адаптер автоматически парсит старые заголовки (
MERCHANT,SIGNATURE), проверяет подписи по алгоритму HMAC-SHA512, конвертирует форматы сумм и отдает ответы в старом конверте{failures, value, isSuccess}.
[DEPRECATION] [general]
Объявление о выводе из эксплуатации API V1.
- Период поддержки (Grace Period): до 12 января 2027 года. Адаптер
работает в штатном режиме без ограничений. Уже в этот период каждый ответ V1
несёт стандартные IETF-заголовки машиночитаемой депрекации:
Deprecation: trueSunset: <дата отключения>(RFC 1123)Link: </api/v2...>; rel="successor-version"— V2-эквивалент пути.
- Полное отключение (Sunset): 12 января 2027 года V1 адаптер выключается
(дата по умолчанию; может быть изменена оператором платформы). Все запросы по
старым путям начинают возвращать
410 Goneс RFC 9457 problem details. - Заголовок
X-Syncra-Deprecatedне используется и не будет — сигнализация о депрекации идёт исключительно черезDeprecation/Sunset/Linkвыше.
2026-07-13 — Архитектурная модернизация: Data-Driven Currencies и Appeals API
[BREAKING] [payout]
Поля card_number и full_name в PayOut переименованы в target_requisite и
target_name для поддержки всех типов реквизитов (карта, СБП, e-wallet). V1
адаптер обрабатывает маппинг автоматически.
Инструкция по миграции:
- "card_number": "2202201234567890"
- "full_name": "Иван Иванович"
+ "target_requisite": "2202201234567890"
+ "target_name": "Иван Иванович"[FEATURE] [disputes]
Добавлен полноценный Appeals API для мерчантов:
POST /appeals— открытие диспута по сделкеGET /appeals— список диспутов с фильтрациейGET /appeals/{id}— получение диспутаPOST /appeals/{id}/messages— отправка сообщения в чатGET /appeals/{id}/messages— история чата
[FEATURE] [general]
Переход на data-driven конфигурацию: валюты, страны, лимиты и методы оплаты теперь управляются через админ-панель без перезапуска сервисов.
[FEATURE] [balance]
Мультивалютные балансы: поле currency теперь отражает реальную валюту тенанта.
USDT wallet_id содержит реальный TRC-20 адрес мерчанта.
Август 2026 — TRY/Havale Channel, Antifraud, White-label и DO Migration
2026-08-18 — Merchant API v0.2.11: канал TRY/Havale для выплат
[FEATURE] [payout]
Выплаты в Турции по IBAN (Havale): в POST /deals/payout добавлены два
optional-поля:
target_bank(string) — банк получателя (слаг или название, напримерziraat); используется для inside-bank каскадного матчинга.requisite_details(map<string,string>) — именованные реквизиты получателя; допустимые ключи:iban,account_number,document_number,bank_name,phone_number. Неизвестные ключи отклоняются с400и списком допустимых.
См. PayOut → Выплаты TRY / IBAN (Havale).
[FEATURE] [general]
Новый справочный эндпоинт GET /api/v1/p2p/merchant/payment-methods —
активные методы тенанта мерчанта (id UUID, slug, name,
requisite_types, currency_code, status). Это канонический источник
значения payment_method_id для POST /deals/payin и слагов
payment_method для POST /deals/payout. GET /banks UUID не
возвращает (его methods — типы реквизитов RequisiteType).
См. Banks → Получение списка методов через API.
Инструкция по миграции: если вы программно получали payment_method_id
из GET /banks — переключитесь на GET /payment-methods; если UUID были
захардкожены — сверьте их с ответом нового эндпоинта после провижининга
методов тенанта.
[FIX] [payin]
Страница PayIn приведена к фактическому поведению API:
- Исправлен источник
payment_method_id: в таблицах параметров ранее ошибочно указывалсяGET /banks; канонический источник UUID —GET /payment-methods(см. выше). Аналогичная правка внесена в Quickstart и Migration Guide. - Статус в примере ответа
200 OK—ESCROW_LOCKED: подбор трейдера и эскроу-лок выполняются синхронно в рамках запроса, при неудачном матчинге вызов завершается ошибкой, а не «висящей» сделкой.INITIALIZED— кратковременный транзитный статус, в ответе создания практически не наблюдается (возможен вGET /dealsдо завершения подбора). - Добавлен пример ответа для TRY (
BANK_TRANSFER/ Havale). - Новая секция «Где реквизиты получателя при PayIn»
(PayIn): реквизиты
получателя (PAN, телефон СБП, IBAN) никогда не возвращаются в теле
ответа
POST /deals/payin(PII-минимизация). Клиент получает их на платёжной странице через публичный эндпоинтGET /api/v1/p2p/checkout/{hash}(контрактCheckoutView:iban,holder_name,payment_method_name,card_number/phone_number); в терминальных состояниях чувствительные поля обнуляются.
[FIX] [payout]
Задокументирована конвенция эха реквизитов выплаты в V2: target_requisite
и значения requisite_details в ответах — эхо данных из запроса мерчанта,
без маскировки (это собственные реквизиты получателя мерчанта, а не данные
трейдера; в логах платформа сохраняет только набор ключей). Маска вида
220220******7890 осталась только в legacy-эндпоинтах V1
(GET /v1/payments/outgoing/{id} и callback-конверте V1). См.
PayOut → Выплаты TRY / IBAN (Havale).
[FIX] [callbacks]
Явное уточнение в Callbacks: платёжные реквизиты в вебхуки
не передаются — никогда. Тела вебхуков (V2 CallbackEventPayload и legacy
V1-конверт) содержат только идентификаторы, суммы, валюту и статус: полные
PAN/IBAN/телефоны мерчанту не отправляются. В V1-конверте cardNumber
приходит только замаскированным (последние 4 цифры), чувствительные
значения в provider_metadata редуцируются. Исчерпывающий источник
реквизитов для PayIn — публичный GET /api/v1/p2p/checkout/{hash}.
[FIX] [general]
Migration Guide — исправления и восстановленные справочники:
- Статусы PayOut: исправлена фактическая ошибка — статус
EXPIREDв V2 существует (таймаут), статусаCANCELLEDнет. Реальный жизненный цикл:INITIALIZED→MATCHED→PROCESSING→COMPLETED; при отсутствии трейдеров —UNASSIGNED, при ошибке —FAILED, по таймауту —EXPIRED(в V1EXPIRED/FAILEDмаппятся в код30). - Таблица маппинга статусов PayIn (V1 код → V2 enum): все коды
1–31, включая переплату/недоплату —14/15→COMPLETED+amount_match_status: overpaid/partial. - Маппинг полей PayIn: V1
method→ V2payment_method_id(UUID изGET /payment-methods); поляpayment_methodдля PayIn в V2 нет. - Восстановлен справочник «V1 сигнатуры запросов» — payload-форматы
Compatibility Adapter по всем 4 legacy-эндпоинтам: PayIn/PayOut —
{timestamp};{id};{salt}, Withdraw — 4 поля (включаяaddress), Dispute — 2 поля без соли; replay-защита:timestampне старше 300 секунд и не более чем на 60 секунд в будущем.
[FIX] [general]
Прочие документационные правки:
- Banks: убрано нереализованное обещание о «временном
исчезновении» банков из справочника — состав
GET /banksформируется из активных методов тенанта (p2p_payment_methods.status = ACTIVE); доступность конкретного трейдера влияет на матчинг сделки, а не на справочник. - Обзор Merchant API и этот changelog: дата полного отключения
(sunset) V1 зафиксирована как 12 января 2027 года (согласно коду
платформы); каждый ответ V1 несёт заголовки
Deprecation,SunsetиLink; rel="successor-version". - Quickstart: статусы в примерах выровнены с реальным
поведением — создание PayIn возвращает
ESCROW_LOCKED(былоPENDING), вебхук —amount_match_status: full(былоMATCHED).
2026-08-09 — DO Migration Prep и выравнивание документации
[FEATURE] [general]
Подготовка инфраструктуры к DO-migration (Digital Ocean переезд):
- RedPanda in-cluster — добавлен для событийной шины (замена managed Kafka).
- Vault HA — High Availability режим для секретов.
- Blue/Green деплой — стратегия бесшовного переключения между окружениями.
- Module-registry переведён на SASL/SCRAM-аутентификацию.
[FIX] [general]
Документационный аудит: все страницы Merchant API выровнены под V2 canonical
contract. Унифицированы X-Signature (не X-Syncra-Signature), payment_url
(не payment_page_url), deal_id (не id), tron_address (не address).
Удалены несуществующие mapping'и из migration-guide.
2026-08-05 — Исправление 4 P0-багов в клиентской аналитике
[FIX] [general]
Исправлены 4 критических бага (P0) в детальной статистике клиентов и antifraud-аналитике:
- Detail stats — некорректный расчёт статистики по сделкам клиента.
- Double-count — задвоение депозитов при определённых переходах статусов.
- Error mapping — неправильная трансляция доменных ошибок в HTTP-коды.
- Fingerprint — обработка пустого/невалидного device fingerprint.
2026-08-04 — IBAN/BANK_TRANSFER и улучшения V1 compat adapter
[FEATURE] [payin]
Добавлен тип реквизита BANK_TRANSFER с поддержкой IBAN для
международных рынков (Turkish Havale, SEPA). Игрок видит IBAN получателя, ФИО
держателя счёта и название банка/канала. См. Hosted Checkout → Перевод по
IBAN.
[FIX] [general]
Улучшения V1 Compatibility Adapter: исправлены withdrawal callback, статус
OVERPAID и URL prefix (3 P0-пробела закрыты).
2026-08-03 — Antifraud stack и White-label brand_config
[FEATURE] [general]
Запуск полноценного Antifraud-стека (TD-081). См. Antifraud:
- Velocity protection — лимит 10 PayIn/час на
client_id, ошибкаCLIENT_RATE_LIMITED(HTTP 429). - Customer blocking —
IsBlocked+BlockedUntil, ошибкаCUSTOMER_BLOCKED(HTTP 403). - Device fingerprinting — заголовок
X-Player-Fingerprint, SHA-256 хэш, GDPR-compliant. - Auto-segmentation — FTD → STD при 3 депозитах, STD → TRUSTED при 10. VIP — ручной оверрайд.
- Player tracking — сохранение
FirstIP/LastIP/LastUserAgentна записи клиента. - Trust-based cascade routing — правила каскада могут фильтровать команды по
customer_type.
[FEATURE] [payin]
White-label brand_config для payform — мерчанты могут кастомизировать
платёжную страницу (primary_color, logo_url, favicon_url, brand_name,
theme) через админ-панель. См. Hosted Checkout →
Брендирование.
[FIX] [general]
RLS purge (TD-068) — корректная очистка Row-Level Security политик при операциях обслуживания.
Шаблон для добавления будущих записей
При внесении любых изменений в API разработчики Syncra обязаны добавлять новую запись в конец этого документа по следующему шаблону:
### YYYY-MM-DD — Заголовок изменения
#### `[FEATURE|FIX|DEPRECATION|BREAKING]` `[категория]`
Детальное описание изменений для разработчиков мерчантов.
**Инструкция по миграции (если применимо):**
Что именно нужно переписать на стороне мерчанта.