TavoCRM API

REST API для интеграций. База: https://{поддомен}.tavocrm.com/api/v1. Формат — JSON.

Авторизация

Создайте ключ в админке (Настройки → Интеграции → Ключи доступа) и передавайте его в заголовке. Спека доступна по /openapi.json — её можно импортировать в Scalar, Postman или Insomnia.

Authorization: Bearer tvk_xxxxxxxxxxxxxxxx

У ключа задаются права (scopes) — orders:read/orders:write, contacts:read/contacts:write, products:read — и привязка к магазинам. Пусто = полный доступ ко всем магазинам. Иначе метод без нужного права вернёт 403 forbidden_scope, а данные (списки и отдельные записи) ограничиваются магазинами ключа. Те же права и магазины действуют и в MCP.

Ключ привязывается к поверхностям — REST API и/или MCP. Запрос к поверхности, к которой ключ не привязан, вернёт 403 forbidden_surface. Привязка к MCP даёт полный доступ к управлению админкой в рамках прав ключа — выдавайте её осознанно.

Служебные

GET /api/v1/ping

Проверка ключа

Проверяет ключ и возвращает код арендатора.

Запрос
curl https://{поддомен}.tavocrm.com/api/v1/ping \
  -H "Authorization: Bearer tvk_..."
Ответ
{
    "pong": true,
    "tenant": "acme"
}

Заказы

GET /api/v1/orders

Список заказов

Постранично, новые сверху. Фильтры status / contact_id / q взаимоисключающие (в этом приоритете), плюс custom[]. contact_id=false — заказы без клиента.

Параметры
statusstringКод статуса
contact_idstringID клиента (или false — без клиента)
qstringПоиск по номеру / external_id
custom[код]objectФильтр по кастомным полям: custom[код]=значение (false = пусто/нет значения)
pageintegerСтраница (с 1)
per_pageintegerРазмер страницы, ≤ 100
Запрос
curl https://{поддомен}.tavocrm.com/api/v1/orders \
  -H "Authorization: Bearer tvk_..."
Ответ
{
    "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
}
POST /api/v1/orders

Создать заказ

В позиции достаточно product_id и qty — название и цена берутся из каталога.

Тело запроса
contact_id *integerСуществующий клиент (обязательно)
items *arrayПозиции (обязательно)
statusstringКод статуса; по умолчанию первый
shop_idinteger
methodstring
currencystring
paid_amountnumber
delivery_costnumber
external_idstring
Запрос
curl https://{поддомен}.tavocrm.com/api/v1/orders \
  -X POST \
  -H "Authorization: Bearer tvk_..." \
  -H "Content-Type: application/json" \
  -d '{"contact_id":12,"items":[{"product_id":5,"qty":2}]}'
Ответ
{
    "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
            }
        ]
    }
}
GET /api/v1/orders/{id}

Заказ по id

Параметры
id *integerИдентификатор
Запрос
curl https://{поддомен}.tavocrm.com/api/v1/orders/{id} \
  -H "Authorization: Bearer tvk_..."
Ответ
{
    "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
            }
        ]
    }
}
POST /api/v1/orders/{id}/status

Сменить статус

Параметры
id *integerИдентификатор
Тело запроса
status *stringКод статуса арендатора
Запрос
curl https://{поддомен}.tavocrm.com/api/v1/orders/{id}/status \
  -X POST \
  -H "Authorization: Bearer tvk_..." \
  -H "Content-Type: application/json" \
  -d '{"status":"shipped"}'
Ответ
{
    "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
            }
        ]
    }
}
POST /api/v1/orders/{id}/pay

Внести оплату

Параметры
id *integerИдентификатор
Тело запроса
amount *numberСумма > 0
Запрос
curl https://{поддомен}.tavocrm.com/api/v1/orders/{id}/pay \
  -X POST \
  -H "Authorization: Bearer tvk_..." \
  -H "Content-Type: application/json" \
  -d '{"amount":2540}'
Ответ
{
    "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
            }
        ]
    }
}

Клиенты

GET /api/v1/contacts

Список клиентов

Фильтры q / user_id / shop_id взаимоисключающие (в этом приоритете) + custom[]. shop_id=false / user_id=false — без значения.

Параметры
qstringПоиск по имени/телефону/email
user_idstringID менеджера (или false)
shop_idstringID магазина (или false)
custom[код]objectФильтр по кастомным полям: custom[код]=значение (false = пусто/нет значения)
pageintegerСтраница (с 1)
per_pageintegerРазмер страницы, ≤ 100
Запрос
curl https://{поддомен}.tavocrm.com/api/v1/contacts \
  -H "Authorization: Bearer tvk_..."
Ответ
{
    "data": [
        {
            "id": 12,
            "first_name": "Иван",
            "last_name": "Петров",
            "phones": [
                "+79990000000"
            ],
            "emails": []
        }
    ],
    "page": 1,
    "pages": 7,
    "total": 312
}
POST /api/v1/contacts

