{
    "openapi": "3.1.0",
    "info": {
        "title": "Seller Moon API",
        "version": "v1",
        "description": "Публичный API Seller Moon: запуск инструментов маркетплейсов и получение их результатов.\n\nАвторизация: заголовок `Authorization: Bearer <ключ>`. Ключ выпускается в настройках профиля\nи действует год.\n\nУ каждого инструмента свой путь — например `/api/v1/tools/product-parsing/tasks`.\nПолный список путей приведён в этой спецификации.\n\nИнструменты работают асинхронно. Сценарий интеграции:\n1. POST на путь инструмента — вернёт `task_id`.\n2. GET на тот же путь с `task_id` в конце, раз в 5–10 секунд.\n3. Задача готова, когда `status` = `completed`; результат лежит в `result`.\n   При `status` = `failed` разбор причины — в поле `error`.\n\nОграничение частоты: 60 запросов в минуту на ключ."
    },
    "externalDocs": {
        "description": "Документация API на сайте",
        "url": "https://sellermoon.ru/api/docs"
    },
    "servers": [
        {
            "url": "https://sellermoon.ru"
        }
    ],
    "security": [
        {
            "bearerAuth": []
        }
    ],
    "paths": {
        "/api/v1/account": {
            "get": {
                "operationId": "account_info",
                "summary": "Тариф и лимиты аккаунта",
                "description": "Возвращает текущий тариф владельца ключа API, объём лимитов тарифа за базовый период и остаток доступных лимитов. Единственный метод, доступный на базовом тарифе.",
                "tags": [
                    "Аккаунт"
                ],
                "parameters": [],
                "responses": {
                    "200": {
                        "description": "Успешный ответ",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Account"
                                },
                                "example": {
                                    "success": true,
                                    "tariff": "Professional",
                                    "tariff_limits": 200000,
                                    "limits_available": 154320,
                                    "error": null
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "`unauthorized` — Ключ API не передан или неверен.\n`api_key_expired` — Срок действия ключа API истёк. Перевыпустите ключ в настройках профиля.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "`rate_limit_exceeded` — Превышена допустимая частота запросов.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "500": {
                        "description": "`internal_error` — Внутренняя ошибка сервиса.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/v1/tools/product-parsing/tasks": {
            "post": {
                "operationId": "tool_task_create_product_parsing",
                "summary": "Создание задачи инструмента — Парсинг карточки товара",
                "description": "Ставит в очередь задачу инструмента, указанного в адресе запроса. Тело запроса зависит от инструмента: у каждого своя схема. Задача выполняется асинхронно: метод возвращает идентификатор, результат забирается методом получения задачи.",
                "tags": [
                    "Инструменты"
                ],
                "parameters": [],
                "responses": {
                    "201": {
                        "description": "Успешный ответ",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/TaskCreated"
                                },
                                "example": {
                                    "success": true,
                                    "task_id": 1024,
                                    "created_at": "2026-09-07T18:30:00+03:00",
                                    "error": null
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "`validation_failed` — Параметры запроса не прошли валидацию.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "`unauthorized` — Ключ API не передан или неверен.\n`api_key_expired` — Срок действия ключа API истёк. Перевыпустите ключ в настройках профиля.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "`tariff_required` — Доступ к API требует платного тарифа.\n`limits_exhausted` — Недостаточно лимитов для выполнения запроса.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "`not_found` — Запрошенный ресурс не найден.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "409": {
                        "description": "`concurrent_tasks_limit` — Превышено количество одновременно выполняемых задач.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "`rate_limit_exceeded` — Превышена допустимая частота запросов.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "500": {
                        "description": "`internal_error` — Внутренняя ошибка сервиса.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                },
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "url": {
                                        "type": "string",
                                        "description": "Адрес карточки товара на Wildberries или OZON.\n- https://www.wildberries.ru/catalog/123456789/detail.aspx — Wildberries, где 123456789 — артикул товара\n- https://www.ozon.ru/product/nazvanie-tovara-123456789/ — OZON, где 123456789 — идентификатор товара",
                                        "examples": [
                                            "https://www.wildberries.ru/catalog/123456789/detail.aspx",
                                            "https://www.ozon.ru/product/nazvanie-tovara-123456789/"
                                        ]
                                    },
                                    "contents": {
                                        "type": "array",
                                        "description": "Что забрать из карточки. Можно указать несколько значений.\n- card-images — фотографии карточки товара\n- card-videos — видео карточки товара\n- review-list — отзывы: текст, оценка, дата, автор\n- review-images — фотографии из отзывов\n- review-videos — видео из отзывов",
                                        "items": {
                                            "type": "string",
                                            "enum": [
                                                "card-images",
                                                "card-videos",
                                                "review-list",
                                                "review-images",
                                                "review-videos"
                                            ]
                                        },
                                        "minItems": 1
                                    },
                                    "review_variant_mode": {
                                        "type": "string",
                                        "description": "Из каких вариантов товара брать отзывы. По умолчанию `all`.\n- all — из всех вариантов товара\n- current — только из варианта, указанного в адресе",
                                        "default": "all",
                                        "enum": [
                                            "all",
                                            "current"
                                        ]
                                    }
                                },
                                "additionalProperties": false,
                                "required": [
                                    "url",
                                    "contents"
                                ]
                            },
                            "example": {
                                "url": "https://www.wildberries.ru/catalog/123456789/detail.aspx",
                                "contents": [
                                    "card-images",
                                    "review-list"
                                ],
                                "review_variant_mode": "all"
                            }
                        }
                    }
                }
            }
        },
        "/api/v1/tools/product-parsing/tasks/{task}": {
            "get": {
                "operationId": "tool_task_result_product_parsing",
                "summary": "Результат задачи инструмента — Парсинг карточки товара",
                "description": "Возвращает текущее состояние задачи и её результат. Пока задача не завершена, поле result пустое, а progress показывает процент выполнения. Состав result зависит от инструмента: у каждого своя схема ответа. Доступны только задачи, созданные владельцем ключа API.",
                "tags": [
                    "Инструменты"
                ],
                "parameters": [
                    {
                        "name": "task",
                        "in": "path",
                        "required": true,
                        "description": "Идентификатор задачи из ответа метода создания — поле `task_id`. Передаётся в адресе запроса.",
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Успешный ответ",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/TaskResultProductParsing"
                                },
                                "example": {
                                    "success": true,
                                    "task_id": 1024,
                                    "tool": "product-parsing",
                                    "status": "completed",
                                    "progress": 100,
                                    "cost": 15,
                                    "created_at": "2026-09-07T18:30:00+03:00",
                                    "finished_at": "2026-09-07T18:31:12+03:00",
                                    "result": {
                                        "article": "123456789",
                                        "product_name": "Кроссовки мужские",
                                        "card_images": [
                                            "https://basket-12.wbbasket.ru/vol1234/part123456/123456789/images/big/1.webp"
                                        ],
                                        "card_videos": [],
                                        "feedbacks": [
                                            {
                                                "name": "Иван",
                                                "date": "05.09.2026 12:30",
                                                "stars": 5,
                                                "variant": "42, чёрный",
                                                "text": "Отличные кроссовки, размер в размер.",
                                                "pros": "Удобные",
                                                "cons": "",
                                                "photos": [],
                                                "videos": []
                                            }
                                        ],
                                        "feedbacks_photos": [],
                                        "feedbacks_videos": []
                                    },
                                    "error": null
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "`unauthorized` — Ключ API не передан или неверен.\n`api_key_expired` — Срок действия ключа API истёк. Перевыпустите ключ в настройках профиля.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "`tariff_required` — Доступ к API требует платного тарифа.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "`not_found` — Запрошенный ресурс не найден.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "`rate_limit_exceeded` — Превышена допустимая частота запросов.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "500": {
                        "description": "`internal_error` — Внутренняя ошибка сервиса.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            }
        }
    },
    "components": {
        "securitySchemes": {
            "bearerAuth": {
                "type": "http",
                "scheme": "bearer",
                "description": "Ключ API из настроек профиля Seller Moon."
            }
        },
        "schemas": {
            "TaskCreated": {
                "type": "object",
                "properties": {
                    "success": {
                        "type": "boolean",
                        "const": true
                    },
                    "task_id": {
                        "type": "integer",
                        "description": "Идентификатор созданной задачи."
                    },
                    "created_at": {
                        "type": "string",
                        "format": "date-time"
                    },
                    "error": {
                        "type": "null"
                    }
                },
                "required": [
                    "success",
                    "task_id"
                ]
            },
            "TaskResult": {
                "type": "object",
                "properties": {
                    "success": {
                        "type": "boolean",
                        "const": true
                    },
                    "task_id": {
                        "type": "integer"
                    },
                    "tool": {
                        "type": "string",
                        "description": "Slug инструмента."
                    },
                    "status": {
                        "type": "string",
                        "enum": [
                            "pending",
                            "running",
                            "completed",
                            "failed"
                        ],
                        "description": "Результат готов при значении completed."
                    },
                    "progress": {
                        "type": "integer",
                        "minimum": 0,
                        "maximum": 100
                    },
                    "cost": {
                        "type": "integer",
                        "description": "Списанные лимиты."
                    },
                    "created_at": {
                        "type": "string",
                        "format": "date-time"
                    },
                    "finished_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date-time"
                    },
                    "result": {
                        "type": [
                            "object",
                            "null"
                        ],
                        "description": "Состав зависит от инструмента. Пуст, пока задача не завершена."
                    },
                    "error": {
                        "$ref": "#/components/schemas/TaskError"
                    }
                },
                "required": [
                    "success",
                    "task_id",
                    "tool",
                    "status",
                    "progress"
                ]
            },
            "TaskError": {
                "type": [
                    "object",
                    "null"
                ],
                "description": "Заполняется, когда задача завершилась без результата.",
                "properties": {
                    "code": {
                        "type": "string",
                        "enum": [
                            "task_failed",
                            "task_cancelled",
                            "task_suspended",
                            "empty_result"
                        ]
                    },
                    "message": {
                        "type": "string"
                    }
                }
            },
            "Account": {
                "type": "object",
                "properties": {
                    "success": {
                        "type": "boolean",
                        "const": true
                    },
                    "tariff": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "Название текущего тарифа."
                    },
                    "tariff_limits": {
                        "type": "integer",
                        "description": "Лимиты тарифа за базовый период."
                    },
                    "limits_available": {
                        "type": "integer",
                        "description": "Остаток доступных лимитов."
                    },
                    "error": {
                        "type": "null"
                    }
                },
                "required": [
                    "success",
                    "tariff",
                    "tariff_limits",
                    "limits_available"
                ]
            },
            "Error": {
                "type": "object",
                "properties": {
                    "success": {
                        "type": "boolean",
                        "const": false
                    },
                    "error": {
                        "type": "object",
                        "properties": {
                            "code": {
                                "type": "string",
                                "enum": [
                                    "unauthorized",
                                    "api_key_expired",
                                    "tariff_required",
                                    "validation_failed",
                                    "limits_exhausted",
                                    "concurrent_tasks_limit",
                                    "rate_limit_exceeded",
                                    "not_found",
                                    "internal_error"
                                ]
                            },
                            "message": {
                                "type": "string"
                            },
                            "fields": {
                                "type": "object",
                                "description": "Ошибки валидации по полям запроса.",
                                "additionalProperties": {
                                    "type": "array",
                                    "items": {
                                        "type": "string"
                                    }
                                }
                            }
                        },
                        "required": [
                            "code",
                            "message"
                        ]
                    }
                },
                "required": [
                    "success",
                    "error"
                ]
            },
            "TaskResultProductParsing": {
                "allOf": [
                    {
                        "$ref": "#/components/schemas/TaskResult"
                    },
                    {
                        "type": "object",
                        "properties": {
                            "result": {
                                "type": [
                                    "object",
                                    "null"
                                ],
                                "description": "Данные карточки. Заполняется, когда status = completed.",
                                "properties": {
                                    "article": {
                                        "type": "string",
                                        "description": "Артикул товара на маркетплейсе."
                                    },
                                    "product_name": {
                                        "type": "string",
                                        "description": "Название товара из карточки."
                                    },
                                    "card_images": {
                                        "type": "array",
                                        "description": "Ссылки на фотографии карточки. Пуст, если card-images не запрошен.",
                                        "items": {
                                            "type": "string",
                                            "format": "uri"
                                        }
                                    },
                                    "card_videos": {
                                        "type": "array",
                                        "description": "Ссылки на видео карточки. Пуст, если card-videos не запрошен.",
                                        "items": {
                                            "type": "string",
                                            "format": "uri"
                                        }
                                    },
                                    "feedbacks": {
                                        "type": "array",
                                        "description": "Отзывы. Пуст, если review-list не запрошен.",
                                        "items": {
                                            "type": "object",
                                            "properties": {
                                                "name": {
                                                    "type": "string",
                                                    "description": "Имя автора отзыва."
                                                },
                                                "date": {
                                                    "type": "string",
                                                    "description": "Дата отзыва в формате ДД.ММ.ГГГГ ЧЧ:ММ."
                                                },
                                                "stars": {
                                                    "type": "integer",
                                                    "description": "Оценка от 1 до 5."
                                                },
                                                "variant": {
                                                    "type": "string",
                                                    "description": "Вариант товара, к которому оставлен отзыв."
                                                },
                                                "text": {
                                                    "type": "string",
                                                    "description": "Текст отзыва."
                                                },
                                                "pros": {
                                                    "type": "string",
                                                    "description": "Достоинства."
                                                },
                                                "cons": {
                                                    "type": "string",
                                                    "description": "Недостатки."
                                                },
                                                "photos": {
                                                    "type": "array",
                                                    "description": "Фотографии этого отзыва.",
                                                    "items": {
                                                        "type": "string",
                                                        "format": "uri"
                                                    }
                                                },
                                                "videos": {
                                                    "type": "array",
                                                    "description": "Видео этого отзыва.",
                                                    "items": {
                                                        "type": "string",
                                                        "format": "uri"
                                                    }
                                                }
                                            }
                                        }
                                    },
                                    "feedbacks_photos": {
                                        "type": "array",
                                        "description": "Все фотографии из отзывов одним списком. Пуст, если review-images не запрошен.",
                                        "items": {
                                            "type": "string",
                                            "format": "uri"
                                        }
                                    },
                                    "feedbacks_videos": {
                                        "type": "array",
                                        "description": "Все видео из отзывов одним списком. Пуст, если review-videos не запрошен.",
                                        "items": {
                                            "type": "string",
                                            "format": "uri"
                                        }
                                    }
                                }
                            }
                        }
                    }
                ]
            }
        }
    }
}