Баланс и операции¶
Раздел описывает работу с балльным счётом клиента: чтение баланса и истории операций, начисление,
двухфазное и прямое списание, лимиты списания. Все операции выполняются над счётом клиента, который
идентифицируется внешним идентификатором externalId (идентификатор профиля во внешней
мастер-системе).
Модуль построен на принципе двойной бухгалтерии: каждая операция формирует проводки в балльном леджере, поэтому баланс всегда сводим, а история операций — неизменна и прослеживаема.
Связанные разделы
- Ручные начисления, корректировки и перевод уровня оператором, в том числе пакетом по списку или файлу, — Ручные операции.
- Целевые счета внутри карты клиента и очередь списания — Субсчета баллов.
- Сгорание баллов по сроку и вручную — Сгорание баллов.
Баланс: три величины¶
Баланс клиента описывается тремя величинами. Все суммы передаются в минорных единицах (целое число; одна минорная единица — наименьший неделимый балл).
| Величина | Поле ответа | Смысл |
|---|---|---|
| Баланс | balanceMinor |
Полный остаток баллов на счёте по данным леджера |
| Удержано (в резерве) | heldMinor |
Баллы, зарезервированные активными удержаниями (hold) с неистёкшим сроком |
| Доступно | availableMinor |
Баллы, которые может взять новая операция — резерв, списание, корректировка — не лишив подтверждения ни один активный резерв |
Как считается доступный остаток¶
Доступное считается по каждому субсчёту, итог — сумма по субсчетам:
- Баллы с наступившим сроком — баллы, срок которых уже наступил, но прогон сгорания их ещё не сжёг. На счёте они лежат, но новой операции уже не достаются: иначе клиенту показали бы сумму, которую касса откажется списать.
- Покрытое — часть активных резервов, которую подтвердят как раз эти баллы. Резерв может взять партию баллов, если её срок не раньше момента создания резерва; такую часть не вычитают второй раз.
- Резерв, созданный уже после срока партии, подтверждается только действующими баллами и вычитается целиком.
Пока все резервы созданы до сроков партий, результат совпадает с «баланс минус большее из резервов и баллов с наступившим сроком». Доступное не бывает отрицательным.
Пример
На счёте 700 действующих баллов и 300 с наступившим, но не сожжённым сроком. После срока касса
резервирует 400. Доступно — 300: 1 000 − 400 − 300 + 0. Резерв на 600 будет отклонён
402 not_enough_funds, а не принят с последующим отказом одного из подтверждений.
По той же формуле работают карточка клиента, личный кабинет, ответы резерва и списания, корректировка оператора и проверка пакета ручных операций (26.3.0). Прогон сгорания удерживает ровно те партии, которыми подтвердятся резервы, поэтому доступное после прогона не меняется.
Чтение баланса¶
GET /v1/customers/{externalId}/balance — роль LOYALTY_ACCOUNT_READ.
Баланс клиента — это не одна сумма, а набор субсчетов. Ответ содержит итог по валюте баллов и разбивку по субсчетам; поля итога сохранены в прежнем виде, поэтому потребители, которые читают только итог (касса, сайт, мобильное приложение, кабинет), продолжают работать без изменений.
{
"currency": "PTS",
"balanceMinor": 150000,
"heldMinor": 20000,
"availableMinor": 130000,
"nearestExpiryAt": "2026-12-31T21:00:00Z",
"nearestExpiryAmountMinor": 5000,
"subaccounts": [
{ "subaccountId": 1, "code": "BASE", "name": "Основной",
"balanceMinor": 120000, "heldMinor": 20000, "availableMinor": 100000,
"nearestExpiryAt": "2026-12-31T21:00:00Z" },
{ "subaccountId": 4, "code": "WELCOME", "name": "Приветственные",
"balanceMinor": 30000, "heldMinor": 0, "availableMinor": 30000,
"nearestExpiryAt": null }
]
}
| Поле разбивки | Смысл |
|---|---|
subaccountId, code, name |
Субсчёт |
balanceMinor, heldMinor, availableMinor |
Три величины баланса на этом субсчёте |
nearestExpiryAt |
Ближайший срок сгорания баллов субсчёта; пусто — сгорающих баллов нет |
Поля итога nearestExpiryAt и nearestExpiryAmountMinor — ближайшее сгорание по клиенту: дата —
ближайший срок партии баллов с остатком (в том числе уже наступивший, если прогон сгорания ещё не
прошёл), сумма — все партии с той же календарной датой в часовом поясе программы по всем
субсчетам, без вычета резерва.
Та же разбивка приходит в карточке клиента (GET /v1/customers/{externalId}/card, блок
loyalty.subaccounts) — одним ответом с итогом.
Счета клиента во всех включённых валютах (26.3.0)
У каждого активного клиента есть счёт в каждой включённой валюте — балльной и денежной — на её
базовом субсчёте. Счета открываются при заведении клиента (форма, API, импорт, первая запись
профиля), а при создании или включении валюты — фоновой задачей для всех активных клиентов.
Заблокированным клиентам фоновая задача счетов не открывает — они открываются при разблокировке.
Флаг preCreateAccounts при создании клиента больше не нужен: он принимается и игнорируется.
Счёт на другом субсчёте по-прежнему возникает первой проводкой на этот субсчёт; открыть счёт
явно можно командой POST /v1/customers/{externalId}/accounts (роль LOYALTY_ACCOUNT_WRITE).
Запрос баланса по неизвестному клиенту вернёт ошибку, а не создаст счёт.
Баланс в карточке клиента¶
В карточке клиента на вкладке «Счета и балансы» сверху вниз показываются:
- Плитки баланса: «Доступно баллов» — основной показатель, «Всего баллов» и «В резерве» (только если резерв больше нуля).
- Доступное по типам баллов — если у клиента два субсчёта и больше, под первым рядом плиток — плитка «Доступно — {название субсчёта}» на каждый субсчёт, в порядке очереди списания. В сумме они дают «Доступно баллов».
- Уровень — текущий уровень (с пометкой «Назначен вручную» при ручном назначении), «Множитель начисления» и прогресс до следующего уровня, см. Уровни.
- «Разбивка по субсчетам» — название и код каждого субсчёта и полный остаток на нём. Порядок строк — очередь списания (в этом порядке баллы будут потрачены), а не величина остатка. Если разбивки нет, секция не показывается.
- «Счета» — счета клиента во всех включённых валютах, балльных и денежных: номер счёта, валюта, статус («Активен», «Неактивен», «Приостановлен») и суммы «Баланс», «Начислено», «Списано». Счёт, который сервер ещё не открыл, показывается с прочерком вместо номера и нулями.
Суммы показываются с точностью своей валюты из справочника валют: плитки
и разбивка — в валюте баллов клиента, строка счёта — в своей валюте. Без роли
LOYALTY_CURRENCY_READ справочник недоступен, и суммы выводятся с двумя знаками после запятой.
Сроки сгорания на этой вкладке не показываются — для них есть вкладка «Сроки сгорания», см.
Сгорание баллов.
GET /v1/customers/{externalId}/accounts (роль LOYALTY_ACCOUNT_READ) отдаёт по каждому счёту
сводку summary: balanceMinor, creditMinor, debitMinor, а также heldMinor («В резерве») и
expiredMinor («Сгорело всего» — ушло на счёт сгорания за всё время; null, если счёт сгорания не
отделён от счетов списания и начислений). Включённая валюта без открытого счёта приходит строкой с
нулями и accountNumber: null.
История операций клиента¶
GET /v1/customers/{externalId}/operations — роль LOYALTY_MONITORING_READ. Ответ — страница
{items, page, size, total}.
Вкладка «Бонусные операции»¶
В карточке клиента история показывается на вкладке «Бонусные операции»: колонки «ID транзакции», «Дата», «Тип операции», «Сумма», «Источник», «Причина», «Оператор». Фильтры — в заголовках колонок, фильтрует сервер по всей истории клиента; смена фильтра возвращает на первую страницу.
| Колонка | Фильтр |
|---|---|
| Дата | Период «с — по»; любая граница может быть пустой, обе включительно (сутки — в часовом поясе программы) |
| Тип операции | «Начисление», «Списание», «Корректировка», «Сторно» — несколько значений по «ИЛИ» |
| Сумма | «от — до» в баллах; сравнивается без знака: 500 — 500 находит и начисление, и списание на 500 |
| Источник | «Покупка в магазине», «Акция», «Промокод», «Ручная операция», «Оплата баллами», «Сгорание по сроку», «Сгорание оператором», «Реферальная программа», «Сценарий RT Flow», «Партнёрский оффер» — несколько значений по «ИЛИ» |
Сортировка — только по дате: новые сверху или старые сверху. Знак и цвет суммы задаёт тип операции: начисление — «+», списание, корректировка, сгорание и сторно — «−». Сторно — это отмена начисления (возврат покупки, отзыв промокода), баллы при нём снимаются. Фильтры и сортировка вкладки не сохраняются между сеансами.
Применения акций отдельно показывает вкладка «Участие в акциях», см. Карточка клиента.
Параметры запроса¶
| Параметр | Назначение |
|---|---|
page, size |
Номер страницы (с 0) и размер (по умолчанию 20) |
sort |
Сортировка по дате: createdAt,desc (по умолчанию) или createdAt,asc. Единственное поддерживаемое поле — createdAt; прочие поля сортировки игнорируются без ошибки |
createdFrom, createdTo |
Период по моменту операции, границы включительно; любую можно не передавать |
type |
Тип операции: ACCRUAL, REDEMPTION, CORRECTION, REVERSAL. Несколько значений — по «ИЛИ» |
amountFromMinor, amountToMinor |
Сумма в минорных единицах, без знака, границы включительно |
source |
Источник операции (см. ниже). Несколько значений — по «ИЛИ» |
promotionId |
Версия сработавшей акции |
hasPromotion |
true — только применения акций (источник PROMOTION); false — вся остальная история; не передан — история целиком |
mechanicCode |
Отбор по механике сработавшей акции. Несколько значений — по «ИЛИ» |
Правила отбора:
- Все параметры необязательны и складываются по «И»; списки передаются повтором параметра или через запятую.
totalсчитается по тому же отбору, что и строки, — счётчик совпадает с содержимым выдачи.- Отбор идёт по всей истории клиента на сервере, а не по загруженной странице.
- Неизвестное значение
type,sourceилиmechanicCodeдаёт пустую выдачу, а не ошибку; пустое значение — как отсутствие параметра. Перевёрнутый диапазон периода или суммы — пустая страница. - Сторно начисления по акции наследует поля акции (и подходит под
promotionId), но участием в акции не считается: подhasPromotion=trueне попадает. - Строки без акции под фильтр
mechanicCodeне подходят, поэтому он осмыслен вместе сhasPromotion=true. - При одинаковом времени записи (операции одной транзакции) порядок доопределяется идентификатором операции — страницы не теряют и не дублируют строки.
Поля строки истории¶
| Поле | Смысл |
|---|---|
operationId |
Идентификатор операции |
createdAt |
Момент операции |
type |
Тип: ACCRUAL «Начисление», REDEMPTION «Списание», CORRECTION «Корректировка», REVERSAL «Сторно» |
amountMinor |
Сумма в минорных единицах |
source |
Источник: PURCHASE — покупка, PROMOTION — акция, PROMOCODE — промокод, MANUAL — ручная операция, REDEMPTION — оплата баллами, EXPIRY — плановое сгорание, MANUAL_EXPIRY — сгорание оператором, REFERRAL — реферальная программа, RT_FLOW — сценарий RT Flow, PARTNER — партнёрский оффер |
reason, reasonCode, comment |
Подпись причины, код причины из справочника «Причины операций» и комментарий оператора (у ручных операций) |
operator |
Оператор ручной операции |
promotionId, promotionName, promotionMechanicCode |
Сработавшая акция: версия, применившаяся к покупке, её название и механика. У операций без акции пусты |
subaccount |
Субсчёт операции {id, code, name} |
accountNumber |
Счёт клиента по проводке операции; у операции по нескольким счетам — счёт первой проводки, без проводки — null. В интерфейсе пока не выводится |
Сгорание в истории
Плановое сгорание баллов по сроку попадает в историю за прогон записью на каждый субсчёт, по
которому было сгорание (источник EXPIRY «Сгорание по сроку»). Ручное сгорание, запущенное
оператором, записывается с источником MANUAL_EXPIRY «Сгорание оператором», причиной и
оператором. Тип у обеих записей — REDEMPTION «Списание»: отличить сгорание от траты баллов
можно по источнику, в том числе фильтром «Источник». Подробнее — Сгорание баллов.
Начисление баллов¶
POST /v1/customers/{externalId}/accruals — роль LOYALTY_ACCRUAL_WRITE, обязателен заголовок
Idempotency-Key.
Это одиночное ручное начисление оператора. Интеграционные начисления (RT Flow, модуль Promo, очередь команд) идут своими точками приёма и в этом разделе не описываются.
| Поле | Тип | Обязательность | Описание |
|---|---|---|---|
pointsMinor |
целое > 0 | да | Сумма начисления в минорных единицах |
reasonCode |
строка | да | Код причины из справочника «Причины операций» (активная запись) |
comment |
строка ≤ 500 | при OTHER |
Комментарий оператора; обязателен при причине «Прочее» |
reference |
строка | да | Внешняя ссылка операции (например, номер документа-основания) |
subaccountCode |
строка | нет | Субсчёт; не указан — базовый субсчёт валюты. Субсчёт должен быть активен |
expireAt |
дата-время | нет | Срок сгорания лота; не указан — первый заданный по цепочке: свой срок субсчёта → срок уровня клиента → базовый срок валюты; не задан нигде — баллы не сгорают (см. Сгорание баллов) |
curl -X POST https://<host>/v1/customers/CUST-42/accruals \
-H "Authorization: Bearer <token>" \
-H "Idempotency-Key: 8f1c0b2e-..." \
-H "Content-Type: application/json" \
-d '{"pointsMinor": 50000, "reasonCode": "COMPENSATION", "reference": "DOC-1001", "subaccountCode": "BASE"}'
Причина — только из справочника (26.3.0)
Поле свободного текста reason у ручного начисления убрано: причина задаётся кодом
reasonCode и необязательным комментарием comment. Правила причины (права на «Прочее»,
обязательный комментарий) и коды ошибок описаны в разделе
Ручные операции.
Начисление отклоняется:
- заблокированному клиенту —
422 customer_blocked; - на неактивный субсчёт —
409 subaccount_not_active; - в выключенную валюту баллов —
422 currency_disabled(см. Справочник валют).
Двухфазное списание (hold → commit/cancel)¶
Двухфазное списание разделяет резервирование и фактическое списание баллов. Это модель авторизации/захвата (auth/capture), удобная для кассовых сценариев: сначала баллы резервируются (hold), затем — по факту завершения покупки — либо списываются (commit), либо резерв освобождается (cancel).
sequenceDiagram
participant POS as Касса/корзина
participant L as Loyalty
POS->>L: POST /holds (резерв, срок жизни)
L-->>POS: holdId, availableMinor, parts
alt покупка завершена до срока
POS->>L: POST /holds/{holdId}/commit
L-->>POS: transactionId, availableMinor
else покупка отменена
POS->>L: POST /holds/{holdId}/cancel
L-->>POS: статус, availableMinor
else срок резерва истёк
Note over L: резерв перестаёт держать баллы,<br/>подтвердить его нельзя
end
Все три команды требуют роль LOYALTY_REDEMPTION_WRITE и заголовок Idempotency-Key.
Резерв (hold)¶
POST /v1/customers/{externalId}/holds
Уменьшает доступный остаток, не затрагивая полный баланс.
| Поле | Тип | Обязательность | Описание |
|---|---|---|---|
amountMinor |
целое > 0 | да | Сумма резерва в минорных единицах |
reference |
строка | да | Внешняя ссылка операции |
purchaseAmountMinor |
целое | нет | Сумма чека — нужна для процентных лимитов списания |
items |
массив | нет | Позиции чека {sku, category, amountMinor} (до 1000) — нужны субсчетам с ограничением «на что» (товары, категории), см. ниже |
storeCode, merchantCode |
строка | нет | Место покупки: код торговой точки и код мерчанта — нужны субсчетам с ограничением «где» |
expireAt |
дата-время | нет | Срок жизни резерва; не указан — действует срок по умолчанию |
{
"holdId": 5512,
"availableMinor": 110000,
"parts": [ { "subaccountId": 1, "code": "BASE", "amountMinor": 20000 } ]
}
parts — разбивка резерва по субсчетам в порядке очереди списания. Разбивка фиксируется в момент
создания резерва, и подтверждение списывает именно по ней, даже если очередь субсчетов успела
измениться.
BREAKING (26.3.0): у резерва всегда есть срок
Если expireAt не передан, резерв получает срок по умолчанию — операционный параметр
redemption.hold-ttl (по умолчанию 30 минут, меняется в администрировании без перезапуска).
Бессрочных резервов больше нет: раньше резерв без срока держал баллы клиента вечно, если касса не
дошла ни до подтверждения, ни до отмены.
Интеграция, которая создаёт резерв без expireAt и подтверждает его позже срока по умолчанию,
получит отказ. Явно переданный expireAt по-прежнему не переопределяется.
Срок жизни резерва¶
- Как только срок резерва вышел, баллы снова доступны клиенту — независимо от того, успел ли фоновый сборщик отметить резерв.
- Подтвердить просроченный резерв нельзя: проверка срока выполняется в самой операции подтверждения.
- Снять (cancel) просроченный резерв можно: вызов завершается успешно и возвращает статус
EXPIRED— резерв и так уже освобождён. - Фоновый сборщик переводит активные резервы с вышедшим сроком в статус
EXPIRED, чтобы состояние было видно. Расписание —LOYALTY_REDEMPTION_HOLD_EXPIRY_CRON(по умолчанию выключен; на корректность списания не влияет).
Подтверждение (commit)¶
POST /v1/customers/{externalId}/holds/{holdId}/commit
Списывает зарезервированные баллы по зафиксированной разбивке: полный баланс уменьшается.
Резерв не в активном состоянии (подтверждён, отменён, истёк) — 409 hold_not_active; неизвестный
резерв — 404 hold_not_found.
Отмена (cancel)¶
POST /v1/customers/{externalId}/holds/{holdId}/cancel
Освобождает резерв без списания.
Прямое списание (redeem)¶
POST /v1/customers/{externalId}/redemptions — роль LOYALTY_REDEMPTION_WRITE, обязателен
заголовок Idempotency-Key.
| Поле | Тип | Обязательность | Описание |
|---|---|---|---|
amountMinor |
целое > 0 | да | Сумма списания в минорных единицах |
reference |
строка | да | Внешняя ссылка операции |
purchaseAmountMinor |
целое | нет | Сумма чека — для процентных лимитов списания |
items, storeCode, merchantCode |
нет | Позиции чека и место покупки — как у резерва | |
reason |
строка | нет | Технический комментарий источника |
{
"transactionId": 90945,
"balanceMinor": 80000,
"availableMinor": 60000,
"parts": [
{ "subaccountId": 4, "code": "WELCOME", "amountMinor": 30000 },
{ "subaccountId": 1, "code": "BASE", "amountMinor": 40000 }
]
}
Списание идёт по очереди субсчетов и может затронуть несколько субсчетов; parts показывает, с
какого субсчёта сколько списано. Сторно возвращает баллы на те же субсчета. Подробнее —
Субсчета баллов.
Нехватка баллов
Если доступных баллов не хватает суммарно по всем субсчетам, списание отклоняется целиком —
402 not_enough_funds; частичного списания нет. Баллы под активными резервами не считаются
доступными.
Ограничения субсчетов при списании¶
У субсчёта могут быть ограничения области списания (26.3.0), см. Субсчета баллов:
- «на что» — товары и категории: такой субсчёт отдаёт не больше стоимости подходящих ему позиций
items, пересчитанной в баллы по курсу валюты баллов (с округлением вниз); остальное списывается со следующих субсчетов по очереди. Безitemsтакие субсчета в списании не участвуют. Категория подходит, если она есть среди категорий позиции (у товара каталога — на любом из трёх уровней); - «где» — мерчанты и торговые точки: субсчёт участвует, если точка запроса есть среди точек правила или мерчант запроса — среди мерчантов правила. Запрос без места такой субсчёт пропускает.
Ограничения «на что» и «где» действуют вместе. Позицию, подходящую двум субсчетам, расходуют по очереди; субсчета без ограничений её стоимость не расходуют. Резерв фиксирует разбивку в момент создания. Сгорание, корректировки и обмен ограничения не проверяют.
Лимиты списания¶
Перед списанием и резервом сумма проверяется по правилам списания клиента:
- правила активной конфигурации программы (26.3.0) — область списания, минимум и максимум за покупку (в том числе свой максимум на каждом уровне), минимальный баланс, кратность; см. Конфигурации программы. У конфигурации без своих правил действует общая политика списания;
- частные лимиты по разрезам — уровень, сегмент, валюта баллов — сильнее правил конфигурации. Общая политика и разрезы настраиваются в разделе «Настройка ПЛ», блоки «Ограничения на списание баллов» и «Лимиты по разрезам», см. Операционная конфигурация.
| Тип границы | Как считается |
|---|---|
FIX |
Абсолютное значение в минорных единицах |
PERCENT |
Процент от суммы чека purchaseAmountMinor; при области «товары» или «категории» — от суммы подходящих позиций items. Если сумма чека не передана, процентная граница общей политики не применяется |
Проверки идут в порядке: минимальный баланс, область, минимум и максимум, кратность. Нарушение — отказ, а не урезание суммы:
| Код | Когда |
|---|---|
redemption_below_min_balance |
Доступных баллов меньше минимального баланса для списания — тратить нельзя даже меньшую сумму |
redemption_scope_not_eligible |
Покупка не подходит под область списания |
redemption_items_required |
Область «товары» или «категории», а позиции чека items не переданы |
redemption_purchase_amount_required |
Область «покупки от суммы», а сумма чека purchaseAmountMinor не передана |
redemption_below_min / redemption_above_max |
Сумма меньше минимума или больше максимума |
redemption_not_multiple |
Сумма не кратна заданной кратности |
Округление границ — внутрь допустимого промежутка (26.3.0)
Дробная граница округляется так, чтобы не расширять разрешённое: максимум — вниз, минимум —
вверх. Например, потолок «не больше 30 % чека» на чеке в 15 даёт 4,5 → 4 (раньше 5, то есть
33 %), порог «не меньше 10 % чека» на чеке в 14 даёт 1,4 → 2 (раньше 1). То же правило — для
границы FIX. На значениях по умолчанию (минимум 0, максимум 100 %) поведение не меняется.
Лимит с нераспознанным типом границы больше не отключается молча — списание по нему отклоняется.
Перевод и обмен¶
POST /v1/transfer переносит сумму между двумя счетами (в т. ч. между субсчетами одного клиента
или между разными клиентами), POST /v1/exchange — пересчитывает и переносит сумму между счетами в
разных валютах по действующему курсу; оба — на уровне счетов, а не под
/v1/customers/{externalId}/..., и оба требуют роль LOYALTY_OPERATION_WRITE и заголовок
Idempotency-Key.
Пересчёт суммы по курсу обмена округляется один раз, вниз и сразу в точности целевой валюты (26.3.0). Раньше при переходе к более грубой точности результат мог округлиться вверх (10,00 по курсу 4 → 3 вместо 2), а при исходной точности грубее целевой терялись разряды (100 по курсу 3 → 33,00 вместо 33,33).
Идемпотентность операций¶
Все операции, изменяющие баланс — начисление, резерв, подтверждение, отмена, прямое списание,
корректировка и ручное сгорание — идемпотентны. Каждый такой запрос обязан содержать заголовок
Idempotency-Key.
- При первом обращении с данным ключом операция выполняется, а её результат сохраняется.
- Повторное обращение с тем же ключом не выполняет операцию заново, а возвращает ранее сохранённый результат.
Это защищает от двойного начисления или двойного списания при повторах запроса (сетевые ретраи, таймауты, повторная отправка кассой).
Уникальность ключа
Idempotency-Key должен быть уникален для каждой логически отдельной операции.
Используйте новый ключ (например, UUID) на каждую новую транзакцию и повторяйте тот же
ключ только при ретрае именно этого запроса.
Сводка эндпоинтов¶
| Операция | Метод и путь | Роль | Идемпотентность |
|---|---|---|---|
| Баланс клиента | GET /v1/customers/{externalId}/balance |
LOYALTY_ACCOUNT_READ |
— (чтение) |
| История операций | GET /v1/customers/{externalId}/operations |
LOYALTY_MONITORING_READ |
— (чтение) |
| Начисление | POST /v1/customers/{externalId}/accruals |
LOYALTY_ACCRUAL_WRITE |
Idempotency-Key |
| Корректировка | POST /v1/customers/{externalId}/corrections |
LOYALTY_REDEMPTION_WRITE |
Idempotency-Key |
| Резерв (hold) | POST /v1/customers/{externalId}/holds |
LOYALTY_REDEMPTION_WRITE |
Idempotency-Key |
| Подтверждение резерва | POST /v1/customers/{externalId}/holds/{holdId}/commit |
LOYALTY_REDEMPTION_WRITE |
Idempotency-Key |
| Отмена резерва | POST /v1/customers/{externalId}/holds/{holdId}/cancel |
LOYALTY_REDEMPTION_WRITE |
Idempotency-Key |
| Прямое списание | POST /v1/customers/{externalId}/redemptions |
LOYALTY_REDEMPTION_WRITE |
Idempotency-Key |
| Ручное сгорание | POST /v1/customers/{externalId}/expirations |
LOYALTY_REDEMPTION_WRITE |
Idempotency-Key |