Правила работы с Gigma API

Эта страница описывает общие правила интеграции. Точный набор полей, заголовков, кодов ответа и ограничений всегда берите из карточки конкретного метода или из OpenAPI: backend не использует один универсальный контракт для всех endpoint.

Базовый адрес

https://api.gigma.ru/api

Например, путь POST /api/login вызывается по адресу:

https://api.gigma.ru/api/login

Заголовки и формат тела

Для JSON-ответа передавайте:

Accept: application/json

Для запроса с JSON-телом добавляйте:

Content-Type: application/json

Другие форматы указываются в карточке метода:

  • загрузка файлов — multipart/form-data;
  • introspection клиентского токена — application/x-www-form-urlencoded;
  • запрос без тела не требует Content-Type.

Не устанавливайте multipart/form-data вручную вместе с boundary: это должен сделать HTTP-клиент при формировании формы.

Авторизация

API использует несколько независимых способов доступа.

КонтекстЗаголовокГде используется
СотрудникAuthorization: Bearer <erp_access_token>Административный API
ПриложениеToken: <application_token>Публичные и клиентские методы конкретного Application
КлиентAuthorization: Bearer <counterparty_access_token>Профиль и персональные commerce-операции
Приложение + клиентОба заголовка одновременноЗаказы, подписки и другие application-scoped методы
Backend-интеграцияAuthorization: Basic <base64(client_id:client_secret)>POST /api/counterparty/auth/introspect

Точный набор авторизации указан у каждого метода. ERP Bearer и Counterparty Bearer выглядят одинаково на уровне HTTP, но относятся к разным guards и не взаимозаменяются.

Bearer и серверные credentials — непрозрачные секреты

Sanctum Bearer может содержать служебные разделители, однако клиент не должен разбирать его на части. Используйте значение access_token.value целиком. client_secret introspection-интеграции храните только на backend.

App Token определяет Application, но в прямой браузерной интеграции не может считаться конфиденциальным: пользователь видит сетевые запросы. Не используйте App Token как замену клиентскому Bearer или проверке прав.

Нельзя:

  • помещать токен в URL или query-параметр;
  • записывать его в аналитику, error tracking и access-логи;
  • определять пользователя по части токена;
  • хранить backend-секреты в браузере.

При наличии собственного backend предпочтительна локальная httpOnly-сессия: Bearer проверяется сервером, а браузер не получает долгоживущий секрет Gigma после обмена.

Готовый запрос

Запрос профиля сотрудника:

curl --request GET 
  --url https://api.gigma.ru/api/user 
  --header 'Accept: application/json' 
  --header 'Authorization: Bearer <erp_access_token>'

Сокращённый успешный ответ:

{
  "user": {
    "id": 17,
    "login": "manager@example.test",
    "first_name": "Ирина",
    "is_banned": false,
    "permissions": []
  }
}

Wrapper и состав объекта зависят от Resource-класса конкретного endpoint. Не выводите имя корневого поля из URL по аналогии.

Успешные ответы

Успех определяется диапазоном 2xx, но конкретный код и тело являются частью контракта метода.

В текущем backend встречаются разные варианты:

  • создание может вернуть 200 с Resource либо явно заданный 201;
  • обновление обычно возвращает 200 с объектом;
  • удаление нередко возвращает 200 с { "message": "..." }, а не 204;
  • асинхронная операция может использовать собственный статус.

Поэтому:

  1. принимайте весь документированный диапазон 2xx;
  2. не пытайтесь парсить тело у ответа, для которого указан 204;
  3. не считайте любой POST автоматически ответом 201;
  4. не считайте любой DELETE автоматически ответом 204.

Форматы значений

Единого формата для всех исторических endpoint нет. Используйте схему конкретного поля.

ЗначениеПравило клиента
ДатаОбычно YYYY-MM-DD; проверяйте format: date
Дата и времяПарсите как ISO 8601 и сохраняйте timezone
ДеньгиНе преобразовывайте decimal-string в float без необходимости
BooleanНовые поля используют true/false; legacy-ответы могут содержать 0/1
IDСчитайте ссылкой на ресурс или живой справочник, а не бизнес-константой
NullableРазличайте отсутствующее поле и явно переданный null

Пагинация, фильтры и сортировка

Пагинация не унифицирована глобально. В API есть:

  • Laravel paginator с data, current_page, last_page, links и URL страниц;
  • UI-таблицы с columns, ресурсным массивом и pagination;
  • непагинированные коллекции со своим wrapper и полем count.

Параметры page, per_page, query, date_from и date_to встречаются часто, но поддерживаются не каждым методом. Отправляйте только параметры, перечисленные в его карточке. Не переносите фильтры одного ресурса на другой автоматически.

Ошибки

Нет или невалиден Bearer

{
  "message": "Unauthenticated."
}

Нет App Token

{
  "message": "Application token is missing"
}

Ошибка валидации

Обычный Form Request возвращает errors, а message может присутствовать или отсутствовать:

{
  "message": "The given data was invalid.",
  "errors": {
    "phone": ["Поле phone является обязательным."],
    "products.0.id": ["Выбранное значение некорректно."]
  }
}

