API Reference¶
Модуль CM Ocean Loyalty предоставляет REST API для управления балльным леджером, акциями,
конфигурацией программы и уровнями, клиентами, их тегами и сегментами, настройкой карточки клиента,
справочниками (НСИ), партнёрскими предложениями, реферальной программой, достижениями, мобильным
кошельком, обменом данными, мониторингом и отчётами. Все эндпоинты используют общий префикс /v1
и обмениваются данными в формате JSON.
Источник истины
API реализован по принципу code-first: спецификация OpenAPI генерируется из кода и
проходит diff-контроль при сборке. Машиночитаемая спецификация (OpenAPI 3.1) поставляется
вместе с модулем в файле openapi.yml и доступна для импорта в Swagger UI, Postman или
кодогенераторы клиентов.
Группы эндпоинтов¶
| Группа | Назначение | Право | Базовые пути |
|---|---|---|---|
Акции (promotions) |
CRUD акций, версионирование, ЖЦ (черновик → запланирована → запуск → пауза → архив), согласование запуска по принципу «четырёх глаз», лимиты, статистика, массовые операции, перенос между контурами | LOYALTY_PROMOTION_READ/WRITE; запуск — LOYALTY_PROMOTION_ACTIVATE; решение по согласованию — LOYALTY_PROMOTION_APPROVE |
/v1/promotions, /v1/promotions/{id}/..., /v1/promotions/{id}/approvals, /v1/promotions/bulk-*, /v1/promotions/stats, /v1/admin/promotions/export, /import |
Условия акции (promotion-criteria) |
Реестр условий для экрана «Настройка акции» (коробочные и добавленные условия, способы задать значение), условия формы акции, статистика и поступление переменных покупки | LOYALTY_DICTIONARY_READ/WRITE (реестр), LOYALTY_PROMOTION_READ (форма акции) |
/v1/admin/promotion-criteria, /v1/admin/promotion-criteria/attribute-stats, /v1/promotions/criteria, /v1/promotions/{id}/criteria/attribute-activity |
Справочники формы акции (promotion-form-dictionary) |
Опубликованные записи справочников для значений условий акции: поиск, страницы, проверка списка кодов | LOYALTY_PROMOTION_READ |
/v1/promotions/dictionaries/{key}/entries, /v1/promotions/dictionaries/{key}/entries/lookup |
Справочник пользователей (users) |
Сотрудники, хотя бы раз входившие в продукт: выбор согласующих и получателей оповещения | LOYALTY_PROMOTION_WRITE |
/v1/users |
Механики (mechanics) |
Каталог шаблонов акций (= диаграммы RT Flow), перенос между контурами | LOYALTY_PROMOTION_READ/WRITE |
/v1/mechanics, /v1/mechanics/{code}, /v1/admin/mechanics/export, /import |
| Базовое начисление | Настройка глобальной механики кэшбэка | LOYALTY_DICTIONARY_READ/WRITE |
/v1/admin/global-mechanic |
Конфигурация программы (program-config) |
Конфигурации программы лояльности: уровни, правила перехода и списания, акции программы и уровней; каталог, черновики, дублирование, активация, история активаций | LOYALTY_PROGRAM_CONFIG_READ/WRITE; активация — LOYALTY_PROGRAM_CONFIG_ACTIVATE |
/v1/program-configs, /v1/program-configs/{id}/..., /v1/program-configs/activations |
Теги клиента (tag) |
Справочник тегов со своим ЖЦ: поиск, создание, переименование (If-Match), слияние, пакетное удаление, перенос бандлом |
LOYALTY_TAG_READ/WRITE |
/v1/tags, /v1/tags/{tagId}/..., /v1/tags/bulk-delete, /export, /import, /lookup |
Метки акций (promotion-label) |
Справочник меток со своим ЖЦ — зеркало тегов, но для акций | LOYALTY_PROMOTION_LABEL_READ/WRITE |
/v1/promotion-labels, /v1/promotion-labels/{labelId}/..., /bulk-delete, /export, /import, /lookup |
Сегменты клиентов (customer-segment) |
Справочник сегментов (число клиентов и действующих акций, архив, удаление), журнал заливок, сегменты клиента | LOYALTY_SEGMENT_READ/WRITE; список сегментов — также с LOYALTY_PROMOTION_READ, LOYALTY_DICTIONARY_READ или LOYALTY_CUSTOMER_READ; сегменты клиента — LOYALTY_PROFILE_READ + LOYALTY_MONITORING_READ |
/v1/customer-segments, /v1/admin/customer-segments/fills, /v1/customers/{externalId}/segments |
Приём сегментов (integration) |
Регистрация сегмента, пачки участников и завершение заливки из системы кампаний (Batch Flow) | LOYALTY_SEGMENT_INTAKE |
/v1/integration/customer-segments/** |
| Условия аудитории акции | Проверка условий (теги, сегменты, участие в акциях/метках) из RT Flow — та же семантика, что у audience акции |
LOYALTY_INTEGRATION_READ |
/v1/integration/rtflow/condition-checks |
Клиенты, счета и баланс (customer) |
Клиенты, каталог с поиском/фильтрами, карточка, теги клиента, счета, баланс по субсчетам, партии баллов и сроки сгорания, история смены статуса, начисление/списание, hold/commit/cancel, слияние, мягкое удаление, массовые операции | LOYALTY_CUSTOMER_*, LOYALTY_ACCOUNT_*, LOYALTY_ACCRUAL_WRITE, LOYALTY_REDEMPTION_WRITE, LOYALTY_CUSTOMER_TAG_WRITE; карточка, партии и история статуса — LOYALTY_PROFILE_READ + LOYALTY_MONITORING_READ |
/v1/customers, /v1/customers/{externalId}/..., /v1/customers/bulk-* |
| Ручные операции и пакеты | Асинхронный приём пакета (файл/список) на начисление, корректировку, перевод уровня, добавление и снятие тегов; статус пакета, поток событий (SSE), CSV-отчёты | Право операции пакета (ACCRUAL_WRITE/REDEMPTION_WRITE/TIER_WRITE/CUSTOMER_TAG_WRITE) |
/v1/customers/operations/batches, /v1/customers/operations/import/validate* |
Импорт клиентов (customers) |
Загрузка клиентов из CSV с предварительной проверкой (dry-run) | LOYALTY_CUSTOMER_WRITE |
/v1/customers/import, /v1/customers/import/validate |
| Достижения | Каталог правил «условие → бейдж», бейджи клиента, пересчёт по требованию | LOYALTY_ACHIEVEMENT_READ/WRITE, LOYALTY_PROFILE_READ |
/v1/admin/achievements, /v1/customers/{externalId}/achievements |
| Мобильный кошелёк | Карта участника для Apple Wallet / Google Кошелька | B2C_AUTHORITIES (клиентский скоуп loyalty.b2c или LOYALTY_PROFILE_READ для предпросмотра) |
/v1/b2c/me/wallet/apple, /google |
| Реферальная программа | Реферальный блок клиента, список приглашённых | LOYALTY_PROFILE_READ + LOYALTY_MONITORING_READ |
/v1/customers/{externalId}/referral, /referrals |
Операции (Operations) |
Пополнение, списание, перевод, обмен валют между счетами | LOYALTY_OPERATION_WRITE |
/v1/top-up, /v1/withdraw, /v1/transfer, /v1/exchange |
Реальное время (realtime) |
Событие покупки → расчёт акций → начисление | LOYALTY_EVENT_WRITE |
/v1/events/purchase |
Интеграции (integration) |
Приём чеков POS, возврат по чеку и его отмена, резолюция карты, приём начислений от CM Ocean Promo, транзакция у партнёра, начисление RT Flow, проекция клиента Check Scan, сегменты клиента для внешних систем | LOYALTY_INTEGRATION_READ/WRITE |
/v1/integration/pos/**, /v1/integration/promo/**, /v1/integration/partner/transactions, /v1/integration/rtflow/accruals, /v1/integration/checkscan/customers/{externalId}, /v1/integration/customers/{externalId}/segments |
Партнёры и офферы (partner) |
Реестр партнёров, партнёрские офферы (ЖЦ, акцепт/отзыв клиентом), отчёт взаиморасчётов | LOYALTY_PROMOTION_READ/WRITE |
/v1/partners, /v1/partner-offers, /v1/b2c/me/partner-offers |
Мерчанты (admin-merchant) |
Справочник мерчантов (MID, партнёр, MCC, город): создание, правка, закрытие | LOYALTY_MERCHANT_READ/WRITE |
/v1/admin/merchants |
Уровни (tier) |
Уровни активной (или указанной) конфигурации, атрибуты и схема профиля уровня, текущий уровень и история переходов клиента, ручное назначение и массовый перевод. Сами уровни заводятся в составе конфигурации программы | LOYALTY_TIER_READ/WRITE |
/v1/tiers, /v1/tiers/{code}/attributes, /v1/customers/{externalId}/tier, /v1/customers/{externalId}/tier/transitions, /v1/customers/tier-bulk, /v1/admin/tier-profile/fields |
| Настройка карточки клиента | Версии настройки (черновики, копия, отличия от активной, активация, удаление), поля, карточки и таблицы, разделы таблиц, настройка столбцов, источники данных; схема, раскладка, справочники выпадающих списков и строки таблиц для отображения карточки | LOYALTY_DICTIONARY_READ/WRITE; активация версии — LOYALTY_CLIENT_PROFILE_ACTIVATE; удаление версии — LOYALTY_CLIENT_PROFILE_DELETE; отображение карточки — LOYALTY_CUSTOMER_READ |
/v1/admin/client-profile/**, /v1/client-profile/schema, /v1/client-profile/structure, /v1/client-profile/dictionaries/{key}, /v1/customers/{externalId}/profile-tables/{groupId}/rows |
Операционный день (business-day) |
Текущий день, закрытие, дневной отчёт (переоткрытие дня убрано из контракта) | LOYALTY_MONITORING_READ (чтение), LOYALTY_BUSINESS_DAY_WRITE (закрытие) |
/v1/business-day, /v1/business-day/close, /{date}/summary |
Справочники (admin-dictionary) |
Реестр НСИ, записи, ЖЦ статусов, журнал изменений, перенос бандлом (dryRun) | LOYALTY_DICTIONARY_READ/WRITE |
/v1/admin/dictionaries, /v1/admin/dictionaries/{key}/..., /export, /import |
Города и торговые точки (admin-city, admin-store) |
Справочники городов (регион, часовой пояс) и торговых точек: создание, правка, архивация города, закрытие точки | LOYALTY_CITY_READ/WRITE, LOYALTY_STORE_READ/WRITE |
/v1/admin/cities, /v1/admin/stores |
Каталог товаров (admin-product-category, admin-product-item) |
Дерево категорий (до трёх уровней) и товары: создание, правка, статус, удаление, импорт из CSV с предварительной проверкой | LOYALTY_PRODUCT_CATALOG_READ/WRITE |
/v1/admin/product-categories, /v1/admin/product-items, .../import, .../import/validate |
Валюты (admin-currency) |
Единый справочник денежных и балльных валют: карточка, курс, история курса, срок жизни баллов | LOYALTY_DICTIONARY_READ/WRITE |
/v1/admin/currencies, /v1/admin/currencies/{code}/rates |
Пары обмена валют (admin-exchange-pair) |
Пары обмена балльных валют: режим курса, направления и их ограничения, сводка, базовый курс направления | LOYALTY_DICTIONARY_READ/WRITE |
/v1/admin/exchange-pairs, /v1/admin/exchange-pairs/summary, /v1/admin/exchange-pairs/base-rate |
| Валюты и курсы (публичные) | Каталог валют и курсов обмена для остальных потребителей | LOYALTY_CURRENCY_READ, LOYALTY_EXCHANGE_RATE_READ |
/v1/currencies, /v1/exchange-rates |
| Валюты баллов (старый контракт) | Совместимость поверх единого справочника валют — не развивается | LOYALTY_DICTIONARY_READ/WRITE |
/v1/admin/point-currencies |
Субсчета баллов (points-subaccount) |
Целевые счета внутри валюты: заведение, ЖЦ, очередь списания, ограничения списания (товары, категории, мерчанты, торговые точки), итоги за период; базовый субсчёт закреплён за валютой | LOYALTY_DICTIONARY_READ/WRITE (чтение списка — также с любым правом ручных операций) |
/v1/points-subaccounts, /v1/points-subaccounts/{id}/... |
Приём команд (intake) |
Асинхронный вход операций через очередь: подача, разбор отложенных/зависших команд | LOYALTY_INTAKE_WRITE/READ |
/v1/intake/commands, /v1/admin/intake/commands/** |
Обмен данными (integration) |
Ленты изменений (клиенты/счета/операции), регламент переливки витрин, журнал прогонов | LOYALTY_EXCHANGE_READ/WRITE |
/v1/admin/data-exchange/feeds/**, /v1/admin/data-exchange/jobs** |
Журнал аудита (admin-audit) |
Изменения и обращения к ПДн, выгрузка CSV потоком, проверка целостности печатей | LOYALTY_MONITORING_READ |
/v1/admin/audit, /export, /integrity |
Мониторинг (monitoring) |
Сводка начислений, списаний и сгорания за произвольный период, аномалии, предстоящее сгорание, аудит ручных начислений, сверка целостности | LOYALTY_MONITORING_READ (запись сверки — LOYALTY_MAINTENANCE_WRITE/INTEGRATION_WRITE) |
/v1/monitoring/..., /v1/admin/reconciliation/... |
Отчёты (reports) |
Пульс программы, баллы, акции за период (итоги, динамика по дням, выгрузка CSV), уровни, реферальная программа | LOYALTY_MONITORING_READ |
/v1/reports/pulse, /points, /promotions, /tiers, /referrals |
Обслуживание (maintenance) |
Ручной запуск сгорания просроченных лотов баллов (в том числе пробный, dryRun=true) и прогона предупреждений о сгорании |
LOYALTY_MAINTENANCE_WRITE |
/v1/maintenance/points/expire, /v1/maintenance/points/expiry-notice |
Исходящие уведомления (admin-notifications) |
Разбор очереди сообщений клиентам: повтор, снятие с основанием; города профиля, по которым не определился пояс клиента | LOYALTY_NOTIFICATION_READ/WRITE; отчёт по городам — LOYALTY_DICTIONARY_READ |
/v1/admin/notifications, /v1/admin/timezones/unmatched-cities |
Личный кабинет (b2c) |
Карта, баланс, уровень, история, доступные акции, партнёрские офферы, бейджи | Клиентский скоуп loyalty.b2c (или LOYALTY_PROFILE_READ для предпросмотра) |
/v1/b2c/me/** |
| Политика и лимиты списания | Общая политика списания и лимиты по разрезам (уровень/валюта/сегмент) | LOYALTY_DICTIONARY_READ/WRITE |
/v1/admin/redemption-policy, /v1/admin/redemption-limits |
| Операционная конфигурация | Параметры контура (часовой пояс программы и т. п.) | LOYALTY_DICTIONARY_READ/WRITE |
/v1/admin/system-config |
Часовой пояс программы (program) |
Действующий пояс программы (IANA) | Любой аутентифицированный пользователь | /v1/program/timezone |
Роли и деление прав по назначению¶
Полная ролевая модель — в руководстве администратора. Здесь отмечены особенности, важные для интеграторов:
- Справочники со своим экраном (теги клиента, метки акций, сегменты клиентов, города,
торговые точки, мерчанты, категории товаров и товары) защищены собственными правами
(
LOYALTY_TAG_*,LOYALTY_PROMOTION_LABEL_*,LOYALTY_SEGMENT_*,LOYALTY_CITY_*,LOYALTY_STORE_*,LOYALTY_MERCHANT_*,LOYALTY_PRODUCT_CATALOG_*) — общиеLOYALTY_DICTIONARY_*их не открывают; generic-ручки/v1/admin/dictionaries/**отвечают на них409 dictionary_own_screen. Исключение — чтение: список сегментов (GET /v1/customer-segments) открыт и правам экранов, где сегмент выбирают (LOYALTY_PROMOTION_READ,LOYALTY_DICTIONARY_READ,LOYALTY_CUSTOMER_READ), список тегов — и праву присвоения теговLOYALTY_CUSTOMER_TAG_WRITE. - Запуск акции (
POST /v1/promotions/{id}/activate,POST /v1/promotions/bulk-activate) требует отдельного праваLOYALTY_PROMOTION_ACTIVATE— всегда, независимо от того, включено ли согласование;LOYALTY_PROMOTION_WRITEзапуск не открывает. В ручке согласованияPOST /v1/promotions/{id}/approvals/{type}действияsubmit/cancelтребуют права записи, аapprove/reject—LOYALTY_PROMOTION_APPROVE; решать по своей же отправке нельзя. - Активация — отдельное право и у конфигурации программы (
LOYALTY_PROGRAM_CONFIG_ACTIVATE), и у версии настройки карточки клиента (LOYALTY_CLIENT_PROFILE_ACTIVATE); право правки его не даёт, и наоборот. Удаление версии настройки карточки — ещё одно отдельное правоLOYALTY_CLIENT_PROFILE_DELETE. - Сохранение конфигурации программы, которое меняет акции уровней (назначение и снятие акций у уровня,
снятие с программы акции, назначенной уровню, удаление уровня с акциями), кроме
LOYALTY_PROGRAM_CONFIG_WRITEтребуетLOYALTY_PROMOTION_WRITE: оно меняет условие «Уровень клиента» в акциях. Без него —403 access_denied. - Приём сегментов из системы кампаний — собственное право
LOYALTY_SEGMENT_INTAKE, а не общее интеграционное. - Присвоение тега клиенту — отдельное право
LOYALTY_CUSTOMER_TAG_WRITE, не совпадающее ни со справочником тегов, ни сLOYALTY_CUSTOMER_WRITE. - Право «Прочее» в справочнике причин ручных операций — отдельное
LOYALTY_OPERATION_REASON_OTHER_WRITE(до 11.09.2026 называлосьLOYALTY_CORRECTION_OTHER_WRITE) поверх права на саму операцию. - Ручка
/v1/customers/operations/batchesи парные ей проверяют право по выбранной операции (operationв запросе), а не единое право ручки:ANY_MANUAL_OPERATION_WRITEна методе только пропускает запрос дальше, окончательное решение — в сервисе. Операции с тегами (TAG_ASSIGN,TAG_REMOVE) требуютLOYALTY_CUSTOMER_TAG_WRITE. - Экран B2C и мобильный кошелёк используют один и тот же составной допуск: клиентский токен со
скоупом
loyalty.b2c(данные только из токена) или сотрудник сLOYALTY_PROFILE_READ(служебный предпросмотр чужого кабинета).
Идемпотентность¶
Денежные операции, изменяющие баланс, требуют заголовка Idempotency-Key. Повторный запрос с тем
же ключом возвращает результат исходной операции и не создаёт дублирующих проводок в леджере;
повтор того же ключа на другой операции — отказ 422 idempotency_key_reused.
Заголовок обязателен, где не отмечено иное
Idempotency-Key объявлен обязательным для операций начисления, списания, ручного
сгорания, резервирования (hold/commit/cancel), перевода, обмена, приёма пакета ручных
операций, события покупки, приёма чека POS, возврата по чеку и его отмены, приёма
начислений/сторно от Promo. Запрос без этого заголовка отклоняется. Для четырёх точек он
необязателен: POST
/v1/customers/{externalId}/anonymize, POST /v1/customers/tier-bulk,
POST /v1/integration/rtflow/accruals, POST /v1/integration/partner/transactions — если
передан, повтор ключа работает так же, как у обязательных.
| Метод и путь | Назначение |
|---|---|
POST /v1/customers/{externalId}/accruals |
Ручное начисление баллов |
POST /v1/customers/{externalId}/corrections |
Корректировка баллов (снятие оператором) |
POST /v1/customers/{externalId}/expirations |
Ручное сгорание баллов клиента |
POST /v1/customers/{externalId}/redemptions |
Прямое списание баллов |
POST /v1/customers/{externalId}/holds |
Резервирование баллов (hold) |
POST /v1/customers/{externalId}/holds/{holdId}/commit |
Списание зарезервированных баллов |
POST /v1/customers/{externalId}/holds/{holdId}/cancel |
Освобождение резерва |
POST /v1/customers/bulk-accruals |
Массовое начисление набору клиентов |
POST /v1/customers/bulk-corrections |
Массовая корректировка набору клиентов |
POST /v1/customers/operations/batches |
Приём пакета ручной операции по файлу/списку (асинхронно) |
POST /v1/top-up |
Пополнение счёта |
POST /v1/withdraw |
Списание со счёта |
POST /v1/transfer |
Перевод между счетами |
POST /v1/exchange |
Обмен валют между счетами клиента |
POST /v1/events/purchase |
Событие покупки с расчётом акций |
POST /v1/integration/pos/receipts |
Приём чека POS |
POST /v1/integration/pos/returns |
Возврат по чеку POS: сторно баллов и уменьшение накопления уровня |
POST /v1/integration/pos/returns/{returnId}/cancel |
Отмена возврата по чеку: баллы начисляются обратно |
POST /v1/integration/promo/accruals |
Приём начисления от CM Ocean Promo |
POST /v1/integration/promo/accruals/reversals |
Приём сторнирования начисления от CM Ocean Promo |
Пример запроса с Idempotency-Key¶
curl -X POST https://<host>/v1/customers/CUST-1001/accruals \
-H "Authorization: Bearer <access_token>" \
-H "Idempotency-Key: a1b2c3d4-5e6f-7a8b-9c0d-1e2f3a4b5c6d" \
-H "Content-Type: application/json" \
-d '{
"pointsMinor": 50000,
"reasonCode": "GOODWILL",
"reference": "TICKET-7788"
}'
Ответ:
Единицы измерения сумм
Денежные и балльные суммы передаются в минорных единицах (поля с суффиксом Minor,
тип int64) — целое число наименьших долей валюты (например, копеек). Точность отображения
задаётся в каталоге валют (GET /v1/currencies/{code}, поле display.precision).
Оптимистическая блокировка (If-Match / ETag)¶
Записи, которые правят несколько администраторов, защищены оптимистической блокировкой по версии:
изменяющая ручка требует заголовок If-Match со значением ETag из ответа на чтение/создание.
Так устроены:
| Что правится | Ручки с If-Match |
|---|---|
| Теги клиента, метки акций | PATCH /v1/tags/{tagId}, POST /v1/tags/{tagId}/merge, PATCH /v1/promotion-labels/{labelId}, POST /v1/promotion-labels/{labelId}/merge |
| Черновик конфигурации программы | PATCH /v1/program-configs/{id} |
| Реестр условий акции (сохраняется целиком) | PUT /v1/admin/promotion-criteria — значение поля revision из GET |
| Черновик версии настройки карточки клиента | Изменяющие ручки полей, карточек и таблиц, разделов и столбцов (/v1/admin/client-profile/fields, /groups, /table-sections) — ревизия версии; сама версия передаётся параметром configurationId |
- Ответ на создание и на изменяющий вызов несёт заголовок
ETag: "<version>". GET /v1/client-profile/schemaиGET /v1/client-profile/structureотдают вETagпару «идентификатор активной версии : ревизия» — по ней видно, что активная версия сменилась между запросами. ВIf-Matchэто значение не передаётся.If-Matchпринимает как строгую ("3"), так и слабую (W/"3") форму значения.- Отсутствие заголовка на изменяющем вызове —
428 version_required; устаревшая версия —409 version_conflict. - Слияние (
merge) несёт версию цели вIf-Match, версию источника — в теле запроса, так как заголовок один, а записей в операции две: у меток тело{sourceId, sourceVersion}, у тегов —{sourceTagId, sourceVersion}.
curl -X PATCH https://<host>/v1/tags/42 \
-H "Authorization: Bearer <access_token>" \
-H "If-Match: \"3\"" \
-H "Content-Type: application/json" \
-d '{"value": "vip-2026"}'
Постраничные ответы¶
Списочные эндпоинты принимают параметры page (отсчёт с нуля), size и sort (в формате
property,asc|desc) и возвращают конверт с метаданными:
total — на всех постраничных списках
Ранее часть списков мониторинга (аномалии, сгорающие лоты, аудит ручных начислений) отдавала
голый массив без общего числа строк, и усечённая выдача была неотличима от полной. Сейчас
все постраничные списки продукта возвращают конверт {items, page, size, total} — в том
числе история переходов уровня клиента (GET /v1/customers/{externalId}/tier/transitions), —
и полагаться на длину items как на полное число записей нельзя. Массивом без страниц
отдаются только короткие перечни настроек: уровни, поля и группы схемы карточки, версии
настройки карточки, авторы для фильтров и т. п.
Поле сортировки вне объявленного для конкретного списка allowlist по умолчанию игнорируется молча
(не 400 и не 500) — контракт называет единственное поддерживаемое поле там, где сортировка
ограничена. Исключение — список приглашённых клиентов
(GET /v1/customers/{externalId}/referrals): там недопустимое поле сортировки отклоняется
400 referral_sort_invalid.
Аутентификация¶
API защищён как OAuth2 resource server поверх Keycloak. Каждый запрос должен содержать
действительный JWT в заголовке Authorization: Bearer <token>. Доступ к операционным эндпоинтам
ограничен ролями LOYALTY_* по принципу deny-by-default; клиентский контур /v1/b2c/** — по
отдельной security-цепочке со скоупом loyalty.b2c. Подробности — в разделе документации по
безопасности и в ролевой модели.
Ограничение частоты¶
Часть эндпоинтов защищена ограничителем частоты запросов (GCRA, ключ — субъект токена или IP).
Отказ — 429 с телом problem+json, полем retryAfterSeconds и заголовком Retry-After;
конкретные коды (resolve_rate_limited, bulk_rate_limited и т. д.) — в разделе «Ограничение
частоты» реестра кодов ошибок.
Формат ошибок¶
При ошибке сервис возвращает RFC 7807 (application/problem+json) со стабильным полем code и
traceId. Полный реестр кодов, их HTTP-статусы и условия возникновения — на отдельной странице
«Коды ошибок».
| HTTP-статус | Типовое значение |
|---|---|
400 Bad Request |
Нарушение правил полей тела или параметров (validation_failed, поле — в начале detail) либо нечитаемое тело (bad_request) |
401 Unauthorized |
Отсутствует или недействителен JWT |
402 Payment Required |
Недостаточно средств/баллов для операции |
403 Forbidden |
У субъекта нет требуемой роли LOYALTY_* (у решения по согласованию акции — свои коды approval_forbidden, approval_not_assigned) |
404 Not Found |
Ресурс (клиент, акция, счёт, запись справочника) не найден |
409 Conflict |
Конфликт состояния (недопустимый переход статуса, версия записи устарела и т. п.) |
413 Payload Too Large |
Файл загрузки или пачка участников сегмента больше допустимого |
415 Unsupported Media Type |
Неподдерживаемый Content-Type либо бинарный файл вместо текстового CSV |
422 Unprocessable Entity |
Данные синтаксически верны, но нарушают доменное правило |
428 Precondition Required |
Изменение версионируемой записи без заголовка If-Match |
429 Too Many Requests |
Превышен лимит частоты запросов |
500 Internal Server Error |
Непредвиденная ошибка (internal_error) или рассогласование данных, правленных в обход приложения (свой стабильный код) |
503 Service Unavailable |
Недоступна внешняя система (реестр клиентов MDM, транспорт пакетов) |
Существенные изменения контракта в 26.3.0¶
BREAKING — сверьте интеграции перед обновлением
- Ошибки валидации —
400 validation_failed. Нарушение правил полей тела и параметров отдаётся с кодомvalidation_failed, нарушения перечислены вdetailкакполе: сообщение(fieldKey: must not be blank; label: must not be blank), путь вложенного поля —criteria[0].mode.bad_requestостаётся только для тела или значения, которое не удалось разобрать. Касается и интеграций: POS (/v1/integration/pos/receipts), Promo (/v1/integration/promo/accruals,/reversals), RT Flow (/v1/integration/rtflow/*), лент изменений (limitвне диапазона). - Приоритет акции обязателен.
POST/PUT /v1/promotionsбезpriority—400 validation_failed; значение по умолчанию100больше не подставляется. - Условия акции — список
criteriaвместоscope. ВPOST/PUT /v1/promotions, ответе и файле переноса условие — запись{code, mode, values | range}с режимомINCLUDE/EXCLUDE. Полеscopeудалено, границы суммы чека изparams.minCheckMinor/maxCheckMinorне читаются, кодinvalid_check_rangeзаменёнpromotion_criterion_range_invalid. ВPUTотсутствующийcriteriaсохранённые условия не трогает, снять их — явнымcriteria: []. Файлы переноса со старымscopeимпортируются с конвертацией. - Условие «Уровень клиента» — пары
{configId, code}.params.conditions.client.level(строка) заменено спискомparams.conditions.client.levels; прежний ключ —400 validation_failed, несуществующая конфигурация или уровень —422 promotion_level_unknown. - Награда механики обязательна, потолок бонуса — только поле акции. Акция на «Множителе»,
«Подарке» или «Начислении за единицу» без
multiplier,giftMinorилиpointsPerUnit—422 promotion_param_required; параметрparams.maxBonusMinorбольше не читается, потолок — полеmaxBonusMinor. Запуск акции на механике без параметров —409 promotion_mechanic_not_configured. - Запуск акции — отдельное право.
POST /v1/promotions/{id}/activateиPOST /v1/promotions/bulk-activateтребуютLOYALTY_PROMOTION_ACTIVATE; без него —403 access_denied, даже если согласование выключено. - Код точки в покупке обязателен.
externalStoreCodeвPOST /v1/events/purchaseиstoreCodeвPOST /v1/integration/pos/receipts; для покупки без физической точки передаётся код виртуальной точки из справочника торговых точек. - Сегменты клиента — только из заливки системы кампаний. Поле
segmentsвPOST /v1/events/purchaseигнорируется (помеченоdeprecated), полеsegmentsудалено из профиля клиента (identityкарточки, ответ записи профиля) — сегменты клиента отдаётGET /v1/customers/{externalId}/segments. Вerrors[]отказаpromotion_audience_unresolvedпоявилась ссылкаkind: SEGMENTс кодом сегмента вvalueиid: null. - Партнёр без
merchantIds/mcc. Поля убраны изPOST/PUT /v1/partners; мерчанты ведутся в справочнике/v1/admin/merchants. - Уровни — только в составе конфигурации программы.
PUT/DELETE /v1/tiers/{code}удалены вместе с кодомtier_ordinal_taken(порядок уровней сервер выводит из порогов), уровни пишутся черезPOST/PATCH /v1/program-configs;GET /v1/tiersпринимает необязательныйconfigId. У уровня нет поляmetric(метрика перехода —tierMetricконфигурации), появился порогentryCount.GET /v1/customers/{externalId}/tier/transitionsотдаёт конверт{items, page, size, total}вместо массива, параметрlimitудалён. - Базовый субсчёт вместо основного. Признак
isBaseвместоisDefault, операцияPOST /v1/points-subaccounts/{id}/defaultудалена, отказ закрытия базового субсчёта —409 subaccount_base_cannot_closeвместоsubaccount_default_cannot_close. Срок субсчётаexpiryDate(дата) заменён наexpiryAt(момент,date-time). - Атрибуты карточки клиента — списки значений.
PUT /v1/customers/{externalId}/attributesиattributesвGET /v1/customers/{externalId}/card— словарь «ключ → список строк». Новое значение ручного поля принимается только в формате его типа (иначе400 validation_failed); значение поля, которого нет в схеме, преднастроенного или с колонкой источника, архивного или скрытого —422(unknown_attribute,system_field_immutable,field_archived,field_hidden). Очистка пустым списком проходит всегда. - Схема полей карточки клиента версионируется. Ручки полей, карточек и таблиц, разделов и
столбцов (
/v1/admin/client-profile/fields,/groups,/table-sections) требуют параметрconfigurationId— версию настройки, изменяющие — ещё иIf-Match.fieldType: LISTотклоняется (выпадающий список —inputSource: DROPDOWN+refDict),optionsJsonубран из запроса, карточка поляgroupобязательна. Ключ нового поля проверяется, а не исправляется (^[a-z_][a-z0-9_]*$, до 64 символов), и не переименовывается (422 field_key_immutable); удаляется только поле, не заполненное ни у одного клиента (409 field_has_values). - Слияние клиентов отвечает правдой.
POST /v1/customers/{externalId}/mergeтам, где раньше был200, отвечает404 customer_not_found(источник удалён параллельно) или409 version_conflict(источник уже слит в другого клиента); повтор слияния в того же клиента — по-прежнему200. - Тело акции — полная замена. Отсутствующий
participationLimitвPUT /v1/promotions/{id}снимает лимит участий (как и отсутствующийbudgetMinorснимает бюджет) — частичныйPUTневозможен. - Правка приостановленной акции зависит от применений. Пауза с хотя бы одним применением
отклоняется
409 promotion_not_editable(так же —PUT/DELETE /v1/promotions/{id}/participation-limit); на паузе правится только неприменявшаяся акция. Черновик и запланированная акция правятся всегда, активная, завершённая и архивная — нет. - Бюджет акции — деньги, а не баллы.
budgetMinorзадаётся в минорных единицах базовой денежной валюты; каждое начисление по акции пересчитывается в деньги по курсу валюты баллов на момент начисления, уже израсходованное при смене курса не переоценивается. Тип поля не изменился. - У резерва баллов (
hold) всегда есть срок.expireAtбез значения раньше означал бессрочный резерв; теперь применяется дефолтredemption.hold-ttl(по умолчаниюPT30M) — резерв, не подтверждённый и не снятый в срок, автоматически истекает. - Причина ручных операций — код справочника, а не свободный текст. У начисления и
перевода уровня поле
reasonубрано в пользуreasonCode+ необязательногоcomment(обязателен при причине «Прочее»). - Списки мониторинга всегда несут
total. Аномалии, сгорающие лоты, аудит ручных начислений переведены на общий конверт{items, page, size, total}. - Статусная модель акции изменена. Статус
ARCHIVEDубран из перечисления, архив стал отдельным обратимым признакомarchived; добавлен статусSCHEDULED. Фильтрstatusкаталога акций стал множественным (список значений вместо одного);createdBy/updatedByстали объектами{id, displayName}вместо строк; массовые запросы каталога акций (bulk-*) принимают не больше 500 идентификаторов за раз. - Каталог клиентов: фильтр по уровню переименован
tierCode→tier, стал списком кодов; тумблер «Показать архивные» возвращает всю базу с архивными первым блоком. GET /v1/currencies— в ответе появилсяkind(MONEY/POINTS),display.symbolможет бытьnull; неизвестный код валюты —404 currency_not_foundвместо500.- Старый
/v1/admin/point-currenciesработает поверх единого справочника валют.colorиsortOrderне сохраняются; удаление включённой валюты —409 currency_enabled, валюты со ссылками —409 currency_in_use. - Схема ответа журнала аудита переименована. В
openapi.ymlответGET /v1/admin/auditописан схемойAuditEntryViewвместоAuditView(под именемAuditViewтеперь — история изменений справочника). Клиенты, сгенерированные по спецификации, нужно перегенерировать. - Недоступность реестра клиентов (MDM) отдаётся как
503 mdm_unavailable, а не404 customer_not_found— интеграции обязаны различать эти два случая. - Переоткрытие операционного дня убрано из контракта.
POST /v1/business-day/{date}/reopenи кодbusiness_day_not_closedудалены; «открыт ровно один день» — инвариант базы. - Массовые операции ручных начислений — единый ответ
BulkResult.bulk-accruals,bulk-corrections,tier-bulkотвечают формой{batchId, status, total, succeeded[], errors[]}; прежние поля (succeeded[{transactionId,...}],failed[],rejected[],assigned[]) убраны. Полеsourceубрано и из тел запроса этих трёх точек — источник операции сервер определяет сам.
Полная спецификация¶
Полный перечень эндпоинтов, схем запросов/ответов и перечислений приведён в поставляемой
OpenAPI-спецификации openapi.yml (OpenAPI 3.1). Импортируйте её в Swagger UI или Postman
для интерактивного изучения и генерации клиентов.