16 KiB
Документация API
Справочник эндпоинтов для бэкофиса маркетплейса.
Базовый URL: https://your-api-domain.com/api
🇬🇧 English documentation: API.md
Проекты
Получить все проекты
GET /api/projects
Ответ 200:
[
{
"id": "dexar",
"name": "dexar",
"displayName": "Dexar Marketplace",
"active": true,
"logoUrl": "https://..."
}
]
Категории
Получить категории проекта
GET /api/projects/:projectId/categories
Ответ 200:
[
{
"id": "cat1",
"name": "Электроника",
"visible": true,
"priority": 1,
"img": "https://...",
"projectId": "dexar",
"subcategories": [ ...Subcategory[] ],
"translations": {
"ru": { "name": "Электроника" }
}
}
]
Получить категорию по ID
GET /api/categories/:categoryId
Ответ 200: (объект категории с вложенными подкатегориями)
Создать категорию
POST /api/projects/:projectId/categories
Тело запроса:
{
"name": "Новая категория", // обязательно
"visible": true,
"priority": 10,
"img": "https://...",
"translations": { // опционально
"ru": { "name": "Новая категория" }
}
}
Ответ 201: (созданный объект категории)
Обновить категорию
PATCH /api/categories/:categoryId
Тело запроса: (любое подмножество полей)
{
"name": "Обновлённое название",
"visible": false,
"priority": 5,
"translations": {
"ru": { "name": "Обновлённое название" }
}
}
Ответ 200: (обновлённый объект категории)
Удалить категорию
DELETE /api/categories/:categoryId
Ответ 204 No Content
Примечание: каскадно удаляет все подкатегории и товары внутри
Подкатегории
Подкатегории рекурсивны — вложенность неограничена. Единственное ограничение: подкатегория с товарами не может иметь дочерних подкатегорий (и наоборот).
Объект подкатегории
{
"id": "sub1",
"name": "Смартфоны",
"visible": true,
"priority": 1,
"img": "https://...",
"categoryId": "cat1", // всегда ID корневой категории
"parentId": "cat1", // ID прямого родителя (категория или подкатегория)
"itemCount": 15,
"hasItems": true,
"subcategories": [], // дочерние подкатегории (пусто, если hasItems = true)
"translations": {
"ru": { "name": "Смартфоны" }
}
}
categoryId— всегда ID корневой категории этого поддерева.
parentId— ID прямого родителя: может быть ID категории или подкатегории.
Получить подкатегории категории
GET /api/categories/:categoryId/subcategories
Ответ 200: Subcategory[] (вложенные подкатегории рекурсивно заполнены)
Получить подкатегорию по ID
GET /api/subcategories/:subcategoryId
Ответ 200: объект подкатегории (с вложенными подкатегориями при наличии)
Создать подкатегорию в категории (уровень 1)
POST /api/categories/:categoryId/subcategories
Тело запроса:
{
"id": "custom-id", // опционально, генерируется автоматически (используется в URL)
"name": "Смартфоны", // обязательно
"visible": true,
"priority": 10,
"translations": {
"ru": { "name": "Смартфоны" }
}
}
Ответ 201: (созданный объект подкатегории)
Ошибка 400: если категория не существует
Создать подкатегорию в подкатегории (уровень 2+, вложенная)
POST /api/subcategories/:parentSubcategoryId/subcategories
Тело запроса:
{
"id": "custom-id", // опционально
"name": "Apple", // обязательно
"visible": true,
"priority": 10
}
Ответ 201: (созданный объект подкатегории)
Ошибка 400: если родительская подкатегория содержит товары (hasItems = true)
Ошибка 404: если родительская подкатегория не найдена
Обновить подкатегорию
PATCH /api/subcategories/:subcategoryId
Тело запроса: (любое подмножество полей)
{
"id": "new-slug", // ID редактируется — используется в URL маркетплейса
"name": "Новое название",
"visible": false,
"priority": 3,
"translations": {
"ru": { "name": "Новое название" }
}
}
Ответ 200: (обновлённый объект подкатегории)
Удалить подкатегорию
DELETE /api/subcategories/:subcategoryId
Ответ 204 No Content
Примечание: каскадно удаляет все вложенные подкатегории и товары
Товары
Товары всегда принадлежат самой глубокой подкатегории в иерархии (листовой узел).
Подкатегория с хотя бы одним товаром имеет hasItems: true и не может принимать дочерние подкатегории.
Получить товары (с пагинацией)
GET /api/subcategories/:subcategoryId/items
Query-параметры:
page number (по умолчанию: 1)
limit number (по умолчанию: 20)
search string опционально — фильтр по названию (без учёта регистра)
visible boolean опционально — фильтр по видимости
tags string опционально — теги через запятую
lang string опционально — код языка (en | ru); влияет на поля names/descriptions в ответе
Ответ 200:
{
"items": [
{
"id": "item1",
"name": "iPhone 15 Pro",
"visible": true,
"priority": 1,
"quantity": 50,
"price": 1299,
"currency": "USD",
"imgs": ["https://...", "https://..."],
"tags": ["new", "featured"],
"badges": ["new", "exclusive"],
"simpleDescription": "Последний iPhone...",
"description": [
{ "key": "Цвет", "value": "Чёрный" },
{ "key": "Память", "value": "256 ГБ" }
],
"subcategoryId": "sub1",
"translations": {
"ru": {
"name": "iPhone 15 Pro",
"simpleDescription": "Последний iPhone с корпусом из титана",
"description": [
{ "key": "Цвет", "value": "Чёрный" },
{ "key": "Память", "value": "256 ГБ" }
]
}
},
"comments": [
{
"id": "c1",
"text": "Отличный товар!",
"author": "Иван",
"stars": 5,
"createdAt": "2024-01-10T10:30:00Z"
}
]
}
],
"total": 150,
"page": 1,
"limit": 20,
"hasMore": true
}
Получить товар по ID
GET /api/items/:itemId
Query-параметры:
lang string опционально (en | ru)
Ответ 200: (полный объект товара)
Создать товар
POST /api/subcategories/:subcategoryId/items
Тело запроса:
{
"name": "Новый товар", // обязательно
"visible": true,
"priority": 10,
"quantity": 100,
"price": 999,
"currency": "USD", // USD | EUR | RUB | GBP | UAH
"imgs": ["https://..."],
"tags": ["new"],
"badges": ["new", "exclusive"], // опционально — стандартные или свои метки
"simpleDescription": "Краткое описание",
"description": [
{ "key": "Размер", "value": "Большой" }
],
"translations": { // опционально
"ru": {
"name": "Новый товар",
"simpleDescription": "Краткое описание",
"description": [
{ "key": "Размер", "value": "Большой" }
]
}
}
}
Ответ 201: (созданный объект товара)
Побочный эффект: устанавливает hasItems = true на подкатегории.
Подкатегория больше не может принимать дочерние подкатегории.
Обновить товар
PATCH /api/items/:itemId
Тело запроса: (любое подмножество полей)
{
"name": "Новое название",
"price": 899,
"quantity": 80,
"visible": false,
"translations": {
"ru": { "name": "Новое название" }
}
}
Ответ 200: (обновлённый объект товара)
Обновление изображений — всегда передавай полный массив:
PATCH /api/items/:itemId
Тело запроса:
{
"imgs": ["https://new1.jpg", "https://new2.jpg"]
}
Ответ 200: (обновлённый объект товара)
Удалить товар
DELETE /api/items/:itemId
Ответ 204 No Content
Побочный эффект: если в подкатегории не осталось товаров — hasItems становится false.
Подкатегория снова может принимать дочерние подкатегории.
Массовое обновление товаров
PATCH /api/items/bulk
Тело запроса:
{
"itemIds": ["item1", "item2", "item3"],
"data": {
"visible": true
}
}
Ответ 204 No Content
Загрузка файлов
Загрузить изображение
POST /api/upload
Тело запроса: multipart/form-data
image: File
Ответ 201:
{
"url": "https://cdn.example.com/uploads/abc123.jpg"
}
Мультиязычность (i18n)
Поля name, simpleDescription и description поддерживают переводы через объект translations.
Структура объекта переводов
{
"translations": {
"ru": {
"name": "Название на русском",
"simpleDescription": "Описание на русском",
"description": [
{ "key": "Ключ", "value": "Значение" }
]
}
}
}
Основные поля (
name,simpleDescription,description) хранятся на английском (по умолчанию).
Переводы хранятся вtranslations[langCode].*.
Запрос конкретного языка
Передай параметр ?lang=ru в GET-запросах. Бэкенд должен:
- Вернуть
translations.ru.*там, где перевод заполнен. - Откатиться к основному полю (английскому), если перевод отсутствует.
GET /api/items/:itemId?lang=ru
GET /api/subcategories/:subcategoryId/items?lang=ru&page=1
Альтернативно — заголовок Accept-Language: ru.
Поддерживаемые языки
| Код | Язык |
|---|---|
| en | Английский (по умолчанию) |
| ru | Русский |
Примечания
- Все ответы — JSON.
- Используй
PATCHдля частичного обновления — передавай только изменяемые поля. priority: меньшее число — выше в списке.- Поддерживаемые значения
currency:USD,EUR,RUB,GBP,UAH. badges: необязательный массив строк. Стандартные значения с цветами в интерфейсе:new,sale,exclusive,hot,limited,bestseller,featured. Свои строки тоже допустимы.imgs: при обновлении всегда передавай полный массив, не отдельные изображения.description: массив пар{ key, value }— свободные атрибуты товара.- Автосохранение из бэкофиса отправляет
PATCHс одним полем каждые ~500 мс.
Бизнес-правила
Вложенные подкатегории
Иерархия выглядит так:
Категория (напр. Электроника)
Подкатегория L1 (напр. Кухня) <- можно добавлять детей ИЛИ товары, не оба
Подкатегория L2 (напр. Большая кухня) <- то же правило
Подкатегория L3 (напр. Духовки) <- если есть товары — это листовой узел
Товары...
Правила:
- Категория всегда может принимать новые подкатегории (категории никогда не хранят товары напрямую).
- Подкатегория с товарами (
hasItems: true) не может принимать дочерние подкатегории.POST /api/subcategories/:id/subcategoriesна узел сhasItems: true→400 Bad Request.
- Подкатегория с дочерними подкатегориями не может принимать товары (товары только в листовых узлах).
- При создании первого товара в подкатегории →
hasItemsстановитсяtrue. - При удалении последнего товара →
hasItemsстановитсяfalse; дочерние подкатегории снова можно добавлять.
Структура URL (фронтенд маркетплейса)
Поля id подкатегорий и товаров используются напрямую в URL маркетплейса:
/{categoryId}/{sub1Id}/{sub2Id}/.../{itemId}
Примеры:
/electronics/smartphones/iphone-15
/electronics/smartphones/apple/iphone-15-pro
/furniture/living-room/sofas/corner-sofa-modelo
Поле id подкатегорий редактируется через PATCH для переименования слагов.
Комментарии
stars— опционально, целое число от 1 до 5.author— опционально (анонимные комментарии допустимы).createdAt— строка в формате ISO 8601.
Каскадное удаление
| Удаляемый объект | Также удаляется |
|---|---|
| Категория | все подкатегории (рекурсивно) и их товары |
| Подкатегория | все вложенные подкатегории (рекурсивно) и их товары |
| Товар | ничего больше |