Создать клиента

Нужно указать имя или телефон.

Тело запроса
first_namestring
last_namestring
middle_namestring
phonesarray
emailsarray
external_idstring
Запрос
curl https://{поддомен}.tavocrm.com/api/v1/contacts \
  -X POST \
  -H "Authorization: Bearer tvk_..." \
  -H "Content-Type: application/json" \
  -d '{"first_name":"Иван","phones":["+79990000000"]}'
Ответ
{
    "data": {
        "id": 12,
        "first_name": "Иван",
        "last_name": "Петров",
        "phones": [
            "+79990000000"
        ],
        "emails": []
    }
}
GET /api/v1/contacts/{id}

Клиент по id

Параметры
id *integerИдентификатор
Запрос
curl https://{поддомен}.tavocrm.com/api/v1/contacts/{id} \
  -H "Authorization: Bearer tvk_..."
Ответ
{
    "data": {
        "id": 12,
        "first_name": "Иван",
        "last_name": "Петров",
        "phones": [
            "+79990000000"
        ],
        "emails": []
    }
}

Товары

GET /api/v1/products

Список товаров

Фильтры q (по названию), active (1/0) + custom[].

Параметры
qstringПоиск по названию
activebooleanТолько активные (1) / скрытые (0)
custom[код]objectФильтр по кастомным полям: custom[код]=значение (false = пусто/нет значения)
pageintegerСтраница (с 1)
per_pageintegerРазмер страницы, ≤ 100
Запрос
curl https://{поддомен}.tavocrm.com/api/v1/products \
  -H "Authorization: Bearer tvk_..."
Ответ
{
    "data": [
        {
            "id": 5,
            "name": "Кроссовки",
            "brand": "Nike",
            "price": 2540,
            "sku": "SNK-5",
            "category_ids": [
                3,
                7
            ],
            "active": true
        }
    ],
    "page": 1,
    "pages": 7,
    "total": 312
}
GET /api/v1/products/{id}

Товар по id

Параметры
id *integerИдентификатор
Запрос
curl https://{поддомен}.tavocrm.com/api/v1/products/{id} \
  -H "Authorization: Bearer tvk_..."
Ответ
{
    "data": {
        "id": 5,
        "name": "Кроссовки",
        "brand": "Nike",
        "price": 2540,
        "sku": "SNK-5",
        "category_ids": [
            3,
            7
        ],
        "active": true
    }
}

Вебхуки

Вебхуки — действие триггера «HTTP-запрос»: событие + условия + HTTP-запрос на ваш URL с настраиваемым телом и необязательной подписью HMAC-SHA256 (заголовок X-TavoCRM-Signature: sha256=<hex>). Настройка — Настройки → Интеграции → Триггеры.

Подробно — в справочнике по триггерам.

MCP-сервер

Эндпоинт https://{поддомен}.tavocrm.com/mcp — JSON-RPC 2.0, авторизация тем же Bearer-ключом. Набор инструментов и доступ определяются правами (scopes) и магазинами ключа — так же, как в REST: инструмент доступен, если у ключа есть соответствующий scope (например orders:write). Пустые права у ключа = полный доступ, включая админ-инструменты (справочники, статусы, роли, пользователи). Ключ должен быть привязан к поверхности MCP (в форме ключа), иначе запрос вернёт 403 forbidden_surface. Настройка адреса и публичного доступа — Настройки → MCP-сервер.

curl https://{поддомен}.tavocrm.com/mcp \
  -H "Authorization: Bearer tvk_..." \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'

Публичный MCP (анонимное оформление)

Эндпоинт https://{поддомен}.tavocrm.com/mcp/public — без ключа (включается в Настройки → MCP-сервер). Для ИИ-агента покупателя: каталог (products_search, products_get) и оформление заказа (checkout). Первый checkout с name + phone создаёт клиента и возвращает client_token — «мини-ЛК» клиента: повторные заказы (checkout с client_token) и статусы только своих заказов (my_orders, my_order_get). Токен передаётся аргументом инструмента. Запросы ограничены по частоте на IP. Проверка доступности (для бота): GET /mcp/public с Accept: application/json → 200 с описанием сервера, если включено, иначе 404. При заходе из браузера тот же адрес перенаправляет на страницу-инструкцию /connect — её же можно дать покупателям (подключение ассистента, готовый промпт).

Коды ошибок

HTTP / codeerrorЗначение
401missing_token / invalid_tokenнет / неверный ключ
403forbidden_scope / shop_forbidden / forbidden_surfaceу ключа нет нужного права / запись вне магазинов ключа / ключ не привязан к этой поверхности (API или MCP)
404not_foundсущность не найдена
422invalid_contact, no_items, invalid_status, invalid_amount, name_or_phone_requiredошибки валидации
422limit_reachedдостигнут лимит тарифа

MCP: протокольные ошибки JSON-RPC (-32700 parse, -32601 method, -32602 unknown tool); ошибки инструмента — result.isError = true с текстом.