Настройка подписок

Перед запуском продаж подготовьте тарифы и назначьте их приложению. После этого клиентская витрина сможет получить каталог и оформить первую подписку.

Административный API нужен для настройки и наблюдения. Он работает с Bearer сотрудника и не должен вызываться из публичного frontend.

Подготовка

До первого запроса:

  1. создайте Application и сохраните его App Token;
  2. подключите приложению склад с активной платёжной интеграцией;
  3. получите Bearer сотрудника через вход сотрудника;
  4. убедитесь, что у сотрудника есть права на номенклатуру, приложения и просмотр заказов.

Ниже <employee_token> — Bearer сотрудника. Храните его на сервере и не передавайте в браузер клиента.

Шаг 1. Создайте тариф

Тариф подписки — это номенклатура с признаком is_subscription: true, ценой и периодом списания.

POST /api/nomenclatures HTTP/1.1
Host: api.gigma.ru
Authorization: Bearer <employee_token>
Content-Type: application/json

{
    "name": "Доступ Pro, год",
    "kind_id": 1,
    "is_subscription": true,
    "billing_period_months": 12,
    "price": "9900.00"
}

kind_id: 1 — услуга. billing_period_months задаёт частоту списания: 1 — каждый месяц, 12 — каждый год, максимум 120. price — стоимость одного периода. Полный контракт — в создании номенклатуры.

Варианты одного тарифа

Месячный и годовой варианты создавайте отдельными позициями. Свяжите их через parent_nomenclature_id, задайте подпись в variant_label и порядок в variant_sort_order.

Метод subscription-catalog/grouped соберёт варианты в одну карточку. Назначить приложению нужно каждый вариант отдельно.

Что проверить перед назначением

Создание номенклатуры не проверяет готовность тарифа к покупке. Ошибка проявится только при checkout ответом 422. Проверьте заранее:

  • price больше нуля;
  • billing_period_months не меньше 1;
  • is_subscription равно true;
  • у приложения есть платёжный склад;
  • валюта и условия тарифа совпадают с тем, что показано клиенту.

На один тариф у клиента не может быть двух одновременно действующих подписок. Конфликтом считаются статусы active, charging и past_due; повторная покупка вернёт 422.

Шаг 2. Назначьте тариф приложению

POST /api/applications/12/subscription-nomenclatures HTTP/1.1
Host: api.gigma.ru
Authorization: Bearer <employee_token>
Content-Type: application/json

{
    "nomenclature_id": 5120,
    "sort_order": 10,
    "is_active": true
}

Назначить можно только подписочную позицию своего проекта. sort_order определяет порядок в каталоге, а is_active: false скрывает тариф без удаления назначения. Полный контракт — в настройке приложения.

У приложения, созданного через API, subscription_catalog_configured включён сразу. Поэтому каталог показывает только назначенные активные тарифы, а до первого назначения он пуст.

Режим совместимости остаётся только у старых приложений с опущенным subscription_catalog_configured: их каталог может вернуть все подписочные позиции проекта, включая позиции без application_id. Не рассчитывайте на этот режим в новой интеграции.

Шаг 3. Проверьте каталог как клиентская витрина

Проверяйте тарифы с App Token приложения, а не с Bearer сотрудника.

GET /api/counterparty/subscription-catalog/grouped HTTP/1.1
Host: api.gigma.ru
Token: <application_token>
Accept: application/json

Убедитесь, что ответ содержит только нужные тарифы, правильные цены, периоды и порядок вариантов. Формы ответа описаны в каталоге тарифов.

Шаг 4. Проведите тестовое оформление

Авторизуйте тестового клиента и пройдите оформление подписки полностью:

  1. создайте checkout;
  2. завершите платёж;
  3. получите подписку клиента;
  4. проверьте status, current_period_end и сохранённый способ оплаты;
  5. отмените тестовую подписку либо используйте отдельный тестовый тариф.

Не считайте интеграцию готовой только по появлению payment_link. Проверьте успешный платёж, отказ банка, повтор запроса и возврат клиента до окончательного подтверждения платежа.

Наблюдение в административном API

После запуска Gigma сама выполняет списания и меняет статусы. Сотрудник может получить список, карточку и ленту изменений.

Административный контур только читает подписки. Отменить или возобновить подписку из этой стороны нельзя. Для действий от имени клиента используйте клиентские методы.

Данные всегда ограничены проектом сотрудника. Сотрудник ниже администратора с заданным branch_id видит только подписки, чей первый заказ относится к его филиалу. Администратор, владелец и сотрудник без филиала видят все доступные подписки проекта.

Список подписок

