{
    "openapi": "3.1.0",
    "info": {
        "title": "TavoCRM API",
        "version": "1.0.0",
        "description": "REST API для интеграций. Тенант определяется по поддомену, авторизация — Bearer-ключ (Настройки → Интеграции → Ключи доступа). У ключа можно задать права (scopes: orders:read/write, contacts:read/write, products:read) и привязку к магазинам: пустые — полный доступ ко всем магазинам; иначе доступ и выдача данных ограничены правами и магазинами ключа. Ключ привязывается к поверхностям REST API и/или MCP."
    },
    "servers": [
        {
            "url": "https://{tenant}.tavocrm.com/api/v1",
            "variables": {
                "tenant": {
                    "default": "acme",
                    "description": "Код арендатора (поддомен)"
                }
            }
        }
    ],
    "security": [
        {
            "bearerAuth": []
        }
    ],
    "tags": [
        {
            "name": "service",
            "description": "Служебные"
        },
        {
            "name": "orders",
            "description": "Заказы"
        },
        {
            "name": "contacts",
            "description": "Клиенты"
        },
        {
            "name": "products",
            "description": "Товары"
        }
    ],
    "paths": {
        "/ping": {
            "get": {
                "tags": [
                    "service"
                ],
                "summary": "Проверка ключа",
                "description": "Проверяет ключ и возвращает код арендатора.",
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "example": {
                                    "pong": true,
                                    "tenant": "acme"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Не авторизован",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/orders": {
            "get": {
                "tags": [
                    "orders"
                ],
                "summary": "Список заказов",
                "description": "Постранично, новые сверху. Фильтры status / contact_id / q взаимоисключающие (в этом приоритете), плюс custom[]. contact_id=false — заказы без клиента.",
                "parameters": [
                    {
                        "name": "status",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Код статуса"
                    },
                    {
                        "name": "contact_id",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string"
                        },
                        "description": "ID клиента (или false — без клиента)"
                    },
                    {
                        "name": "q",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Поиск по номеру / external_id"
                    },
                    {
                        "name": "custom",
                        "in": "query",
                        "style": "deepObject",
                        "explode": true,
                        "schema": {
                            "type": "object",
                            "additionalProperties": {
                                "type": "string"
                            }
                        },
                        "description": "Фильтр по кастомным полям: custom[код]=значение (false = пусто/нет значения)"
                    },
                    {
                        "name": "page",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "integer"
                        },
                        "description": "Страница (с 1)"
                    },
                    {
                        "name": "per_page",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "integer"
                        },
                        "description": "Размер страницы, ≤ 100"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "example": {
                                    "data": [
                                        {
                                            "id": 1043,
                                            "number": 1043,
                                            "status": "new",
                                            "contact_id": 12,
                                            "amount": 5080,
                                            "currency": "RUB",
                                            "paid_amount": 0,
                                            "items": [
                                                {
                                                    "product_id": 5,
                                                    "name": "Кроссовки",
                                                    "qty": 2,
                                                    "price": 2540,
                                                    "sum": 5080
                                                }
                                            ]
                                        }
                                    ],
                                    "page": 1,
                                    "pages": 7,
                                    "total": 312
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Не авторизован (нет/неверный ключ)",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "Недостаточно прав ключа (scope), запись вне магазинов ключа или ключ не привязан к этой поверхности (API/MCP)",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "Не найдено",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "Ошибка валидации",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            },
            "post": {
                "tags": [
                    "orders"
                ],
                "summary": "Создать заказ",
                "description": "В позиции достаточно product_id и qty — название и цена берутся из каталога.",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "contact_id",
                                    "items"
                                ],
                                "properties": {
                                    "contact_id": {
                                        "type": "integer",
                                        "description": "Существующий клиент (обязательно)"
                                    },
                                    "items": {
                                        "type": "array",
                                        "description": "Позиции (обязательно)",
                                        "items": {
                                            "type": "object",
                                            "properties": {
                                                "product_id": {
                                                    "type": "integer"
                                                },
                                                "qty": {
                                                    "type": "number"
                                                },
                                                "price": {
                                                    "type": "number"
                                                },
                                                "name": {
                                                    "type": "string"
                                                }
                                            }
                                        }
                                    },
                                    "status": {
                                        "type": "string",
                                        "description": "Код статуса; по умолчанию первый"
                                    },
                                    "shop_id": {
                                        "type": "integer"
                                    },
                                    "method": {
                                        "type": "string"
                                    },
                                    "currency": {
                                        "type": "string"
                                    },
                                    "paid_amount": {
                                        "type": "number"
                                    },
                                    "delivery_cost": {
                                        "type": "number"
                                    },
                                    "external_id": {
                                        "type": "string"
                                    }
                                }
                            },
                            "example": {
                                "contact_id": 12,
                                "items": [
                                    {
                                        "product_id": 5,
                                        "qty": 2
                                    }
                                ]
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Создан",
                        "content": {
                            "application/json": {
                                "example": {
                                    "data": {
                                        "id": 1043,
                                        "number": 1043,
                                        "status": "new",
                                        "contact_id": 12,
                                        "amount": 5080,
                                        "currency": "RUB",
                                        "paid_amount": 0,
                                        "items": [
                                            {
                                                "product_id": 5,
                                                "name": "Кроссовки",
                                                "qty": 2,
                                                "price": 2540,
                                                "sum": 5080
                                            }
                                        ]
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Не авторизован (нет/неверный ключ)",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "Недостаточно прав ключа (scope), запись вне магазинов ключа или ключ не привязан к этой поверхности (API/MCP)",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "Не найдено",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "Ошибка валидации",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/orders/{id}": {
            "get": {
                "tags": [
                    "orders"
                ],
                "summary": "Заказ по id",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        },
                        "description": "Идентификатор"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "example": {
                                    "data": {
                                        "id": 1043,
                                        "number": 1043,
                                        "status": "new",
                                        "contact_id": 12,
                                        "amount": 5080,
                                        "currency": "RUB",
                                        "paid_amount": 0,
                                        "items": [
                                            {
                                                "product_id": 5,
                                                "name": "Кроссовки",
                                                "qty": 2,
                                                "price": 2540,
                                                "sum": 5080
                                            }
                                        ]
                                    }
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "Не найдено",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Не авторизован",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/orders/{id}/status": {
            "post": {
                "tags": [
                    "orders"
                ],
                "summary": "Сменить статус",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        },
                        "description": "Идентификатор"
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "status"
                                ],
                                "properties": {
                                    "status": {
                                        "type": "string",
                                        "description": "Код статуса арендатора"
                                    }
                                }
                            },
                            "example": {
                                "status": "shipped"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "example": {
                                    "data": {
                                        "id": 1043,
                                        "number": 1043,
                                        "status": "new",
                                        "contact_id": 12,
                                        "amount": 5080,
                                        "currency": "RUB",
                                        "paid_amount": 0,
                                        "items": [
                                            {
                                                "product_id": 5,
                                                "name": "Кроссовки",
                                                "qty": 2,
                                                "price": 2540,
                                                "sum": 5080
                                            }
                                        ]
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Не авторизован (нет/неверный ключ)",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "Недостаточно прав ключа (scope), запись вне магазинов ключа или ключ не привязан к этой поверхности (API/MCP)",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "Не найдено",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "Ошибка валидации",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/orders/{id}/pay": {
            "post": {
                "tags": [
                    "orders"
                ],
                "summary": "Внести оплату",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        },
                        "description": "Идентификатор"
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "amount"
                                ],
                                "properties": {
                                    "amount": {
                                        "type": "number",
                                        "description": "Сумма > 0"
                                    }
                                }
                            },
                            "example": {
                                "amount": 2540
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "example": {
                                    "data": {
                                        "id": 1043,
                                        "number": 1043,
                                        "status": "new",
                                        "contact_id": 12,
                                        "amount": 5080,
                                        "currency": "RUB",
                                        "paid_amount": 0,
                                        "items": [
                                            {
                                                "product_id": 5,
                                                "name": "Кроссовки",
                                                "qty": 2,
                                                "price": 2540,
                                                "sum": 5080
                                            }
                                        ]
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Не авторизован (нет/неверный ключ)",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "Недостаточно прав ключа (scope), запись вне магазинов ключа или ключ не привязан к этой поверхности (API/MCP)",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "Не найдено",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "Ошибка валидации",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/contacts": {
            "get": {
                "tags": [
                    "contacts"
                ],
                "summary": "Список клиентов",
                "description": "Фильтры q / user_id / shop_id взаимоисключающие (в этом приоритете) + custom[]. shop_id=false / user_id=false — без значения.",
                "parameters": [
                    {
                        "name": "q",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Поиск по имени/телефону/email"
                    },
                    {
                        "name": "user_id",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string"
                        },
                        "description": "ID менеджера (или false)"
                    },
                    {
                        "name": "shop_id",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string"
                        },
                        "description": "ID магазина (или false)"
                    },
                    {
                        "name": "custom",
                        "in": "query",
                        "style": "deepObject",
                        "explode": true,
                        "schema": {
                            "type": "object",
                            "additionalProperties": {
                                "type": "string"
                            }
                        },
                        "description": "Фильтр по кастомным полям: custom[код]=значение (false = пусто/нет значения)"
                    },
                    {
                        "name": "page",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "integer"
                        },
                        "description": "Страница (с 1)"
                    },
                    {
                        "name": "per_page",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "integer"
                        },
                        "description": "Размер страницы, ≤ 100"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "example": {
                                    "data": [
                                        {
                                            "id": 12,
                                            "first_name": "Иван",
                                            "last_name": "Петров",
                                            "phones": [
                                                "+79990000000"
                                            ],
                                            "emails": []
                                        }
                                    ],
                                    "page": 1,
                                    "pages": 7,
                                    "total": 312
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Не авторизован (нет/неверный ключ)",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "Недостаточно прав ключа (scope), запись вне магазинов ключа или ключ не привязан к этой поверхности (API/MCP)",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "Не найдено",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "Ошибка валидации",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            },
            "post": {
                "tags": [
                    "contacts"
                ],
                "summary": "Создать клиента",
                "description": "Нужно указать имя или телефон.",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "first_name": {
                                        "type": "string"
                                    },
                                    "last_name": {
                                        "type": "string"
                                    },
                                    "middle_name": {
                                        "type": "string"
                                    },
                                    "phones": {
                                        "type": "array",
                                        "items": {
                                            "type": "string"
                                        }
                                    },
                                    "emails": {
                                        "type": "array",
                                        "items": {
                                            "type": "string"
                                        }
                                    },
                                    "external_id": {
                                        "type": "string"
                                    }
                                }
                            },
                            "example": {
                                "first_name": "Иван",
                                "phones": [
                                    "+79990000000"
                                ]
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Создан",
                        "content": {
                            "application/json": {
                                "example": {
                                    "data": {
                                        "id": 12,
                                        "first_name": "Иван",
                                        "last_name": "Петров",
                                        "phones": [
                                            "+79990000000"
                                        ],
                                        "emails": []
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Не авторизован (нет/неверный ключ)",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "Недостаточно прав ключа (scope), запись вне магазинов ключа или ключ не привязан к этой поверхности (API/MCP)",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "Не найдено",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "Ошибка валидации",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/contacts/{id}": {
            "get": {
                "tags": [
                    "contacts"
                ],
                "summary": "Клиент по id",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        },
                        "description": "Идентификатор"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "example": {
                                    "data": {
                                        "id": 12,
                                        "first_name": "Иван",
                                        "last_name": "Петров",
                                        "phones": [
                                            "+79990000000"
                                        ],
                                        "emails": []
                                    }
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "Не найдено",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Не авторизован",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/products": {
            "get": {
                "tags": [
                    "products"
                ],
                "summary": "Список товаров",
                "description": "Фильтры q (по названию), active (1/0) + custom[].",
                "parameters": [
                    {
                        "name": "q",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Поиск по названию"
                    },
                    {
                        "name": "active",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "boolean"
                        },
                        "description": "Только активные (1) / скрытые (0)"
                    },
                    {
                        "name": "custom",
                        "in": "query",
                        "style": "deepObject",
                        "explode": true,
                        "schema": {
                            "type": "object",
                            "additionalProperties": {
                                "type": "string"
                            }
                        },
                        "description": "Фильтр по кастомным полям: custom[код]=значение (false = пусто/нет значения)"
                    },
                    {
                        "name": "page",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "integer"
                        },
                        "description": "Страница (с 1)"
                    },
                    {
                        "name": "per_page",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "integer"
                        },
                        "description": "Размер страницы, ≤ 100"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "example": {
                                    "data": [
                                        {
                                            "id": 5,
                                            "name": "Кроссовки",
                                            "brand": "Nike",
                                            "price": 2540,
                                            "sku": "SNK-5",
                                            "category_ids": [
                                                3,
                                                7
                                            ],
                                            "active": true
                                        }
                                    ],
                                    "page": 1,
                                    "pages": 7,
                                    "total": 312
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Не авторизован (нет/неверный ключ)",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "Недостаточно прав ключа (scope), запись вне магазинов ключа или ключ не привязан к этой поверхности (API/MCP)",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "Не найдено",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "Ошибка валидации",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/products/{id}": {
            "get": {
                "tags": [
                    "products"
                ],
                "summary": "Товар по id",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        },
                        "description": "Идентификатор"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "example": {
                                    "data": {
                                        "id": 5,
                                        "name": "Кроссовки",
                                        "brand": "Nike",
                                        "price": 2540,
                                        "sku": "SNK-5",
                                        "category_ids": [
                                            3,
                                            7
                                        ],
                                        "active": true
                                    }
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "Не найдено",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Не авторизован",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            }
        }
    },
    "components": {
        "securitySchemes": {
            "bearerAuth": {
                "type": "http",
                "scheme": "bearer",
                "description": "API-ключ из «Настройки → Интеграции → Ключи доступа». Права (scopes) и магазины ключа определяют доступ к методам и видимость данных."
            }
        },
        "schemas": {
            "Error": {
                "type": "object",
                "properties": {
                    "error": {
                        "type": "string"
                    }
                },
                "example": {
                    "error": "invalid_token"
                }
            }
        }
    }
}