Перейти к содержанию

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"
  }'

Ответ:

{
  "transactionId": 904512,
  "balanceMinor": 1250000
}

Единицы измерения сумм

Денежные и балльные суммы передаются в минорных единицах (поля с суффиксом 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) и возвращают конверт с метаданными:

{
  "items": [],
  "page": 0,
  "size": 20,
  "total": 0
}

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 для интерактивного изучения и генерации клиентов.