Модуль 8 · Уровень: продвинутый, для тех, кто дружит с кодом

API и выгрузки: превращаем Трекер из сайта в платформу

Скажу честно сразу: если ты не пишешь код, этот модуль можно пропустить и жить дальше. Но прочитать его стоит даже без единой строчки Python: поймёшь, как на самом деле работает наш бот Гермес и почему «выгрузи мне отчёт» занимает у скрипта три секунды.

После модуля ты умеешь

Что даёт API

Всё, что ты делаешь в Трекере мышкой, можно делать скриптом. Правило простое: есть кнопка, есть и запрос к API. Создать задачу, поменять статус, найти всё просроченное, добавить комментарий: для каждого действия есть свой HTTP-запрос.

Зачем это нужно, когда руки и так справляются:

Технически это обычный REST: шлёшь HTTP-запросы на https://api.tracker.yandex.net, актуальная версия v3, ответы приходят в JSON. Подойдёт любой язык, в примерах будет Python с библиотекой requests.

Получаем доступ по шагам

API должно понимать, кто ты и в какой организации работаешь. Для этого нужны две вещи: OAuth-токен (это про «кто ты») и ID организации (это про «где»).

  1. Открой oauth.yandex.ru и нажми Создать приложение

    Входи тем же Яндекс ID, которым ходишь в Трекер. «Приложение» звучит громко, на деле это просто запись «такой-то скрипт имеет такие-то права».

  2. Укажи название, выбери вариант Для доступа к API или отладки

    Название любое понятное, например «Отчёты Котолавки». Почта для связи: твоя рабочая.

  3. В разделе доступов добавь права Трекера: tracker:read для чтения, tracker:write для создания и изменения задач

    Правило минимума: скрипту-выгрузке хватит tracker:read. Права на запись выдавай, только если скрипт реально что-то создаёт.

  4. Сохрани приложение, скопируй его ClientID и перейди по ссылке https://oauth.yandex.ru/authorize?response_type=token&client_id=<твой_ClientID>

    Яндекс спросит подтверждение и покажет токен: длинную строку символов. Это и есть ключ для скриптов, скопируй его в надёжное место.

  5. Узнай ID организации: в Трекере открой АдминистрированиеОрганизации и скопируй значение поля с идентификатором

    Если организация облачная (Yandex Cloud Organization), в запросах вместо заголовка X-Org-ID используется X-Cloud-Org-ID. Какой у вас случай, видно там же в настройках: облачный идентификатор из букв и цифр, обычный из цифр.

В каждом запросе к API эти две вещи едут в заголовках:

Authorization: OAuth <твой_токен>
X-Org-ID: <ID_организации>        # для облачных организаций: X-Cloud-Org-ID
oauth.yandex.ru Создание приложения Название сервиса Отчёты Котолавки Для какой платформы Веб-сервисы Для доступа к API или отладки Доступ к данным Яндекс Трекер tracker:read · чтение данных из Трекера tracker:write · создание и изменение данных Создать приложение без этих галочек токен в Трекер не пустят
Создание OAuth-приложения: главное не забыть отметить права Трекера, иначе API ответит отказом.

Токен = ключ от всего Трекера. Кто держит токен, тот может читать и менять задачи от твоего имени. Поэтому три железных «не»: не вшивай токен в код, не коммить в git, не кидай в чаты «на секундочку». Правильно так: положи его в переменную окружения (export TRACKER_TOKEN=...) или в менеджер секретов, а скрипт пусть читает оттуда. Если токен всё же засветился, отзови его на oauth.yandex.ru и выпусти новый.

Читаем задачи: первый скрипт

Начнём с чтения, оно безопасное: ничего не сломаешь. Задача: получить все открытые задачи очереди и напечатать их номера и названия. Для поиска задач в API есть эндпоинт POST /v3/issues/_search: шлёшь ему фильтр, получаешь JSON-список задач.

# list_tasks.py: открытые задачи очереди KOT
import os
import requests

# токен и ID организации берём из переменных окружения, не из кода
TOKEN = os.environ["TRACKER_TOKEN"]
ORG_ID = os.environ["TRACKER_ORG_ID"]

headers = {
    "Authorization": f"OAuth {TOKEN}",
    "X-Org-ID": ORG_ID,  # у облачных организаций: "X-Cloud-Org-ID"
}

resp = requests.post(
    "https://api.tracker.yandex.net/v3/issues/_search",
    headers=headers,
    params={"perPage": 100},          # задач на страницу ответа
    json={
        "filter": {
            "queue": "KOT",           # ключ очереди
            "resolution": "empty()",  # ещё не решённые, то есть открытые
        },
        "order": "+status",           # сортировка по статусу
    },
)
resp.raise_for_status()  # если что-то не так, упадём с понятной ошибкой

issues = resp.json()
for issue in issues:
    print(f'{issue["key"]:10} {issue["summary"]}')

