Initial commit

This commit is contained in:
2026-07-06 13:05:56 +03:00
commit 831c72dc60
28 changed files with 2527 additions and 0 deletions
@@ -0,0 +1,298 @@
# REST API — методы и примеры (richcode.api)
Полный справочник действий модуля `richcode.api` и примеры запросов. Составлено по исходникам контроллеров (`bitrix/modules/richcode.api/lib/*/controllers/*.php`) и ядра модуля (`lib/core/`). Обзор и настройки — в [[REST API (richcode.api)]].
## Содержание
- URL-схема
- Авторизация и фильтры
- Формат ответа
- Справочник действий (по контроллерам)
- Примеры запросов
- Точные схемы (проверено по моделям)
## URL-схема
```
/{apiPath}/{module}/{token}/{controller}/{action}
```
- `apiPath` — базовый путь, по умолчанию `api` (модуль срабатывает, если первый сегмент URL равен ему — из `Init::checkPathApi`).
- `module` / `controller` — из карты в `lib/core/Init.php`: `iblock/element`, `sale/product|order|store|discount|measure`, `main/user`, `crm/deal`.
- `token` — сегмент URL с токеном (если включена авторизация).
- `action`**оставшиеся сегменты пути после контроллера, склеенные точкой**. Поэтому `.../element/section/add` → действие `section.add`, `.../order/status/set``status.set`.
- Параметры: для GET — query-строка; для POST/PUT/DELETE — тело JSON (`Content-Type: application/json`) или form-data.
## Авторизация и фильтры
Проверки идут по порядку (`Init::checkFilters`): **токен → только HTTPS → IP-список → группа пользователя**. Любая непройденная — ответ `403`.
- Токен берётся из **сегмента URL** и ищется в поле пользователя **`UF_API_TOKEN`** (`Tokens::checkToken`). Запрос выполняется **от имени этого пользователя** — его правами и ограничен.
- Пользователь-владелец токена должен состоять в группе, заданной в настройках модуля (`Config::getGroupId()`).
- Формат токена: `xxxxxxxx-xxxxxxxx-xxxxxxxx-xxxxxxxx` (например `b2b23c2b-8df82f85-256913d3-ff261962`), генерируется в настройках модуля.
> [!warning] Расхождения, которые собьют с толку
> - В подсказке настроек модуля поле названо `UF_RESTFUL_API_TOKEN`, но в коде используется **`UF_API_TOKEN`**. Верно то, что в коде.
> - Та же подсказка предлагает передавать токен заголовком `Authorization-Token`, но рабочий код (`Route`+`Init`) читает токен **из сегмента URL**, а не из заголовка. Заголовок лишь разрешён в CORS. Используйте токен в URL.
> - Токен в URL попадёт в логи веб-сервера и в собственный лог модуля (HL-блок). Это чувствительно — см. [[Информационная безопасность (apelsincom)]].
## Формат ответа
Всегда JSON `{"status", "result"}` (из `lib/core/Response.php`):
- Успех — HTTP 200: `{"status":200,"result": <данные>}`.
- Бизнес-ошибка — HTTP 400: `{"status":400,"result":{"type":"error","message":"..."}}`.
- Отказ фильтра (нет токена / не HTTPS / чужой IP / не та группа) — HTTP 403: `{"status":403,"result":{"type":"error","message":"Forgbiden"}}` (опечатка в исходнике сохранена как есть).
## Справочник действий
### iblock / element (и sale / product — те же действия, но по товарам каталога)
| Действие (URL) | Параметры | Что делает |
|---|---|---|
| `add` | поля элемента | создать элемент, вернуть ID |
| `update` | `ID` + поля | обновить элемент |
| `delete` | `ID` | удалить |
| `get` | `ID` | элемент по ID |
| `list` | фильтр/выборка | список элементов |
| `fields` | — | доступные поля элемента |
| `property.list` | (`IBLOCK_ID`) | список свойств инфоблока |
| `property.get` | `ID` | свойство по ID |
| `property.enumeration.fields` | параметры свойства | значения списочного свойства |
| `property.add` / `property.update` | поля свойства | создать/изменить свойство |
| `property.enumeration.add` / `.update` | поля | значения списочного свойства |
| `property.add.group` / `property.update.group` / `property.enumeration.add.group` / `property.enumeration.update.group` | `fields[]` | групповые операции |
| `section.add` / `section.update` | поля раздела | создать/изменить раздел |
| `section.update.group` | `fields[]` | групповое изменение разделов |
| `section.list` | фильтр | список разделов |
| `section.get` | `ID` | раздел по ID |
| `section.property.list` | `IBLOCK_ID` | свойства раздела |
| `section.property.enumeration.fields` | — | значения свойств раздела |
| `update.group` | `fields[]` | групповое обновление элементов |
| `file.add` | файл | добавить файл |
| `measure.ratio.update` | параметры | коэффициент единицы измерения |
| `store.amount.get` / `store.amount.set` | параметры остатков | остатки товара по складам |
### sale / order
| Действие | Параметры | Что делает |
|---|---|---|
| `create` | поля заказа | создать заказ, вернуть ID |
| `get` | `ORDER_ID` | заказ по ID |
| `list` | фильтр | список заказов |
| `fields` | — | поля заказа |
| `basket` | `ORDER_ID` | состав корзины заказа |
| `status.list` | — | список статусов заказа |
| `status.set` | `ORDER_ID`, `STATUS_ID` | сменить статус |
| `cancel` / `uncancel` | `ORDER_ID` | отмена / снятие отмены |
| `payed` / `unpayed` | `ORDER_ID` | отметить оплаченным / нет |
| `delivery.status.list` | — | статусы доставки |
| `delivery.status.set` | `ORDER_ID`, `STATUS_ID` | статус доставки |
| `delivery.accept` / `delivery.decline` | `ORDER_ID` | принять / отклонить доставку |
| `shipment.accept` / `shipment.decline` | `ORDER_ID` | отгрузка |
| `payer.list` | — | типы плательщиков |
| `property.list` / `property.enum` | — | свойства заказа |
| `payment.list` / `delivery.list` | — | доступные оплаты / доставки |
### sale / store
| Действие | Параметры | Что делает |
|---|---|---|
| `add` | `fields` | создать склад |
| `update` | `fields` | изменить склад |
| `set.amount` | `PRODUCT_ID`, `STORE_ID`, кол-во | задать остаток |
| `set.amount.group` | `fields[]` | групповые остатки |
| `list` | — | список складов |
### sale / measure, sale / discount, main / user, crm / deal
| Контроллер | Действия |
|---|---|
| `sale/measure` | `add`, `update` (`fields.ID`), `delete` (`ID`), `list` |
| `sale/discount` | `add`, `update`, `delete` (`ID`), `list` |
| `main/user` | `list`, `add`, `update`, `delete` (`ID`), `fields` |
| `crm/deal` | `productrows.set` (задать товарные позиции сделки) |
## Примеры запросов
Ниже `https://<домен>` = адрес сайта, `<TOKEN>` = токен из `UF_API_TOKEN`, `apiPath` = `api`. Reads — через GET, writes — через POST (роутер разбирает параметры и там, и там; метод влияет только на способ передачи данных).
> [!warning] Каталог vs обычный инфоблок — разные контроллеры
> Проверено по моделям: **`iblock/element` работает только с НЕ-каталожными инфоблоками**, а для товаров и разделов **каталога (инфоблок 2) нужен `sale/product`** (те же действия). Перепутаете — получите ошибку «Инфоблок с указанным ID не найден». Поэтому примеры для каталога ниже — на `sale/product`. И у `add`/`update`/`section.*` тело обёрнуто в ключ **`fields`** (у `order/create` — нет). Полные схемы — в разделе «Точные схемы».
**Доступные поля элемента:**
```bash
curl "https://<домен>/api/iblock/<TOKEN>/element/fields"
```
**Получить товар каталога по ID:**
```bash
curl "https://<домен>/api/sale/<TOKEN>/product/get?ID=123"
# → {"status":200,"result":{ ...поля товара... }}
```
**Список товаров каталога:**
```bash
curl "https://<домен>/api/sale/<TOKEN>/product/list?filter[IBLOCK_ID]=2"
```
**Создать товар каталога (инфоблок 2):**
```bash
curl -X POST "https://<домен>/api/sale/<TOKEN>/product/add" \
-H "Content-Type: application/json" \
-d '{"fields":{
"IBLOCK_ID": 2,
"NAME": "Кроссовки Модель X",
"CODE": "krossovki-model-x",
"ACTIVE": "Y",
"PRICE": 4990,
"CURRENCY": "RUB",
"QUANTITY": 10,
"PROPERTY_ARTNUMBER": "ART-001"
}}'
# → {"status":200,"result": <новый ID>}
```
**Создать элемент обычного (не каталог) инфоблока:**
```bash
curl -X POST "https://<домен>/api/iblock/<TOKEN>/element/add" \
-H "Content-Type: application/json" \
-d '{"fields":{"IBLOCK_ID":5,"NAME":"Новость","CODE":"novost","ACTIVE":"Y","PROPERTY_AUTHOR":"Редакция"}}'
```
**Обновить товар:**
```bash
curl -X POST "https://<домен>/api/sale/<TOKEN>/product/update" \
-H "Content-Type: application/json" \
-d '{"fields":{"ID": 123, "NAME": "Новое название", "PRICE": 5490}}'
```
**Удалить товар:**
```bash
curl -X POST "https://<домен>/api/sale/<TOKEN>/product/delete" \
-H "Content-Type: application/json" -d '{"ID": 123}'
```
**Разделы каталога:**
```bash
# список разделов
curl "https://<домен>/api/sale/<TOKEN>/product/section/list?filter[IBLOCK_ID]=2"
# создать раздел
curl -X POST "https://<домен>/api/sale/<TOKEN>/product/section/add" \
-H "Content-Type: application/json" \
-d '{"fields":{"IBLOCK_ID":2,"NAME":"Мужская обувь","CODE":"muzhskaya-obuv","ACTIVE":"Y"}}'
```
**Остатки на складе:**
```bash
curl -X POST "https://<домен>/api/sale/<TOKEN>/store/set/amount" \
-H "Content-Type: application/json" \
-d '{"PRODUCT_ID":123,"STORE_ID":1,"AMOUNT":10}'
```
**Заказы:**
```bash
# получить заказ
curl "https://<домен>/api/sale/<TOKEN>/order/get?ORDER_ID=1001"
# список заказов
curl "https://<домен>/api/sale/<TOKEN>/order/list"
# создать заказ (полная схема — в разделе «Точные схемы»)
curl -X POST "https://<домен>/api/sale/<TOKEN>/order/create" \
-H "Content-Type: application/json" \
-d '{"PERSON_TYPE_ID":1,"DELIVERY_ID":1,"PAYSYSTEM_ID":1,
"ITEMS":[{"PRODUCT_ID":412,"QUANTITY":1}],
"PROPERTIES":[{"ID":1,"VALUE":"Иван"}]}'
# сменить статус
curl -X POST "https://<домен>/api/sale/<TOKEN>/order/status/set" \
-H "Content-Type: application/json" -d '{"ORDER_ID":1001,"STATUS_ID":"F"}'
# отметить оплаченным
curl -X POST "https://<домен>/api/sale/<TOKEN>/order/payed" \
-H "Content-Type: application/json" -d '{"ORDER_ID":1001}'
```
**Пользователь:**
```bash
curl -X POST "https://<домен>/api/main/<TOKEN>/user/add" \
-H "Content-Type: application/json" -d '{ ...поля пользователя... }'
```
## Точные схемы (проверено по моделям)
Схемы ниже сверены по коду моделей (`lib/…/models/…`), а не по догадкам.
### Правило: каталог vs обычный инфоблок
- `iblock/element/*` — только **не-каталожные** инфоблоки (`add`, `list`, `get`, `section.*` внутренне исключают каталоги).
- `sale/product/*` — только **каталог** (инфоблок 2); те же действия, но модель работает с ценой, остатком и товарными полями.
- У `add` / `update` / `section.add` / `section.update` тело обёрнуто в ключ **`fields`** (плоская карта). Свойства элемента — с префиксом `PROPERTY_<КОД>`, поля раздела — `UF_<КОД>`.
### element/add — элемент обычного инфоблока
`POST /api/iblock/<TOKEN>/element/add`
```json
{ "fields": {
"IBLOCK_ID": 5,
"NAME": "Заголовок",
"CODE": "zagolovok",
"ACTIVE": "Y",
"SORT": 100,
"PREVIEW_TEXT": "…",
"DETAIL_TEXT": "…",
"IBLOCK_SECTION_ID": 12,
"PROPERTY_AUTHOR": "Редакция"
} }
```
Стандартные поля (`getAvailableElementFields`): `ID, IBLOCK_ID, IBLOCK_SECTION_ID, ACTIVE, XML_ID, DATE_ACTIVE_FROM, DATE_ACTIVE_TO, SORT, NAME, PREVIEW_PICTURE, PREVIEW_TEXT, DETAIL_PICTURE, DETAIL_TEXT, CODE`. Если `CODE` пуст, а в инфоблоке включён транслит — сгенерируется из `NAME`. Возвращает ID нового элемента. Каталог (ИБ 2) метод отклонит.
### sale/product/add — товар каталога (инфоблок 2)
`POST /api/sale/<TOKEN>/product/add`
```json
{ "fields": {
"IBLOCK_ID": 2,
"NAME": "Кроссовки Модель X",
"CODE": "krossovki-model-x",
"ACTIVE": "Y",
"IBLOCK_SECTION_ID": 15,
"PRICE": 4990,
"CURRENCY": "RUB",
"QUANTITY": 10,
"VAT_ID": 1,
"VAT_INCLUDED": "Y",
"MEASURE": 5,
"WEIGHT": 800,
"PROPERTY_ARTNUMBER": "ART-001",
"PROPERTY_MANUFACTURER": "Производитель"
} }
```
Помимо полей элемента поддерживаются товарные (`Product::getAvailableElementFields`): `PRICE, CURRENCY, QUANTITY, QUANTITY_RESERVED, VAT_ID, VAT_INCLUDED, MEASURE, EXTERNAL_ID, PURCHASING_PRICE, PURCHASING_CURRENCY, WIDTH, HEIGHT, LENGTH, WEIGHT`. Метод сам заводит товар в торговом каталоге и ставит базовую цену. Требует именно каталог.
### section.add — раздел
`POST /api/sale/<TOKEN>/product/section/add` (каталог) или `/api/iblock/<TOKEN>/element/section/add` (обычный ИБ)
```json
{ "fields": {
"IBLOCK_ID": 2,
"NAME": "Мужская обувь",
"CODE": "muzhskaya-obuv",
"SORT": 100,
"ACTIVE": "Y",
"IBLOCK_SECTION_ID": 0,
"UF_SHOW_IN_MENU": 1
} }
```
Поля раздела: `ID, IBLOCK_SECTION_ID, IBLOCK_ID, NAME, CODE, SORT, ACTIVE` + пользовательские `UF_*` (например `UF_SHOW_IN_MENU`, см. [[Инфоблоки и каталог (apelsincom)]]).
### order/create — заказ
`POST /api/sale/<TOKEN>/order/create` (**без** обёртки `fields`). Заказ создаётся на пользователя токена.
```json
{
"PERSON_TYPE_ID": 1,
"DELIVERY_ID": 1,
"PAYSYSTEM_ID": 1,
"ITEMS": [
{ "PRODUCT_ID": 412, "QUANTITY": 1 },
{ "PRODUCT_ID": 413, "QUANTITY": 4 }
],
"PROPERTIES": [
{ "ID": 1, "VALUE": "Иван" },
{ "ID": 5, "VALUE": ["Опция А", "Опция Б"] }
]
}
```
- `ITEMS[].PRODUCT_ID` — ID товара/предложения каталога, `QUANTITY` — количество. Корзина строится через провайдер `catalog`, валюта — базовая.
- `PROPERTIES[].ID` — ID свойства заказа (значения списков — из `order/property.list`), `VALUE` может быть массивом для множественных.
- `DELIVERY_ID` / `PAYSYSTEM_ID` — из `order/delivery.list` и `order/payment.list`; `PERSON_TYPE_ID` — из `order/payer.list`.
- Возвращает ID созданного заказа; при ошибке — 400 с текстом от `sale`.
### Остальные схемы — сверять в моделях
Для `store/set.amount`, `user/add`, `measure/*`, `discount/*` и свойств (`property.*`) точный формат — в `lib/sale/models/Store.php`, `Product/DmlStore.php`, `lib/main/models/User.php`, `lib/iblock/models/Element/DmlProperty.php`. Быстро узнать поля вживую: `…/product/fields`, `…/order/fields`, `…/user/fields`, `…/product/property/list?filter[IBLOCK_ID]=2`.
## См. также
- [[REST API (richcode.api)]]
- [[Сценарии. Товары и разделы]]
- [[Информационная безопасность (apelsincom)]]