Метод
GET
URL
https://api.gigma.ru/api/tables/subscriptions
Авторизация
Bearer сотрудника
Headers
Authorization: Bearer {employee_token}
Успешный ответ
200

Метод возвращает конфигурацию таблицы, строки текущей страницы, счётчики и пагинацию.

Параметры запроса

  • page (integer, опционально) — номер страницы, начиная с 1;
  • per_page (integer, опционально) — от 1 до 100, по умолчанию 20;
  • query (string, опционально) — поиск по ФИО, названию компании или телефону клиента; строка от 3 до 100 символов, для телефонного запроса нужно минимум 3 цифры;
  • status[] (string[], опционально) — active, charging, past_due, canceled;
  • application_id[] (integer[], опционально) — приложения текущего проекта;
  • date_from (date, опционально) — дата создания подписки от этой границы;
  • date_to (date, опционально) — дата создания подписки до этой границы;
  • sort_by (string, опционально) — created_at, current_period_end, last_payment_at или amount;
  • sort_dir (string, опционально) — asc или desc.

Если в query есть буквы, каждое слово ищется в фамилии, имени, отчестве или названии компании. Запрос без букв считается телефонным: формат номера не важен, но после нормализации должно остаться не меньше трёх цифр.

Ответ

{
    "columns": [
        {
            "id": 210,
            "table_id": 25,
            "order": 0,
            "key": "id",
            "text": "№"
        }
    ],
    "subscriptions": [
        {
            "id": {
                "icon": null,
                "value": 981,
                "url": "https://app.gigma.ru/subscriptions/list-subscriptions/981"
            },
            "created_at": "2026-08-18T10:15:00.000000Z",
            "counterparty": {
                "icon": "https://api.gigma.ru/storage/uploads/default.svg",
                "value": "Иванов Иван",
                "link": "https://app.gigma.ru/counterparty/list-counterparty/3312"
            },
            "phone": "79990000000",
            "nomenclature": {
                "icon": "https://api.gigma.ru/storage/uploads/default.svg",
                "value": "Доступ Pro, год",
                "link": "https://app.gigma.ru/nomenclatures/list-nomenclatures/5120"
            },
            "application": {
                "icon": "https://api.gigma.ru/storage/uploads/default.svg",
                "value": "Сайт",
                "link": "https://app.gigma.ru/ecommerce/list-ecommerce/12"
            },
            "amount": "9900.00 RUB",
            "current_period_end": "2027-08-18T10:15:00.000000Z",
            "status": "active"
        }
    ],
    "counters": {
        "total": 171,
        "active": 128,
        "past_due": 2,
        "canceled": 37
    },
    "pagination": {
        "total": 171,
        "per_page": 20,
        "current_page": 1,
        "last_page": 9,
        "from": 1,
        "to": 20
    }
}

subscriptions — не сырой объект подписки, а строки для таблицы. У ячейки id переход хранится в url; у клиента, тарифа и приложения — в link. Значение icon для этих связанных ячеек — абсолютный URL, включая стандартную иконку, если собственного изображения нет.

Счётчики учитывают проект, филиал, поиск, приложение и даты, но считаются до применения status[]. Поэтому они показывают распределение даже при выбранном статусном фильтре. Отдельного поля charging в counters нет: такие подписки входят только в total.

Даты административного контура сериализуются в формате Laravel с микросекундами, например 2026-08-18T10:15:00.000000Z. Это отличается от клиентских ответов с форматом 2026-08-18T10:15:00+00:00.

Ошибки

  • 401 — Bearer сотрудника отсутствует или не распознан;
  • 403 — нет ни одного из прав view-orders, create-orders, edit-orders;
  • 422 — параметры фильтра или сортировки не прошли проверку.

Карточка подписки

Метод
GET
URL
https://api.gigma.ru/api/subscriptions/{id}
Авторизация
Bearer сотрудника
Headers
Authorization: Bearer {employee_token}
Успешный ответ
200

Метод возвращает подписку, клиента, приложение, тариф и связанные заказы. Используйте его для разбора конкретного списания, а не пытайтесь восстановить карточку из строки таблицы.

Ответ