print(f"Всего открытых задач: {len(issues)}")

Запускаешь python list_tasks.py и видишь в терминале свой Трекер без браузера:

терминал $ python list_tasks.py TREK-25 Подготовка к онлайн-встрече по аналитической машине TREK-24 Внутренний конкурс на лучшее ИИ-решение TREK-19 Организовать демо аудита звонков для Автохаба TREK-17 Запустить обзвон нейронкой и замерить конверсию TREK-14 Файл-светофор мониторинга дилеров TREK-10 Зарегистрировать домен sollers.auto Всего открытых задач: 6 $ ответ API, три секунды, ни одного клика мышкой
Вывод скрипта: открытые задачи очереди TREK. Тот же список, что в браузере, только теперь его можно скармливать другим программам.

Если задач больше сотни. API отдаёт результаты страницами: параметр perPage задаёт размер страницы, page выбирает номер. Крутишь page=1, 2, 3..., пока не придёт пустой список. А фильтровать можно не только объектом filter, но и языком запросов из модуля 5: передай строку в поле query, пример будет ниже в выгрузке.

Создаём задачу скриптом

Теперь запись. Создание задачи: POST /v3/issues. Обязательных полей всего два, очередь и название, остальное по вкусу.

# new_task.py: заводим задачу с исполнителем и дедлайном
import os
import requests

headers = {
    "Authorization": f"OAuth {os.environ['TRACKER_TOKEN']}",
    "X-Org-ID": os.environ["TRACKER_ORG_ID"],
}

payload = {
    "queue": "KOT",                          # куда: ключ очереди
    "summary": "Сверка остатков склада",     # название, обязательное поле
    "description": "Сверить остатки корма в базе с фактом на складе. "
                   "Расхождения записать в комментарий.",
    "assignee": "maks",                      # логин исполнителя
    "deadline": "2026-07-21",                # дедлайн в формате ГГГГ-ММ-ДД
}

resp = requests.post(
    "https://api.tracker.yandex.net/v3/issues",
    headers=headers,
    json=payload,
)
resp.raise_for_status()

issue = resp.json()
print("Создана задача:", issue["key"], "·", issue["summary"])
# Создана задача: KOT-27 · Сверка остатков склада

В ответ API возвращает созданную задачу целиком, включая её номер. Дальше этот номер можно куда угодно: в лог, в сообщение бота, в письмо. Для запуска по расписанию скрипт вешают на планировщик: cron на сервере или «Планировщик заданий» в Windows.

Выгрузка для отчёта: закрытое за неделю в CSV

Классика жанра: руководитель хочет по понедельникам список всего, что закрыли за неделю. Соберём из уже знакомых деталей: поиск задач, только теперь языком запросов, плюс модуль csv из стандартной библиотеки.

# weekly_report.py: задачи, закрытые за 7 дней, в CSV
import csv
import os
from datetime import date, timedelta

import requests

headers = {
    "Authorization": f"OAuth {os.environ['TRACKER_TOKEN']}",
    "X-Org-ID": os.environ["TRACKER_ORG_ID"],
}

week_ago = (date.today() - timedelta(days=7)).isoformat()
# язык запросов из модуля 5 работает и в API: поле query
query = f'Queue: KOT AND Resolved: >= "{week_ago}"'

resp = requests.post(
    "https://api.tracker.yandex.net/v3/issues/_search",
    headers=headers,
    params={"perPage": 100},
    json={"query": query, "order": "+resolvedAt"},
)
resp.raise_for_status()
issues = resp.json()

# utf-8-sig, чтобы Excel сразу понял русские буквы
with open("closed_week.csv", "w", newline="", encoding="utf-8-sig") as f:
    writer = csv.writer(f, delimiter=";")
    writer.writerow(["Номер", "Название", "Исполнитель", "Закрыта"])
    for issue in issues:
        writer.writerow([
            issue["key"],
            issue["summary"],
            issue.get("assignee", {}).get("display", "без исполнителя"),
            issue.get("resolvedAt", "")[:10],  # дата без времени
        ])

print(f"Готово: {len(issues)} задач в closed_week.csv")

Файл открывается в любой табличке: Excel, Яндекс Документы, Google Sheets. Дальше сводные, графики, что душе угодно. Один раз написал, и утренний отчёт по понедельникам делается сам.

Как устроен Гермес: тот же API, никакой магии

