Управление промокодами
Промокод уменьшает стоимость заказа в клиентском приложении Gigma. Вы задаёте код, размер скидки, период, лимиты и аудиторию, а витрина передаёт код при расчёте корзины и создании заказа.
Для управления используйте методы /api/discounts. Методы /api/promotions относятся к старому справочнику промоакций и не создают промокоды.
Промокод может относится к конкретному Application. Если application_id равен null, код работает во всех приложениях того же проекта.
Как это работает
- Сотрудник создаёт промокод. Без поля
statusобъект получает статусdraft. - Сотрудник активирует код.
- Витрина передаёт
promo_codeв предварительный расчёт заказа. - Gigma считает скидку после товарных скидок.
- При создании заказа Gigma повторно проверяет код с учётом клиента, приложения, дат и лимитов.
- Применение попадает в журнал.
Сотрудник → POST /api/discounts → промокод draft → activate
│
Клиент → precalculate → создание заказа ─────────────┴→ журнал применений Авторизация
| Задача | Авторизация |
|---|---|
| Управлять промокодами, статистикой и журналом | Bearer сотрудника |
| Предварительно рассчитать корзину | App Token |
| Создать заказ с промокодом | App Token + Bearer клиента |
Административные методы /api/discounts работают внутри проекта сотрудника. Чужой application_id или branch_id не проходит валидацию, а чтение или изменение промокода другого проекта возвращает 404.
Код уникален во всём проекте среди неархивированных промокодов, а не только внутри одного приложения.
branch_id используется как атрибут и фильтр административного списка. В текущей клиентской проверке он не ограничивает применение кода по филиалу.
Быстрый старт
Шаг 1. Создайте промокод
POST /api/discounts HTTP/1.1
Host: api.gigma.ru
Authorization: Bearer <employee_token>
Accept: application/json
Content-Type: application/json
{
"name": "10% на первый заказ",
"code": "WELCOME10",
"discount_type": "percent",
"discount_value": 10,
"application_id": 17,
"min_order_amount": 500,
"max_discount_amount": 1000,
"total_usage_limit": 1000,
"per_client_usage_limit": 1,
"audience": "new_clients",
"starts_at": "2026-08-20T00:00:00+03:00",
"ends_at": "2026-09-30T23:59:59+03:00"
} Gigma удаляет пробелы по краям кода и переводит латинские буквы в верхний регистр. Допустимы A–Z, цифры и дефис, длина — до 64 символов.
Шаг 2. Активируйте код
POST /api/discounts/42/activate HTTP/1.1
Host: api.gigma.ru
Authorization: Bearer <employee_token>
Accept: application/json Шаг 3. Рассчитайте корзину
POST /api/counterparty/orders/precalculate HTTP/1.1
Host: api.gigma.ru
Token: <application_token>
Accept: application/json
Content-Type: application/json
{
"products": [
{ "id": 34780, "quantity": 2 }
],
"promo_code": "WELCOME10"
} Успешный расчёт возвращает promo_discount_amount, final_price и applied_discount. Предварительный расчёт не резервирует лимит и не заменяет окончательную проверку.
Шаг 4. Создайте заказ
Передайте тот же promo_code в POST /api/counterparty/orders вместе с обычными полями заказа. На этом шаге Gigma повторно проверяет код от имени авторизованного клиента и записывает применение.
Полный контракт находится в разделе «Заказы и оплата».
Настройки промокода
Размер скидки
discount_type: "percent"— процент от суммы после товарных скидок;discount_valueот0.01до100.discount_type: "fixed"— фиксированная сумма;discount_valueне меньше0.01.max_discount_amountограничивает скидку сверху.- Итоговая скидка не превышает сумму заказа.
Период и статусы
starts_at и ends_at необязательны. Для объекта со статусом active поле effective_status рассчитывается по датам:
| Состояние | effective_status |
|---|---|
| дата начала ещё не наступила | scheduled |
| дата окончания прошла | expired |
| промокод действует сейчас | active |
draft, paused, archived | совпадает с status |
Исчерпанный лимит не меняет effective_status: код остаётся active, но заказ получает ошибку лимита.
Лимиты
min_order_amount— минимальная сумма после товарных скидок.total_usage_limit— общий лимит применений.per_client_usage_limit— лимит на одного клиента.total_used_count— текущий счётчик.usage_percent— доля использования общего лимита;null, если лимит не задан.
Аудитория
| Значение | Поведение |
|---|---|
all | доступно всем |
new_clients | доступно клиенту без ранее успешных заказов |
partners | значение сохраняется, но применение сейчас отклоняется кодом 2009 |
custom | значение сохраняется, но применение сейчас отклоняется кодом 2010 |
Правила, зависящие от клиента, могут быть неполными в публичном precalculate. Окончательное решение принимает POST /api/counterparty/orders с Bearer клиента.
Административные методы
Получение списка промокодов
- Метод
- GET
- URL
https://api.gigma.ru/api/discounts- Авторизация
- Bearer сотрудника
- Headers
Authorization: Bearer {token}- Успешный ответ
200
Возвращает промокоды текущего проекта, недавно изменённые — первыми. Без фильтра status архивные записи не возвращаются.
Параметры запроса
query(string, необязательно, до 255 символов) — поиск по названию или коду.status(string, необязательно) —all,active,scheduled,expired,paused,draftилиarchived.audience(string, необязательно) —all,new_clients,partnersилиcustom.period(string, необязательно) — месяцYYYY-MM; возвращаются коды, действовавшие хотя бы один день месяца.application_id(integer, необязательно) — приложение текущего проекта.branch_id(integer, необязательно) — филиал текущего проекта.page(integer, необязательно) — номер страницы, начиная с 1.per_page(integer, необязательно) — от 1 до 200, по умолчанию 50.
Пример запроса
GET /api/discounts?status=active&application_id=17&period=2026-08&page=1&per_page=50 HTTP/1.1
Host: api.gigma.ru
Authorization: Bearer <employee_token>
Accept: application/json Ответ
{
"discounts": [
{
"id": 42,
"project_id": 10,
"application_id": 17,
"branch_id": null,
"name": "10% на первый заказ",
"code": "WELCOME10",
"description": null,
"status": "active",
"effective_status": "active",
"discount_type": "percent",
"discount_value": 10,
"min_order_amount": 500,
"max_discount_amount": 1000,
"total_usage_limit": 1000,
"total_used_count": 24,
"per_client_usage_limit": 1,
"usage_percent": 2.4,
"audience": "new_clients",
"starts_at": "2026-08-20T00:00:00.000000Z",
"ends_at": "2026-09-30T20:59:59.000000Z",
"url": null,
"paused_at": null,
"archived_at": null,
"share_path": "?ref=WELCOME10",
"magic_link": "https://shop.example.com/?ref=WELCOME10",
"created_by": 14,
"updated_by": 14,
"created_at": "2026-08-20T09:00:00.000000Z",
"updated_at": "2026-08-20T09:10:00.000000Z"
}
],
"discountsCount": 1,
"pagination": {
"current_page": 1,
"per_page": 50,
"last_page": 1,
"total": 1
}
} Возможные ошибки
401— Bearer сотрудника отсутствует или недействителен.422— фильтр имеет неверный формат либо связанный объект относится к другому проекту.
Создание промокода
- Метод
- POST
- URL
https://api.gigma.ru/api/discounts- Авторизация
- Bearer сотрудника
- Headers
Authorization: Bearer {token}; Content-Type: application/json- Успешный ответ
201
Если status не передан, используется draft; если не передана audience, используется all; min_order_amount по умолчанию равен 0.
Параметры запроса
name(string, обязательно, до 255 символов) — внутреннее название.code(string, обязательно, до 64 символов) — латинские буквы, цифры и дефис.discount_type(string, обязательно) —percentилиfixed.discount_value(number, обязательно) — размер скидки.status(string, необязательно) —draft,active,pausedилиarchived.application_id(integer|null, необязательно) — ограничить код одним приложением.branch_id(integer|null, необязательно) — атрибут филиала.min_order_amount(number|null, необязательно) — минимальная сумма, не меньше 0.max_discount_amount(number|null, необязательно) — верхняя граница скидки, не меньше 0.total_usage_limit(integer|null, необязательно) — общий лимит, не меньше 1.per_client_usage_limit(integer|null, необязательно) — лимит на клиента, не меньше 1.audience(string, необязательно) —all,new_clients,partnersилиcustom.starts_at(string|null, необязательно) — начало действия.ends_at(string|null, необязательно) — окончание действия, не раньшеstarts_at.url(string|null, необязательно, до 2048 символов) — собственная ссылка.description(string|null, необязательно) — описание.
Пример запроса
{
"name": "500 ₽ на заказ от 5000 ₽",
"code": "SAVE-500",
"discount_type": "fixed",
"discount_value": 500,
"application_id": 17,
"min_order_amount": 5000,
"total_usage_limit": 300,
"per_client_usage_limit": 1,
"audience": "all"
} Ответ
При успешном создании API возвращает HTTP 201 с объектом discount.
Возможные ошибки
401— Bearer сотрудника отсутствует или недействителен.422— код занят, формат неверен, процент больше 100 либо связанный объект принадлежит другому проекту.
Получение промокода
- Метод
- GET
- URL
https://api.gigma.ru/api/discounts/{discount}- Авторизация
- Bearer сотрудника
- Headers
Authorization: Bearer {token}- Успешный ответ
200
Возвращает промокод и до 20 последних применений в latest_usages.
Параметры пути
discount(integer, обязательно) — идентификатор промокода.
Ответ
{
"discount": {
"id": 42,
"application_id": 17,
"name": "10% на первый заказ",
"code": "WELCOME10",
"status": "active",
"effective_status": "active",
"discount_type": "percent",
"discount_value": 10,
"total_used_count": 24,
"latest_usages": [
{
"id": 301,
"order_id": 9001,
"counterparty_id": 701,
"code": "WELCOME10",
"original_amount": 2500,
"product_discount_amount": 0,
"discount_amount": 250,
"final_amount": 2250,
"status": "confirmed",
"used_at": "2026-08-20T10:00:00.000000Z"
}
]
}
} Возможные ошибки
401— Bearer сотрудника отсутствует или недействителен.404— промокод не найден либо относится к другому проекту.
Частичное изменение промокода
- Метод
- PATCH
- URL
https://api.gigma.ru/api/discounts/{discount}- Авторизация
- Bearer сотрудника
- Headers
Authorization: Bearer {token}; Content-Type: application/json- Успешный ответ
200
Изменяет только переданные поля.
Параметры пути
discount(integer, обязательно) — идентификатор промокода.
Параметры запроса
Поля те же, что при создании, но все необязательны. При одновременном изменении процентного типа и значения передавайте оба поля.
Пример запроса
{
"discount_type": "percent",
"discount_value": 15,
"ends_at": "2026-10-31T23:59:59+03:00"
} Ответ
HTTP 200 с обновлённым объектом discount.
Возможные ошибки
401— Bearer сотрудника отсутствует или недействителен.404— промокод не найден либо относится к другому проекту.422— данные не прошли валидацию или код конфликтует с другой неархивированной записью.
Изменение промокода через PUT
- Метод
- PUT
- URL
https://api.gigma.ru/api/discounts/{discount}- Авторизация
- Bearer сотрудника
- Headers
Authorization: Bearer {token}; Content-Type: application/json- Успешный ответ
200
Поддерживается для совместимости и использует тот же частичный контракт, что PATCH.
Параметры пути
discount(integer, обязательно) — идентификатор промокода.
Параметры запроса
Те же поля, что в PATCH /api/discounts/{discount}.
Ответ
HTTP 200 с обновлённым объектом discount.
Возможные ошибки
401— Bearer сотрудника отсутствует или недействителен.404— промокод не найден либо относится к другому проекту.422— данные не прошли валидацию.
Постановка промокода на паузу
- Метод
- POST
- URL
https://api.gigma.ru/api/discounts/{discount}/pause- Авторизация
- Bearer сотрудника
- Headers
Authorization: Bearer {token}- Успешный ответ
200
Меняет status на paused и заполняет paused_at.
Параметры пути
discount(integer, обязательно) — идентификатор промокода.
Ответ
HTTP 200 с обновлённым объектом discount.
Возможные ошибки
401— Bearer сотрудника отсутствует или недействителен.404— промокод не найден либо относится к другому проекту.
Активация промокода
- Метод
- POST
- URL
https://api.gigma.ru/api/discounts/{discount}/activate- Авторизация
- Bearer сотрудника
- Headers
Authorization: Bearer {token}- Успешный ответ
200
Меняет status на active, очищает paused_at и archived_at.
Параметры пути
discount(integer, обязательно) — идентификатор промокода.
Ответ
HTTP 200 с обновлённым объектом discount.
Возможные ошибки
401— Bearer сотрудника отсутствует или недействителен.404— промокод не найден либо относится к другому проекту.422— другой неархивированный промокод проекта уже использует тот же код.
Архивирование промокода
- Метод
- POST
- URL
https://api.gigma.ru/api/discounts/{discount}/archive- Авторизация
- Bearer сотрудника
- Headers
Authorization: Bearer {token}- Успешный ответ
200
Меняет status на archived и заполняет archived_at. Журнал сохраняется, а код можно повторно использовать в новой записи.
Параметры пути
discount(integer, обязательно) — идентификатор промокода.
Ответ
HTTP 200 с обновлённым объектом discount.
Возможные ошибки
401— Bearer сотрудника отсутствует или недействителен.404— промокод не найден либо относится к другому проекту.
Удаление промокода
- Метод
- DELETE
- URL
https://api.gigma.ru/api/discounts/{discount}- Авторизация
- Bearer сотрудника
- Headers
Authorization: Bearer {token}- Успешный ответ
204
Метод не удаляет запись физически: он архивирует промокод, чтобы сохранить журнал.
Параметры пути
discount(integer, обязательно) — идентификатор промокода.
Ответ
Успешный ответ — HTTP 204 No Content без тела.
Возможные ошибки
401— Bearer сотрудника отсутствует или недействителен.404— промокод не найден либо относится к другому проекту.
Получение статистики промокодов
- Метод
- GET
- URL
https://api.gigma.ru/api/discounts/stats- Авторизация
- Bearer сотрудника
- Headers
Authorization: Bearer {token}- Успешный ответ
200
Возвращает статистику проекта за выбранный месяц. В использования и экономию входят только записи confirmed.
Параметры запроса
period(string, необязательно) — месяцYYYY-MM, по умолчанию текущий.application_id(integer, необязательно) — ограничить статистику одним приложением.
Ответ
{
"period": "2026-08",
"active_count": 4,
"active_delta": 1,
"usage_count_for_period": 127,
"usage_delta_percent": 18.69,
"saved_amount_for_period": 45890.5,
"saved_delta_percent": 12.3
} Описание полей ответа
active_count— количество кодов, активных сейчас с учётом дат.active_delta— сколько кодов со статусомactiveсоздано в выбранном месяце.usage_count_for_period— подтверждённые применения.usage_delta_percent— изменение к предыдущему месяцу; может бытьnull.saved_amount_for_period— подтверждённая сумма скидок.saved_delta_percent— изменение к предыдущему месяцу; может бытьnull.
Возможные ошибки
401— Bearer сотрудника отсутствует или недействителен.422— неверный период или приложение принадлежит другому проекту.
Получение применений промокода
- Метод
- GET
- URL
https://api.gigma.ru/api/tables/discounts/{discount}/usages- Авторизация
- Bearer сотрудника
- Headers
Authorization: Bearer {token}- Успешный ответ
200
Возвращает табличную историю применений.
Параметры пути
discount(integer, обязательно) — идентификатор промокода.
Параметры запроса
page(integer, необязательно) — номер страницы.per_page(integer, необязательно) — от 1 до 100, по умолчанию 10.status(string, необязательно) —reserved,confirmed,canceled,allили список через запятую.from(string, необязательно) — начало периодаYYYY-MM-DD.to(string, необязательно) — конец периодаYYYY-MM-DD.counterparty_id(integer, необязательно) — клиент.order_id(integer, необязательно) — заказ.application_id(integer, необязательно) — приложение.query(string, необязательно, до 128 символов) — код, ID заказа или имя клиента.sort_by(string, необязательно) —used_at,final_amount,discount_amountилиoriginal_amount.sort_dir(string, необязательно) —ascилиdesc.
Ответ
{
"columns": [],
"discount_usages": [
{
"id": 301,
"used_at": "2026-08-20T10:00:00.000000Z",
"order": { "icon": null, "value": "ORD-9001", "link": "..." },
"counterparty": { "icon": null, "value": "Иван Петров", "link": "..." },
"application": { "icon": null, "value": "Интернет-магазин", "link": "..." },
"code": "WELCOME10",
"original_amount": 2500,
"product_discount_amount": 0,
"discount_amount": 250,
"final_amount": 2250,
"status": "confirmed"
}
],
"pagination": {
"total": 1,
"per_page": 10,
"current_page": 1,
"last_page": 1,
"from": 1,
"to": 1
}
} reserved — заказ с оплатой картой создан, но платёж не подтверждён. После оплаты запись становится confirmed. При ошибке платежа применение получает canceled, а общий счётчик уменьшается.
Возможные ошибки
401— Bearer сотрудника отсутствует или недействителен.404— промокод не найден либо относится к другому проекту.422— фильтры не прошли валидацию.
Применение на витрине
Предварительный расчёт
POST /api/counterparty/orders/precalculate принимает App Token и необязательное поле promo_code.
{
"products": [
{ "id": 34780, "quantity": 2 }
],
"promo_code": "welcome10"
} Успешный ответ содержит:
{
"original_price": 2500,
"product_discount_amount": 0,
"promo_discount_amount": 250,
"total_discount_amount": 250,
"final_price": 2250,
"applied_discount": {
"id": 42,
"code": "WELCOME10",
"name": "10% на первый заказ",
"type": "percent",
"value": 10
},
"discount_error": null
} Если код нельзя применить, публичный расчёт не раскрывает точную причину:
{
"applied_discount": null,
"discount_error": {
"reason": "Промокод не применим.",
"code": 2099
}
} Создание заказа
POST /api/counterparty/orders принимает App Token, Bearer клиента и поле promo_code. Код повторно проверяется в транзакции, поэтому успешный предварительный расчёт не гарантирует создание заказа: лимит мог закончиться, а аудитория — зависеть от клиента.
Успешный заказ возвращает promo_code, original_price, product_discount_amount, promo_discount_amount, total_discount_amount и final_price.
Если промокод обнулил заказ с оплатой банковской картой, Gigma не создаёт платёж на 0 ₽: заказ сразу переводится в оплаченный статус, а применение подтверждается.
Ошибки применения
Создание заказа возвращает HTTP 422 с message и числовым code:
| Код | Причина |
|---|---|
2001 | промокод не найден |
2002 | статус не active |
2003 | период ещё не начался |
2004 | срок закончился |
2005 | сумма меньше min_order_amount |
2006 | общий лимит исчерпан |
2007 | клиент исчерпал свой лимит |
2008 | код только для новых клиентов |
2009 | аудитория partners не настроена |
2010 | аудитория custom не поддерживается |
2011 | код относится к другому приложению |
При ошибке платёжной системы после создания заказа применение отменяется, а ответ 502 сообщает, что промокод не был списан.
Ссылки промокода
share_pathимеет вид?ref=<CODE>.magic_linkравенurl, если оно задано.- Если
urlне задан, Gigma собирает ссылку из настроенного frontend URL иshare_path; без frontend URL поле равноnull.
Получение ref из адресной строки и подстановка его в форму — ответственность frontend. API применяет код только после передачи promo_code.
Старый справочник промоакций
/api/promotions — read-only справочник и не является API управления промокодами. Он сохранён для совместимости старых административных экранов. Пошаговый сценарий находится в разделе «Промоакции».
GET /api/promotions/{promotion}работает без общей проверки проекта. Не используйте его как источник промокодов и не перебирайте идентификаторы.
Получение справочника промоакций
- Метод
- GET
- URL
https://api.gigma.ru/api/promotions- Авторизация
- Bearer сотрудника
- Headers
Authorization: Bearer {token}- Успешный ответ
200
Параметры запроса
query(string, необязательно) — поиск по названию.
Ответ
{
"promotions": [
{
"id": 1,
"name": "Промоакция",
"avatar": "https://api.gigma.ru/storage/uploads/default.svg",
"created_at": "2024-07-27T18:13:40.000000Z"
}
],
"promotionsCount": 1
} Возможные ошибки
401— Bearer сотрудника отсутствует или недействителен.
Получение элемента справочника промоакций
- Метод
- GET
- URL
https://api.gigma.ru/api/promotions/{promotion}- Авторизация
- Bearer сотрудника
- Headers
Authorization: Bearer {token}- Успешный ответ
200
Параметры пути
promotion(integer, обязательно) — идентификатор записи.
Ответ
{
"promotion": {
"id": 1,
"name": "Промоакция",
"avatar": "https://api.gigma.ru/storage/uploads/default.svg",
"created_at": "2024-07-27T18:13:40.000000Z"
}
} Возможные ошибки
401— Bearer сотрудника отсутствует или недействителен.404— запись не найдена.
Что дальше
- Заказы и оплата — полный контракт расчёта и создания заказа.
- Настройка Application и вебхуков — получить
application_idи App Token. - Правила API — авторизация, ошибки и безопасные повторы.