Ключи вложенных полей записываются через точку. Не привязывайте обработку к языку текста: используйте HTTP-код и имя поля.

Как клиенту реагировать

КодЧто означаетДействие клиента
400Запрос понятен, но текущий flow или состояние не подходитИсправить последовательность действий; не повторять без изменения
401Нет, истёк или не подходит токенУдалить локальную сессию или повторить вход; тот же токен не отправлять циклически
403Идентичность подтверждена, но нет permission, scope или token abilityОстановить запрос и проверить настройки доступа
404Ресурс отсутствует либо скрыт проектной/application-границейНе перебирать ID; проверить контекст проекта и приложения
409Конфликт состояния или повтор операцииПолучить актуальное состояние и решить конфликт
415Неверный Content-TypeПересобрать запрос в формате из карточки метода
422Не прошла валидация или бизнес-проверкаПоказать ошибки полей либо исправить данные
429Превышен лимитУчесть Retry-After, применить backoff с jitter и не создавать параллельный retry-шторм
5xx или timeoutРезультат неизвестен либо backend временно недоступенДля чтения — ограниченный retry; для записи — сначала сверить состояние через GET

Rate limits

Лимиты задаются на уровне конкретных маршрутов. Универсального публичного значения «60 запросов в минуту для всего API» нет.

Примеры из текущей конфигурации backend:

ОперацияОграничение
POST /api/login5 запросов в минуту
POST /api/counterparty/login5 в минуту на project + contact и 30 в минуту на IP
POST /api/counterparty/send_password3 в час на project + contact и 20 в час на IP
POST /api/counterparty/auth/introspect60 в минуту на IP и 300 в минуту на backend-клиент
POST /api/counterparty/session/heartbeat6 в минуту на клиентскую сессию

Эти значения описывают текущую реализацию, а не бессрочную квоту продукта. Клиент всё равно должен корректно обрабатывать 429 и заголовки ответа.

Повторы и идемпотентность

Общего публичного контракта Idempotency-Key для Gigma API нет.

ЗапросРекомендация
GETМожно повторить с ограниченным exponential backoff
POST создания или оплатыНе повторять вслепую после timeout/5xx; сначала найти результат по бизнес-идентификатору
PUT/PATCHПовтор допустим только если карточка метода и операция действительно идемпотентны
DELETEНе считать глобально идемпотентным: повтор может вернуть другой код или тело

На стороне продукта сохраняйте собственный correlation ID и состояние попытки. Пользовательское действие, которое может создать заказ, платёж или подписку, блокируйте от двойной отправки.

Webhook

В текущем публичном контракте Application поддерживает событие order.paid.

При доставке Gigma передаёт:

X-Webhook-Event: order.paid
X-Webhook-Event-Id: <event_id>
X-Webhook-Delivery-Id: <delivery_id>
X-Webhook-Timestamp: <unix_timestamp>
X-Signature: sha256=<hex_digest>
Content-Type: application/json

Подпись вычисляется по исходным байтам тела:

HMAC_SHA256(secret, timestamp + "." + raw_body)

Получатель должен:

  1. проверить допустимый возраст X-Webhook-Timestamp;
  2. вычислить HMAC по необработанному body и сравнить подпись constant-time способом;
  3. дедуплицировать событие по X-Webhook-Event-Id или доставку по X-Webhook-Delivery-Id;
  4. сохранить событие транзакционно;
  5. быстро вернуть любой 2xx.

Redirect не используется, timeout доставки — 10 секунд. После неуспеха повторы планируются через 1, 5, 30, 120 и 720 минут. После исчерпания попыток доставка переходит в failed и может быть повторно отправлена администратором.

Подробная настройка находится в «Платформа / Приложения».

Версионирование и совместимость

Публичные пути сейчас находятся под /api без /v1. Отсутствие версии в URL не означает, что клиент может полагаться на недокументированные поля или внутренние классы.

Для устойчивой интеграции:

  • отправляйте только документированные поля;
  • допускайте появление новых необязательных полей в JSON;
  • не полагайтесь на порядок ключей;
  • фиксируйте контрактные тесты на критические сценарии;
  • проверяйте изменения OpenAPI перед релизом клиента.

Машиночитаемый слой

  • openapi.json — методы, security schemes и схемы, извлечённые из карточек endpoint;
  • Swagger UI — просмотр и ручная проверка запросов;
  • llms.txt — индекс документации для агента;
  • llms-full.txt — полный текст страниц;
  • erp-rules.txt — короткие правила безопасной интеграции.

OpenAPI не подменяет runtime-код: генератор намеренно не угадывает ID справочников и не выводит 201/204 только из HTTP-метода.

Спецификация собирается из карточек методов, поэтому отсутствие данных означает «не зафиксировано», а не «запрещено». Код 2XX значит, что точный статус не подтверждён карточкой; отсутствие requestBody не доказывает, что тело не нужно; example иллюстрирует формат, а не допустимый диапазон значений. Полный список правил чтения для агента — в erp-rules.txt §13.

Следующие шаги

© 2026 Gigma