Всё, что бот Сол (Гермес) делает с нашей очередью TREK, собрано ровно из тех кирпичей, что ты видел выше:

  1. Бот регулярно обновляет свой список открытых задач очереди

    Тот самый POST /v3/issues/_search с фильтром по очереди. Список хранится у бота под рукой, чтобы не дёргать API на каждый чих.

  2. Читает рабочую Telegram-группу и ловит поручения

    Сообщения вида «сделать X к сроку» распознаёт языковая модель. Это единственная часть, которой нет в Трекере, всё остальное штатное API.

  3. Сверяет пойманное поручение со своим списком задач

    Похожая задача уже есть? Значит, дубль не нужен. Именно поэтому в TREK нет пяти задач «подготовить встречу» про одну и ту же встречу.

  4. Спрашивает подтверждение и после «да» создаёт задачу

    Тот самый POST /v3/issues. Человек решает, бот исполняет: ни одна задача не появляется без подтверждения.

Мораль всего модуля: API превращает Трекер из сайта, куда ходят люди, в платформу, на которой строят своё. Бот в Telegram, отчёт по расписанию, интеграция с самописной системой склада: всё это один и тот же набор запросов.

Сквозной кейс · Котолавка, серия 8

Макс автоматизирует понедельник

В прошлой серии заявки на возврат и письма поставщиков научились сами падать в очередь. Теперь Макс, который когда-то программировал на Python, решает добить рутину: Оля каждый понедельник просит «что закрыли за неделю», а сверку остатков он сам вечно забывает завести.

Делаем
Макс создаёт на oauth.yandex.ru приложение «Скрипты Котолавки» с правами tracker:read и tracker:write, получает токен и кладёт его в переменную окружения на рабочем ноуте. Пишет два скрипта: weekly_report.py выгружает все задачи KOT, закрытые за 7 дней, в closed_week.csv; второй, new_task.py, заводит задачу «Сверка остатков склада» с исполнителем «maks» и дедлайном на вторник. Оба вешает в планировщик на утро понедельника.
Видим
В понедельник в 8:00 на диске появляется свежий CSV: KOT-31 «Возврат когтеточки», KOT-33 «Ответить на отзывы», ещё девять строк с исполнителями и датами. А в очереди KOT сама собой возникает задача KOT-35 «Сверка остатков склада», дедлайн: вторник, исполнитель: Макс.
Контролируем
Оля открывает CSV в табличке и сверяет пару строк с Трекером: номера и даты закрытия совпадают. Макс проверяет, что задача сверки не задвоилась: скрипт перед созданием ищет в очереди открытую задачу с таким же названием, совсем как Гермес.
Получаем
Отчёт, который раньше собирали полчаса руками, теперь делается сам. Позже Макс узнаёт, что повторяющуюся задачу можно было завести и автодействием из модуля 6, без единой строчки кода. И это нормально: API и встроенная автоматика не соревнуются, а дополняют друг друга. Простое отдаёшь автодействиям, хитрое забираешь в код.

Как это у нас в TREK

Наш живой пример из этого модуля: current_tasks, список открытых задач очереди TREK, который Гермес регулярно обновляет через API. Перед тем как предложить новую задачу из пойманного в Telegram поручения, бот сверяется именно с этим списком: есть похожая открытая задача, значит, дубль не предлагаем. Ровно та схема из четырёх шагов, что описана выше, работает у нас каждый день.

Хочешь написать свой скрипт по очереди TREK, например личную выгрузку своих задач: попроси токен у владельца организации и не заводи лишние приложения. Один общий порядок с ключами лучше, чем десять токенов, о которых все забыли.

Чек-лист: что должно получиться

Мини-тест: 5 вопросов, без занудства

Ошибиться не страшно: под неправильным ответом появится подсказка, куда посмотреть.

1. Макс написал скрипт и собирается положить его в общий git-репозиторий. Где должен жить токен?

Именно. Код едет в git, ключи остаются дома.
Перечитай предупреждение в разделе про доступ: токен не вшивают в код, не коммитят и не кидают в чаты.

2. Скрипту нужно получить все открытые задачи очереди KOT. Какой запрос отправить?

Верно, поиск задач: фильтр в теле, список задач в ответе.
Смотри первый скрипт в разделе «Читаем задачи»: эндпоинт _search принимает filter или query и возвращает JSON-список.

3. Скрипт получает от API ошибку доступа, хотя токен свежий. Что проверить в первую очередь?

Да: почти все отказы API про заголовки, права приложения или права пользователя в Трекере.
Вернись к шагам в разделе «Получаем доступ»: нужны оба заголовка, а у приложения должны стоять галочки tracker:read или tracker:write.

4. Макс узнал, что его задачу «Сверка остатков каждый вторник» можно завести и автодействием без кода. Что теперь делать со скриптом?

Точно. Это не соревнование инструментов, а один ящик с инструментами.
Ответ прячется в финале раздела про Гермеса и в итогах кейса: API и встроенная автоматика дополняют друг друга.

5. В Telegram-группе дважды за день написали «надо подготовить демо для клиента». Почему Гермес не завёл две одинаковые задачи?

Верно: сверка со списком current_tasks, и только потом предложение создать.
Загляни в раздел «Как устроен Гермес»: шаг 3, сверка поручения со списком открытых задач.