# Tebiz Data: документация REST API и MCP

> Tebiz Data (api.tebiz.ru) - API с официальными данными для анализа рынков товаров и отраслей: объём и структура рынка, доли игроков, динамика по годам, цены и спрос по товарным кодам и регионам. Доступ через REST API для скриптов и через MCP для ИИ-агентов по одному ключу, подписка открывает все наборы каталога, цена фиксируется на оплаченный срок. Продукт Tebiz Group: маркетинговые исследования рынков с 2011 года.

HTML-версия: https://api.tebiz.ru/guide. Схема REST: https://api.tebiz.ru/openapi.json. Сводка для LLM: https://api.tebiz.ru/llms.txt.

## Быстрый старт

В примере стоит публичный демо-ключ: он работает без регистрации на образце данных каждого набора.

```bash
curl -H "Authorization: Bearer tbz_live_ItPY9Edf209jODxMstCXtbKsXETPGTJHiNTFf20m" \
  "https://api.tebiz.ru/v1/financials?year=eq.2025&select=inn,name,okved,2110&limit=5"
```

Состав образца: https://github.com/TG-info/tebiz-api-examples/blob/main/DEMO_DATA.md. Чтобы работать со всеми данными, выберите тариф (https://api.tebiz.ru/#pricing) и выпустите свой ключ в кабинете.

## Доступ по ключу API

