# Gigma API — правила безопасной интеграции Статус документа: проверено по runtime-коду backend на 2026-08-15. - Документация: `Artypoul/docs-gigma@72820945b68aedef269c502b4d054c6eee047d02` - Backend: `Progress-NSK/gigma-erp-api@41c426cabfa35b2ec25106b6c8360a06836e8fb6` - Базовый адрес: `https://api.gigma.ru/api` - HTML-правила: `https://docs.gigma.ru/conventions/` - OpenAPI: `https://docs.gigma.ru/openapi.json` - Полный текст: `https://docs.gigma.ru/llms-full.txt` Этот файл — короткий operational guide для агента. Он не заменяет карточку конкретного endpoint и не является доказательством поведения будущей версии backend. ================================================================ 1. Порядок источников ================================================================ Для обычной интеграции используйте опубликованные источники в таком порядке: 1. Карточка конкретного метода в документации. 2. `openapi.json`, сгенерированный из карточек методов. 3. Эта памятка. При аудите или обнаруженном противоречии источником фактического поведения является зафиксированный runtime-код: route → middleware → Form Request → controller/service → Resource → tests. Не переносите контракт одного endpoint на другой по аналогии и не маскируйте расхождение догадкой. ================================================================ 2. Базовые заголовки ================================================================ Для JSON-ответа: ``` Accept: application/json ``` Для JSON-тела: ``` Content-Type: application/json ``` Другие форматы: - файлы: `multipart/form-data`; - `POST /api/counterparty/auth/introspect`: `application/x-www-form-urlencoded`; - GET без тела: `Content-Type` не нужен. HTTP-клиент должен самостоятельно сформировать boundary для multipart. ================================================================ 3. Авторизация ================================================================ ### ERP User ``` Authorization: Bearer ``` Токен получается через `POST /api/login`. ### Application ``` Token: ``` App Token определяет Application и проектный контекст. Backend принимает только активный токен. При отсутствии или ошибке возвращается 401 с `message`. В прямом браузерном сценарии App Token наблюдаем пользователем и не заменяет клиентский Bearer или проверку прав. ### Counterparty ``` Authorization: Bearer ``` Токен получается через клиентский flow. Для части персональных commerce-методов нужно одновременно передавать App Token и Counterparty Bearer. ### Backend introspection ``` Authorization: Basic Content-Type: application/x-www-form-urlencoded ``` Тело: ``` token=&audience= ``` `client_secret` хранится только на backend. `client_id` должен быть UUID. ### Bearer и серверные credentials непрозрачны Используйте `access_token.value` целиком. Не разбирайте Sanctum-токен по разделителю, не извлекайте внутренний ID и не логируйте значение. `client_secret` также не должен покидать backend. Запрещено передавать Bearer и серверные credentials: - в URL или query; - в analytics/error tracking; - в публичном исходном коде; - в скриншотах и issue; - между ERP и Counterparty guards. ================================================================ 4. Project, Application и пользователи ================================================================ - `Project` — граница данных и доступа. - `Application` — конфигурация сайта или приложения внутри Project. - `Branch` — операционная единица внутри Project. - `User` — внутренний сотрудник. - `Counterparty` — внешний клиент/контрагент. Application и Counterparty должны относиться к одному Project. Для scoped клиентских токенов backend дополнительно проверяет Application. Несовпадение может возвращаться как 404, чтобы не раскрывать чужой ресурс. ================================================================ 5. Успешные ответы ================================================================ Успех — документированный `2xx`, а не код, угаданный по методу. В backend встречаются: - `200` с Resource на create/update; - явно заданный `201` на некоторых create; - `200` с `{ "message": "..." }` на delete; - другие коды для специальных операций. Правила клиента: 1. Использовать код из карточки метода. 2. Если карточка разрешает диапазон, принимать `2xx`. 3. Не парсить тело у `204`. 4. Не считать POST автоматически `201`. 5. Не считать DELETE автоматически `204`. Wrapper ответа также endpoint-specific. Например: - `GET /api/storage_units` → `units`, `unitsCount`; - `GET /api/counterparty/payment_types` → `paymentTypes`, `paymentTypesCount`; - `GET /api/user` → `user`; - `GET /api/counterparty` → `counterparty`. Не вычисляйте wrapper из пути. ================================================================ 6. Ошибки ================================================================ Типичные тела: 401 Bearer: ```json {"message":"Unauthenticated."} ``` 401 App Token: ```json {"message":"Application token is missing"} ``` 422 Form Request: ```json { "message":"The given data was invalid.", "errors":{"field":["Сообщение"]} } ``` `message` может отсутствовать. Вложенные поля используют ключи `products.0.id`. Реакция: - 400: исправить flow/состояние, без автоматического повтора; - 401: удалить невалидную сессию и выполнить вход; - 403: проверить permission/scope/ability; - 404: проверить path, Project и Application; не перебирать ID; - 409: получить актуальное состояние и разрешить конфликт; - 415: исправить Content-Type; - 422: обработать `errors` или бизнес-ограничение; - 429: использовать `Retry-After`, backoff и jitter; - 5xx/timeout: GET можно ограниченно повторить; write сначала reconcile через GET. Не сопоставляйте ошибки по тексту сообщения: локаль и формулировка могут измениться. ================================================================ 7. Rate limits ================================================================ Лимиты endpoint-specific. Нет одного гарантированного значения для всего API. Текущие примеры: - `POST /api/login`: 5/min; - `POST /api/counterparty/login`: 5/min на Project+contact и 30/min на IP; - `POST /api/counterparty/send_password`: 3/hour на Project+contact и 20/hour на IP; - introspection: 60/min на IP и 300/min на backend-client; - heartbeat: 6/min на клиентскую сессию. Всегда проектируйте обработку 429 независимо от текущих чисел. ================================================================ 8. Повторы и идемпотентность ================================================================ Общего публичного `Idempotency-Key` нет. - GET: ограниченный retry с exponential backoff. - POST создания/оплаты/подписки: не повторять вслепую. - PUT/PATCH: повторять только при явно идемпотентной семантике метода. - DELETE: не считать глобально идемпотентным. После timeout/5xx write-операции: 1. сохранить correlation/business ID; 2. получить состояние через GET; 3. только затем решить, нужен ли повтор. UI должен блокировать двойное нажатие на операции, создающие деньги или ресурсы. ================================================================ 9. Справочники ================================================================ ID справочников динамичны. Получайте list endpoint и кэшируйте `id → object`. Критические пути: ERP Bearer: - `/api/order_statuses` - `/api/counterparty_types` - `/api/roles` - `/api/permissions` - `/api/screens` - `/api/branches` - `/api/categories` - `/api/nomenclature_types` - `/api/nomenclature_kinds` - `/api/storage_units` - `/api/vats` - `/api/file_types` - `/api/page_types` App Token: - `/api/counterparty/payment_types` - `/api/counterparty/delivery_types` - `/api/counterparty/categories` - `/api/counterparty/brands` - `/api/counterparty/countries` - `/api/counterparty/dictionaries` - `/api/counterparty/page_types` Пути `/api/units` нет. Используйте `/api/storage_units`. Не хардкодьте: - role/status/type IDs; - пропущенные IDs; - seed как production-контракт; - UI color/tone как доменный enum. OpenAPI использует `x-gigma-dictionary` и не публикует снимки ID как `enum`. ================================================================ 10. Форматы данных ================================================================ Точные типы берите из карточки поля/OpenAPI. - Date обычно `YYYY-MM-DD`. - Date-time парсите как ISO 8601 с timezone. - Decimal-string не преобразовывайте в binary float без причины. - Boolean в новых полях `true/false`; legacy может вернуть `0/1`. - `null` и отсутствие поля — разные состояния. - Новые необязательные поля в JSON не должны ломать клиента. Пагинация и фильтры не унифицированы глобально. Не отправляйте `page`, `per_page`, `query` или date filters, если они не описаны у метода. ================================================================ 11. Introspection собственного backend ================================================================ Запрос: ```bash curl --request POST \ --url https://api.gigma.ru/api/counterparty/auth/introspect \ --user ':' \ --header 'Accept: application/json' \ --header 'Content-Type: application/x-www-form-urlencoded' \ --data-urlencode 'token=' \ --data-urlencode 'audience=' ``` Активный ответ содержит: - `active: true`; - `principal_handle`; - `project.id`; - `application.id` и `application.name`; - `scopes`; - `expires_at`. Невалидный токен возвращает только: ```json {"active":false} ``` Неверный audience → 403. Неверный Content-Type → 415. Передача `token` или `audience` в query → 422. Backend продукта должен создавать собственную локальную сессию по `principal_handle`, а не использовать phone/email как стабильный subject. ================================================================ 12. Webhook ================================================================ Поддерживаемое публичное событие: `order.paid`. Headers: ``` X-Webhook-Event X-Webhook-Event-Id X-Webhook-Delivery-Id X-Webhook-Timestamp X-Signature: sha256= ``` Подпись: ``` HMAC_SHA256(secret, timestamp + "." + raw_body) ``` Получатель: 1. проверяет возраст timestamp; 2. проверяет HMAC constant-time; 3. дедуплицирует event/delivery ID; 4. сохраняет событие транзакционно; 5. возвращает 2xx до timeout. Redirect отключён. Timeout 10 секунд. Retry delays: 1, 5, 30, 120, 720 минут. После исчерпания доставка `failed`. ================================================================ 13. OpenAPI и LLM-слой ================================================================ - `/openapi.json`: методы и схемы из карточек endpoint; - `/api-docs/`: Swagger UI; - `/llms.txt`: индекс; - `/llms-full.txt`: полный корпус; - `/conventions/`: человекочитаемые общие правила; - `/enums/`: живые справочники. Генератор OpenAPI намеренно: - не выводит ID справочников как enum; - не угадывает 201/204 по HTTP-методу; - использует `2XX`, если точный success code не указан; - считает Bearer непрозрачным; - использует server `https://api.gigma.ru`, потому что paths уже включают `/api`. ### Как агенту читать openapi.json Спецификация собирается из ручных карточек, поэтому отсутствие данных в ней означает «не зафиксировано», а не «запрещено». Правила чтения: - `2XX` в `responses` — точный код не подтверждён карточкой. Принимайте любой 2xx и определяйте наличие тела по факту, а не по коду. - Нет `requestBody` — это не доказательство, что тело не нужно. Часть карточек не описывает тело. Перед write-запросом откройте карточку метода по `externalDocs.url`. - `requestBody.description` со ссылкой на POST — схема унаследована от метода создания, потому что карточка обновления описывает тело фразой «те же поля». Список `required` там намеренно отсутствует и не должен считаться подтверждением необязательности. - `x-gigma-dictionary` у поля — значение берите из перечисленных list endpoint, а не из `example`. - `example` — иллюстрация из карточки, а не допустимый диапазон значений. Секреты в примерах заменены на плейсхолдеры. - `description` вложенного поля может быть унаследован от одноимённого поля верхнего уровня и иногда описывает не тот объект. Тип и структура надёжны, текст описания вложенного поля — нет. - `security` перечисляет схемы, которые нужно передать одновременно, если их в требовании несколько. - Ошибки в `responses` перечислены только для тех методов, где карточка их фиксирует. Клиент обязан обрабатывать весь набор из раздела 6 независимо от того, что перечислено у метода. Перед релизом SDK сравнивайте новый OpenAPI с зафиксированной версией и проверяйте критические flows контрактными тестами.