{
    "subscription": {
        "id": 981,
        "status": "active",
        "plan_slug": "nomenclature-5120",
        "amount": "9900.00",
        "currency": "RUB",
        "billing_period_months": 12,
        "current_period_start": "2026-08-18T10:15:00.000000Z",
        "current_period_end": "2027-08-18T10:15:00.000000Z",
        "last_payment_at": "2026-08-18T10:15:05.000000Z",
        "last_payment_error": null,
        "next_charge_at": "2027-08-16T10:15:00.000000Z",
        "canceled_at": null,
        "created_at": "2026-08-18T10:15:00.000000Z",
        "updated_at": "2026-08-18T10:15:05.000000Z",
        "counterparty": {
            "id": 3312,
            "name": "Иванов Иван",
            "phone_1": "79990000000",
            "phone_2": null
        },
        "application": {
            "id": 12,
            "name": "Сайт"
        },
        "nomenclature": {
            "id": 5120,
            "name": "Доступ Pro, год"
        },
        "orders": [
            {
                "id": 7741,
                "name": "Подписка Доступ Pro, год",
                "created_at": "2026-08-18T10:15:00.000000Z",
                "price": "9900.00",
                "final_price": "9900.00",
                "status": {
                    "id": 22,
                    "name": "Оплачен"
                },
                "application": {
                    "id": 12,
                    "name": "Сайт"
                },
                "branch": {
                    "id": 1,
                    "name": "Основной"
                }
            }
        ]
    }
}

next_charge_at означает «не раньше этого времени». Список orders объединяет первый заказ и заказы продлений без дублей. В карточке нет идентификаторов платежей провайдера, ключей идемпотентности и данных сохранённого способа оплаты.

Ошибки

  • 401 — Bearer сотрудника отсутствует или не распознан;
  • 403 — недостаточно прав;
  • 404 — подписка не существует либо находится в другом проекте или недоступном сотруднику филиале.

Лента изменений статуса

Метод
GET
URL
https://api.gigma.ru/api/subscriptions/{id}/status-events
Авторизация
Bearer сотрудника
Headers
Authorization: Bearer {employee_token}
Успешный ответ
200

Лента объясняет, когда и почему подписка переходила между состояниями. События идут от новых к старым.

Параметры запроса

  • page_size (integer, опционально) — от 1 до 100, по умолчанию 25;
  • page_token (string, опционально) — токен следующей страницы из предыдущего ответа.

Ответ

{
    "status_events": [
        {
            "name": "subscriptions/981/status-events/4471",
            "id": 4471,
            "event_type": "payment_failed",
            "from_status": "charging",
            "to_status": "past_due",
            "initiator": {
                "type": "system",
                "id": null
            },
            "origin": "scheduler",
            "created_at": "2026-08-18T09:00:00.000000Z"
        }
    ],
    "next_page_token": ""
}

Пустой next_page_token означает, что следующей страницы нет.

Ошибки

  • 401 — Bearer сотрудника отсутствует или не распознан;
  • 403 — недостаточно прав;
  • 404 — подписка не находится в доступном сотруднику контуре;
  • 422 — неверный page_size или page_token.

Получение отдельного события

Метод
GET
URL
https://api.gigma.ru/api/subscriptions/{id}/status-events/{status_event}
Авторизация
Bearer сотрудника
Headers
Authorization: Bearer {employee_token}
Успешный ответ
200

Метод возвращает одно событие из ленты подписки.

Ответ

{
    "name": "subscriptions/981/status-events/4471",
    "id": 4471,
    "event_type": "payment_failed",
    "from_status": "charging",
    "to_status": "past_due",
    "initiator": {
        "type": "system",
        "id": null
    },
    "origin": "scheduler",
    "created_at": "2026-08-18T09:00:00.000000Z"
}

Ошибки

  • 401 — Bearer сотрудника отсутствует или не распознан;
  • 403 — недостаточно прав;
  • 404 — подписка недоступна либо событие не принадлежит этой подписке.

Проверка перед запуском

  • каталог с App Token показывает только назначенные тарифы;
  • цена и период в каталоге совпадают с экраном согласия;
  • checkout обрабатывает HTTP 200, 201, 202, 409 и 422;
  • возврат с платёжной страницы не используется как подтверждение оплаты;
  • backend выдаёт доступ только при active и неистёкшем current_period_end;
  • клиент может отменить подписку и заменить способ оплаты;
  • административный список ограничен проектом и филиалом сотрудника;
  • у поддержки есть сценарий разбора past_due, manual_review и неуспешного платежа.

Ограничения

  • Отменить или возобновить подписку из этой стороны нельзя: административные методы только читают данные.
  • Тариф без is_subscription: true назначить приложению нельзя.
  • Цена подписки берётся из номенклатуры, а не из складского остатка или произвольного клиентского запроса.
  • Для каждого нового приложения назначайте тарифы явно. Режим совместимости с опущенным subscription_catalog_configured не является моделью для новой интеграции.
  • Если платёж не должен повторяться, используйте обычный заказ, а не подписку.