Перейти к содержимому

Спецификация API

Полный справочник по REST-эндпоинтам. Туториалы и примеры см. в Руководстве по API.

Всё, что участник проекта может делать в веб-интерфейсе, доступно здесь — SPA потребляет тот же самый API. Операции, требующие роли owner, помечены (owner); всему остальному нужно лишь членство в проекте (или, для операций чтения, помеченных (viewer), любой уровень доступа).

https://eastagiletracker.com/api/v1

https://api.eastagiletracker.com/api/v1 обслуживает идентичный API. Все запросы и ответы — это JSON, за исключением нескольких эндпоинтов загрузки файлов, которые принимают multipart.

Каждый аутентифицированный запрос отправляет API-ключ одним из способов:

  • X-TrackerToken: <key>
  • Authorization: Bearer <key>

Пользовательские ключи начинаются с ea_user_. Ключи агентов начинаются с ea_agent_. См. Руководство по API → Два вида ключей.

Эндпоинты без аутентификации: /openapi.json, /docs, эндпоинты /auth/* и справочные данные (/story_types, /story_states, /effort_scales, …). /meta требует аутентификации — подходит любой действительный ключ, но он не ограничен проектом (привязанный к проекту ключ агента тоже до него дотягивается).

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

УровеньКто проходитТипичные операции
viewerviewer, member, ownerчтение (список/получение историй, поиск, аналитика)
membermember, ownerвсе операции записи рабочих элементов (истории, задачи, комментарии, …)
ownerтолько ownerнастройки проекта, управление членством, ключи агентов, удаление, импорт, журнал аудита

Не-участник получает 404 unfound_resource (а не 403) на путях проекта, так что ID проектов не перечислимы.

МетодПутьОписание
GET/openapi.jsonАктуальная спецификация OpenAPI 3. Без аутентификации.
GET/docsSwagger UI. Без аутентификации.
GET/metaИдентичность вызывающего (auth.kind/key_id/agent_id/project_id) + граф переходов для типов историй. Требует аутентификации (любой действительный ключ; не ограничен проектом). Вызывайте это первым.

Эти действуют от имени вызывающего и требуют лишь действительного ключа (без роли в проекте).

МетодПутьОписание
POST/auth/registerЗарегистрировать новый аккаунт
POST/auth/loginВойти, возвращает токен сессии
POST/auth/logoutВыйти
POST/auth/forgot-passwordЗапросить письмо для сброса пароля
POST/auth/reset-passwordИспользовать токен сброса для установки нового пароля
GET/auth/verify-emailПодтвердить адрес электронной почты
POST/auth/accept-invite/lookupРазрешить токен приглашения → email (без аутентификации)
POST/auth/accept-inviteПринять приглашение в проект (после аутентификации)
GET/meПрофиль текущего пользователя
PUT/meОбновить профиль
DELETE/meУдалить аккаунт
PUT/me/passwordСменить пароль
PUT/me/settingsОбновить настройки (тема, предпочтения уведомлений)
POST/me/avatarЗагрузить аватар (multipart)
POST/me/api-token/regenerateРотировать ваш API-токен — аннулирует существующие сессии/ключи
GET/me/api_keys · POST /me/api_keys · DELETE /me/api_keys/{id}Управление пользовательскими (ea_user_) API-ключами
GET/me/activityВаша активность по всем проектам
GET/me/data-exportGDPR-самоэкспорт ваших данных
GET/me/consent · POST /me/consentПрочитать / записать согласие ({ consent_type, granted })
GET/legal/pending · POST /legal/acceptОжидающие clickwrap-документы / запись принятия
POST/contact · POST /feedback · POST /feedback/with-screenshotКонтакт + обратная связь внутри приложения

Стартовые справочники, используемые при создании/оценке историй. Стабильные ID.

МетодПутьОписание
GET/story_typesfeature, bug, chore, release (+ allow_points)
GET/story_statesunstarted … accepted, rejected
GET/effort_scalesдоступные шкалы оценки
GET/effort_scales/{scale_id}/valuesзначения баллов в шкале
МетодПутьОписание
GET/projectsСписок ваших проектов
POST/projectsСоздать проект
GET/projects/{id}Получить детали проекта (viewer)
PUT/projects/{id}Обновить настройки проекта (owner)
DELETE/projects/{id}Удалить проект (owner)
GET/projects/{id}/audit-logПоток активности проекта (owner)
GET/projects/{id}/eventsПоток событий с курсорной пагинацией (viewer) — см. Events
МетодПутьОписание
GET/projects/{id}/membershipsСписок участников (viewer)
POST/projects/{id}/membershipsПригласить участника по email (owner)
PUT/projects/{id}/memberships/{mid}Обновить роль (owner)
DELETE/projects/{id}/memberships/{mid}Удалить участника (owner)
GET / POST/projects/{id}/agent_keysСписок / выпуск ключей агентов (owner)
DELETE/projects/{id}/agent_keys/{kid}Отозвать ключ агента (owner)

Всем операциям записи историй нужна роль member.

МетодПутьОписание
GET/projects/{id}/storiesСписок историй (с пагинацией, фильтруемый) (viewer)
POST/projects/{id}/storiesСоздать историю
GET/projects/{id}/stories/{sid}Получить одну историю (viewer)
PUT/projects/{id}/stories/{sid}Обновить историю
DELETE/projects/{id}/stories/{sid}Удалить историю
POST/projects/{id}/stories/{sid}/transitionsСменить состояние с валидацией
POST/projects/{id}/stories/bulk_transitionПеревести много историй (1–100) сразу
POST/projects/{id}/stories/bulk-deleteУдалить много историй
POST/projects/{id}/stories/bulk-duplicateДублировать много историй
POST/projects/{id}/stories/{sid}/duplicateДублировать одну историю

Create (POST …/stories): { "name" (required), "story_type": "feature|bug|chore|release", "description"?, "estimate"?, "current_state"?, "icebox"?, "labels"? }. labels принимает ["auth"] или [{ "name": "auth" }]; неизвестные метки создаются. Значения по умолчанию: story_type=feature, current_state=unstarted.

Update (PUT …/stories/{sid}): те же поля, все опциональные, плюс "position" (float) и "force_state_change" (bool).

Transition (POST …/transitions): { "to": "<state>", "reason"? }. Поле называется to. Возвращает { story_id, state }. Недопустимое перемещение → 422 invalid_transition с details: { from, to, allowed }.

Bulk transition (POST …/bulk_transition): { "story_ids": [int,…] (1–100), "to": "<state>", "reason"? }. Каждая история оценивается независимо; возвращает { results: [ { id, status: "ok" } | { id, status: "failed", error } ] }.

Все member. List/GET для большинства — (viewer).

МетодПутьТело / примечания
GET / POST/projects/{id}/stories/{sid}/tasks · PUT/DELETE …/tasks/{tid}{ description (or task_desc), complete?, task_order? }
GET / POST/projects/{id}/stories/{sid}/comments · PUT/DELETE …/comments/{cid}{ text (or comment_text) } или { comment_emoji }
GET / POST/projects/{id}/stories/{sid}/blockers · PUT/DELETE …/blockers/{bid}{ blocker_desc, resolved? }
GET / POST/projects/{id}/stories/{sid}/links · DELETE …/links/{lid}{ url, link_type?, title? }
GET / POST/projects/{id}/stories/{sid}/reviews · PUT/DELETE …/reviews/{rid}{ reviewer_id? / reviewer_agent_id?, status, comment? }
GET / POST/projects/{id}/stories/{sid}/owners · DELETE …/owners/{mid} · DELETE …/owners/agents/{aid}{ member_id? / agent_id? } — опустите оба, чтобы добавить вызывающего
GET / POST/projects/{id}/stories/{sid}/followers · DELETE …/followers/{mid} · DELETE …/followers/agents/{aid}{ member_id? / agent_id? }
GET / POST/projects/{id}/stories/{sid}/labels · DELETE …/labels/{lid}{ name }
GET / POST/projects/{id}/stories/{sid}/attachments (+ /json) · DELETE …/attachments/{aid}multipart-загрузка (≤ 2 ГБ каждая); список — (viewer)

member для записи, (viewer) для чтения.

МетодПутьОписание
GET / POST/projects/{id}/labelsСписок / создание метки
PUT / DELETE/projects/{id}/labels/{lid}Обновление / удаление метки
POST/projects/{id}/labels/{lid}/archiveАрхивировать (мягко скрыть) метку
МетодПутьОписание
GET/projects/{id}/iterationsСписок итераций (member)
POST/projects/{id}/iterationsСоздать ручную итерацию (owner)
DELETE/projects/{id}/iterations/{itid}Удалить итерацию (owner)
МетодПутьОписание
GET/projects/{id}/search?query=…Поиск по синтаксису фильтров (viewer) — см. Руководство
GET/projects/{id}/analytics/{overview,iteration,releases,activity,cycle-time,projections}Аналитика (viewer). Детализация по итерации принимает ?iteration_id=
GET/projects/{id}/metrics/{velocity,burndown,story-types}Метрики (viewer)
GET / PUT/projects/{id}/preferencesВаши предпочтения доски для этого проекта (member)
МетодПутьОписание
GET/projects/{id}/eventsПоток событий с курсорной пагинацией (viewer)

Параметры запроса: since=<event_id>, types=story.created,story.transitioned,comment.created,…, limit=, cursor=. Ответ включает next_cursor. Передайте последний увиденный event_id как since, чтобы возобновить.

МетодПутьОписание
POST/projects/{id}/import (+ /json)Multipart-загрузка. source=pivotal, jira, asana, gitlab, shortcut, trello, linear, plane, plane_json.
wss://eastagiletracker.com/ws/control?token=<key>

Для интерактивного удалённого управления интерфейсом ({ "action": "get_state", "id": "req-1" }). Не канал данных — все чтения/записи идут через REST. Только для одного инстанса; не распределяется между репликами.

Эндпоинты записи (POST, PUT, DELETE) принимают заголовок Idempotency-Key. Тот же ключ + то же тело воспроизводят кэшированный ответ (окно 24 часа); тот же ключ + другое тело возвращают 409 idempotency_conflict. Не применяется к GET/HEAD/OPTIONS, /auth/* или путям /attachments. Ответы 5xx никогда не кэшируются — повтор достигает обработчика.

Эндпоинты списков принимают cursor=<opaque> и limit=<n≤200>. Когда заданы, ответ — это { "items": [...], "next_cursor": "<str|null>" }; передайте next_cursor обратно для перехода на страницу. Некоторые списки также возвращают заголовок X-Tracker-Pagination-Total.

Эндпоинты списков принимают fields= (через запятую), чтобы возвращать только конкретные поля. story_id включается всегда; неизвестное имя поля возвращает 400 validation_failed с нарушающими именами в details.fields.

GET /projects/123/stories?fields=story_id,name,current_state,owners

У каждой JSON-ошибки есть code и error; некоторые добавляют details:

{ "code": "invalid_transition",
"error": "Cannot move story from `unstarted` to `accepted`",
"details": { "from": "unstarted", "to": "accepted", "allowed": ["started"] } }
СтатусcodeКогда
400invalid_parameterплохой ввод; сообщение в error, без details (большинство валидаций: пусто/длина/null-байт/email)
400validation_failedструктурированная ошибка ввода; details.fields — это массив имён нарушающих полей
401unauthenticatedотсутствующий/недействительный токен
403unauthorized_operationаутентифицирован, но недостаточная роль
404unfound_resourceне найдено — также возвращается не-участникам
409conflictконфликт ресурса (например, дубликат)
409idempotency_conflictIdempotency-Key повторно использован с другим телом
422invalid_transitionнедопустимое перемещение состояния; details несёт { from, to, allowed }
500internal_errorсбой сервера — обобщённое сообщение; безопасно повторять

details.fields — это JSON-массив имён полей (например, ["to"]), иногда с дополнительными ключами вроде max. Карты «поле→сообщение» нет.

{ "code": "validation_failed", "error": "unknown field(s): foo", "details": { "fields": ["foo"] } }

На ключ (на IP для эндпоинтов без аутентификации), токен-бакет GCRA:

  • Auth/auth/*: 0.5 запр/с, всплеск 20.
  • Public/contact, /feedback: 0.2 запр/с, всплеск 10.
  • Sensitive — сброс пароля: ~0.002 запр/с, всплеск 5.

Превышенный лимит возвращает 429 Too Many Requests с заголовком Retry-After и простым текстовым телом (не JSON-конвертом ошибки).