Ключ передаётся в заголовке каждого запроса: `Authorization: Bearer tbz_live_...`. Ключ выпускается в личном кабинете (https://api.tebiz.ru/account) после оформления подписки или пробного доступа и показывается один раз. На аккаунте до пяти ключей, лимит строк у них общий. От тарифа зависят лимит строк в месяц и число запросов в минуту на ключ.

## REST API

Адрес: `GET https://api.tebiz.ru/v1/<набор>`. Ответ: `{"data":[...],"next_cursor":...}`.

### Фильтры

Запись `?поле=оператор.значение`, несколько фильтров объединяются по И, один параметр можно повторить (`year=gte.2020&year=lte.2023`). Фильтровать можно только поля с пометкой «фильтр» в справочнике набора, операторы зависят от типа поля.

| Оператор | Смысл | Пример |
|---|---|---|
| eq | равно | `year=eq.2024` |
| ne | не равно | `okved=ne.62.01` |
| gt, gte | больше, больше или равно | `year=gte.2022` |
| lt, lte | меньше, меньше или равно | `year=lte.2023` |
| like | шаблон без учёта регистра, `*` заменяет любые символы | `okved=like.62*` |
| in | одно из значений через запятую | `inn=in.7707083893,7708004767` |
| is_null | значение не заполнено | `okved=is_null` |

### Выбор полей, лимит, пагинация

`select=a,b,c` вернёт только эти поля. `limit=N` задаёт размер страницы, не больше максимума набора. В запросе до 50 фильтров, в списке in до 1000 значений. Сортировки нет: строки идут по полям курсора. Если `next_cursor` не null, повторите запрос с теми же фильтрами и `cursor=<значение>`. Первый запрос к большому набору (больше 2 млн строк) делайте с фильтром, иначе придёт 400.

```python
cursor = None
while True:
    params = {"year": "eq.2024", "limit": 500}
    if cursor:
        params["cursor"] = cursor
    body = requests.get(URL, headers=HEADERS, params=params).json()
    process(body["data"])
    cursor = body["next_cursor"]
    if not cursor:
        break
```

### Лимиты в заголовках ответа

| Заголовок | Смысл |
|---|---|
| X-RateLimit-Limit | запросов в минуту по тарифу |
| X-RateLimit-Remaining | сколько запросов осталось в текущем окне 60 секунд |
| X-Quota-Rows-Remaining | сколько строк осталось до лимита в этом месяце |
| X-Quota-Scope | global: общий лимит аккаунта, resource: лимит ключа на набор |
| X-Data-Scope | limited: ключ видит образец данных (демо-ключ, пробный доступ) |
| Retry-After | через сколько секунд повторить (при 429 и 503) |

## MCP для ИИ-агентов

Адрес MCP-сервера: `https://api.tebiz.ru/mcp/`, транспорт Streamable HTTP, ключ тот же, что для REST API, в заголовке `Authorization: Bearer tbz_live_...`. Имя сервера в конфигах: `tebiz-data`.

Инструменты (все только читают данные):

- `list_resources`: наборы, доступные ключу. Вызывается первым.
- `describe_resource(resource)`: поля, типы, признак filterable, операторы, лимиты и 3 примера строк.
- `query(resource, filters, select, limit, cursor)`: выборка. filters: список `{"column":"year","op":"eq","value":2024}` по И; like ищет по шаблону, `*` заменяет любые символы. Ответ: `{"columns":[...],"rows":[[...]],"row_count":N,"has_more":bool,"next_cursor":...}`. Если `has_more` равно true, выборка неполная: листайте с `cursor=next_cursor`.

### Подключение

#### Claude Code

Команда в терминале. Проверка: `claude mcp list`.

```bash
claude mcp add --transport http tebiz-data https://api.tebiz.ru/mcp/ \
  --header "Authorization: Bearer tbz_live_..."
```

#### Cursor

Файл `~/.cursor/mcp.json` (для всех проектов) или `.cursor/mcp.json` в проекте.

```json
{
  "mcpServers": {
    "tebiz-data": {
      "url": "https://api.tebiz.ru/mcp/",
      "headers": {
        "Authorization": "Bearer tbz_live_..."
      }
    }
  }
}
```

#### VS Code

Файл `.vscode/mcp.json` в проекте. Ключ VS Code спросит при первом запуске и сохранит в защищённом хранилище.

```json
{
  "servers": {
    "tebiz-data": {
      "type": "http",
      "url": "https://api.tebiz.ru/mcp/",
      "headers": {
        "Authorization": "Bearer ${input:tebiz-key}"
      }
    }
  },
  "inputs": [
    {
      "type": "promptString",
      "id": "tebiz-key",
      "description": "Ключ Tebiz Data",
      "password": true
    }
  ]
}
```

#### Claude Desktop

Файл `claude_desktop_config.json` (Settings, Developer, Edit Config). Подключение идёт через мост `mcp-remote`, нужен Node.js 18 или новее. После правки перезапустите Claude Desktop.

```json
{
  "mcpServers": {
    "tebiz-data": {
      "command": "npx",
      "args": [
        "-y",
        "mcp-remote",
        "https://api.tebiz.ru/mcp/",
        "--header",
        "Authorization:${TEBIZ_AUTH}"
      ],
      "env": {
        "TEBIZ_AUTH": "Bearer tbz_live_..."
      }
    }
  }
}
```

#### Python

Свой агент на официальном MCP SDK для Python.

```python
# pip install -U mcp httpx
import asyncio

import httpx
from mcp import ClientSession
from mcp.client.streamable_http import streamable_http_client


async def main():
    headers = {"Authorization": "Bearer tbz_live_..."}
    async with httpx.AsyncClient(headers=headers, timeout=60) as http:
        async with streamable_http_client("https://api.tebiz.ru/mcp/", http_client=http) as (read, write, _):
            async with ClientSession(read, write) as session:
                await session.initialize()
                result = await session.call_tool("list_resources", {})
                print(result.content[0].text)


asyncio.run(main())
```

ChatGPT и веб-версия Claude.ai пока не подключатся: их коннекторы требуют вход через OAuth, а сервер Tebiz Data принимает ключ в заголовке. Используйте клиенты выше или свой агент на MCP SDK.

### Если не работает

- [missing_key] или 401: ключ не дошёл до сервера. Проверьте заголовок `Authorization: Bearer tbz_live_...` и перезапустите клиент после правки конфига.
- [not_found]: такого набора нет или он не выдан ключу. Вызовите `list_resources`.
- Пустой ответ с полем note: ключ видит только образец данных (демо-ключ или пробный доступ), значений из фильтра в нём нет. Это не значит, что данных нет вообще.
- [bad_request]: фильтр по полю без метки «фильтр» или неподходящий оператор. Поля и операторы показывает `describe_resource`.

## Наборы данных

- [Бухгалтерская отчётность](https://api.tebiz.ru/guide/financials.md) (`financials`): Бухгалтерская отчётность российских организаций по данным ФНС России: баланс и отчёт о финансовых результатах по годам. Одна строка: организация за год. Суммы в тыс. руб.
- [indicators](https://api.tebiz.ru/guide/indicators.md) (`indicators`): Справочник строк бухгалтерской отчётности: код, название, тип и форма. Код не уникален: строка может встречаться несколько раз, например на начало и конец периода.
- [Госзакупки (44-ФЗ)](https://api.tebiz.ru/guide/zakupki.md) (`zakupki`): Госзакупки по 44-ФЗ из ЕИС: позиции контрактов с заказчиком, поставщиком, кодом ОКПД2, ценами и датами. Одна строка: позиция контракта. Суммы в рублях.

## Коды ошибок

При ошибке API возвращает JSON `{"error":"...","detail":"..."}`. Поле `error` стабильно, в `detail` по-русски написано, что случилось и что сделать.

| HTTP | error | Причина и что делать |
|---|---|---|
| 200 | нет | Пустой ответ `{"data":[]}`: под фильтр ничего не попало. У демо-ключа и пробного доступа так бывает вне образца данных, тогда в ответе есть поле `note`. |
| 400 | bad_request | Неизвестное поле, фильтр по полю без метки «фильтр», неподходящий оператор, неверное значение или cursor. Так же отвечает первый запрос к большому набору без фильтра. |
| 401 | unauthorized | Причина в поле `reason`: `missing_key` (нет заголовка), `malformed_key` (ключ записан неверно, 49 символов вместе с tbz_live_), `invalid_key` (ключа нет), `key_revoked` (отозван), `key_expired` (закончился срок ключа), `subscription_expired` (закончилась подписка, дата в `expired_at`, ссылка на продление в `renew_url`, у пробного доступа `"trial": true`). |
| 404 | not_found | Набора нет или он недоступен ключу. Эти случаи API не различает. |
| 429 | rate_limit_exceeded | Превышено число запросов в минуту на ключ (`limit`). Повторите через `Retry-After` секунд, больше запросов дают тарифы выше (`upgrade_url`). |
| 429 | row_quota_exceeded | Исчерпан лимит строк на месяц. Поля `scope` (global или resource), `remaining`, `reset_at`, `limit`, `upgrade_url`. Если `remaining` больше нуля, уменьшите limit. |
| 429 | too_many_requests | С одного IP-адреса больше допустимого числа запросов в минуту. |
| 503 | service_unavailable | Сервис временно недоступен, повторите через `Retry-After` секунд. |
| 504 | timeout | Запрос выполнялся слишком долго. Сузьте выборку фильтрами, например по году. |

В MCP ошибка приходит результатом инструмента с `isError: true`, текст начинается с кода в квадратных скобках (у 401 это причина из `reason`), дальше то же, что `detail` в REST.
