API MBC Dash
Всё, что делает продукт, доступное тому, кто не является браузером: скриптам, CI, вашим собственным инструментам, агенту, которого вы написали сами.
Это руководство. Рассуждения о том, почему оно устроено именно так — почему поверхностей две, почему ключ несёт скоупы, почему идентификаторы работают как работают, — в описании решений.
Где это
https://dash.mbc-apps.com/api/v1
Всё ниже — относительно этого адреса. /api — само приложение; /v1 — та часть, которая обещает
не меняться у вас под руками.
Есть вторая поверхность,
/api/…без версии, которой пользуется веб-приложение. Она не для вас: она меняется тогда, когда это нужно интерфейсу, и без предупреждения. Если вы ловите себя на обращении к ней, потому что чего-то не хватает в/api/v1, — скажите об этом: недостающее и есть ошибка.
Как получить ключ
Настройки → Ключи API → Выпустить ключ. Вы выбираете три вещи:
- Что можно делать — скоупы, перечислены ниже. Берите наименьший набор, который работает.
- Куда можно ходить — проекты. Оставите пусто — ключ дотянется всюду, куда дотягиваетесь вы; выберете несколько — на них и остановится, даже там, куда вас бы пустили. Интеграция, которая только заводит баги в один проект, и доставать должна только до одного проекта.
- Насколько долго — 30, 90, 180 или 365 дней. «Навсегда» нет, и это намеренно.
Секрет показывается один раз. Хранится только его хэш, поэтому восстановить нельзя: потеряли — выпустите другой, а первый отзовите.
curl https://dash.mbc-apps.com/api/v1/workspaces \
-H "Authorization: Bearer mbc_a1b2c3d4-…_xK9…"
X-API-Key: mbc_… тоже работает — для клиентов, которые знают только это написание.
Ключ действует от вашего имени. Он никогда не может больше вас, а скоупы только сужают это дальше. Изменение или отзыв ключа вступают в силу на следующем вызове — никакого токена, который сначала должен истечь.
Имена, а не идентификаторы
Везде, где путь или поле принимает идентификатор, годится любая из двух форм:
| Что | Пишется как | Или как |
|---|---|---|
| Задача | PROD-12 | её uuid |
| Проект | PROD | его uuid |
| Статус | В работе (его имя внутри проекта) | его uuid |
| Своё поле | client (его ключ) или Клиент (его подпись) | его uuid |
| Рабочее пространство | его имя | его uuid |
| Человек | его uuid | — |
То есть вот это работает:
curl -X PATCH https://dash.mbc-apps.com/api/v1/tasks/PROD-12 \
-H "Authorization: Bearer $KEY" -H 'Content-Type: application/json' \
-d '{"status":"В работе","priority":"HIGH"}'
Имена сопоставляются без учёта регистра и всегда внутри того, чему принадлежат: имя статуса ничего не значит за пределами своего проекта. Если имя подходит более чем одному объекту, вы получите ошибку со списком кандидатов, а не молчаливый выбор первого.
Переименование статуса ломает интеграцию, которая ссылалась на него по имени. Это цена читаемых вызовов; каждый ответ несёт ещё и uuid, так что храните его, если хотите быть застрахованы от переименований.
Каждый объект несёт также url в веб-приложение, чтобы скрипт мог сообщить о чём-то, на что
человеку можно кликнуть.
Что можно вызывать
Двадцать две операции. Каждая называет нужный ей скоуп.
Задачи
| Скоуп | ||
|---|---|---|
GET | /tasks/{task} | tasks:read |
POST | /tasks/search | tasks:read |
GET | /tasks/{task}/subtasks | tasks:read |
POST | /spaces/{space}/tasks | tasks:write |
PATCH | /tasks/{task} | tasks:write |
POST | /tasks/{task}/assignees | tasks:write |
DELETE | /tasks/{task}/assignees/{user} | tasks:write |
POST | /tasks/{task}/tags | tasks:write |
DELETE | /tasks/{task}/tags/{tag} | tasks:write |
PUT | /tasks/{task}/fields/{field} | tasks:write |
DELETE | /tasks/{task} | tasks:delete |
Удаление обратимо тридцать дней: задача и её подзадачи уходят в корзину вместе и возвращаются
вместе. Именно поэтому tasks:delete — отдельный скоуп: «может править задачи» и «может их
убирать» — разные решения.
Комментарии
| Скоуп | ||
|---|---|---|
GET | /tasks/{task}/comments | comments:read |
POST | /tasks/{task}/comments | comments:write |
Тексты — Markdown.
Структура
| Скоуп | ||
|---|---|---|
GET | /workspaces | structure:read |
GET | /workspaces/{workspace}/spaces | structure:read |
GET | /spaces/{space} | structure:read |
GET | /spaces/{space}/lists | structure:read |
GET | /spaces/{space}/statuses | structure:read |
GET | /spaces/{space}/fields | structure:read |
POST | /workspaces/{workspace}/spaces | structure:write |
POST | /spaces/{space}/lists | structure:write |
GET | /workspaces/{workspace}/members | members:read |
Проекту нужно только имя; не укажете key — он будет выведен из имени. Задаче нужен только проект:
список подберётся сам, а если у проекта его нет — создастся.
Полный перечень, от самого API
Документ OpenAPI описывает каждую операцию, её аргументы и её ответы:
GET /api/v3/api-docs
Swagger UI — по адресу /api/swagger-ui.html. Операции /v1 помечены тегом Public API.
Поиск задач
POST /tasks/search говорит на том же языке фильтров, что и подборки в интерфейсе, и из этого
следуют две полезные вещи: вы не можете выразить поиск, которого продукт не покажет, а всё, что
выразили, можно сохранить как подборку и открыть человеком.
curl -X POST https://dash.mbc-apps.com/api/v1/tasks/search \
-H "Authorization: Bearer $KEY" -H 'Content-Type: application/json' \
-d '{
"conditions": [
{"field": "space", "op": "in", "values": ["PROD"]},
{"field": "status", "op": "notIn", "values": ["Готово"]},
{"field": "assignee", "op": "in", "values": ["me"]},
{"field": "due", "op": "overdue"}
],
"sort": [{"field": "due", "dir": "asc"}],
"limit": 50
}'
Условия соединяются по И. Значения внутри одного условия — по ИЛИ.
Поля: workspace, space, status, statusCategory, assignee, creator, priority,
type, tag, due, updated, created, customField, title, text.
Операторы: in, notIn, empty, before, after, between, overdue, today,
thisWeek, contains.
Не всякий оператор подходит всякому полю, и запрос неподходящего — ошибка, которая об этом
говорит. Даты идут в from / to как ISO-моменты, а не в values.
Две вещи, которые стоит знать:
updated — это то, как вы спрашиваете, что изменилось. Без него интеграции приходится
перечитывать всё на каждом запуске:
{"field": "updated", "op": "after", "from": "2026-08-01T00:00:00Z"}
customField требует, чтобы поиск сводился к одному проекту, и называет поле в key:
{"field": "customField", "op": "in", "key": "Клиент", "values": ["Acme"]}
Описание поля принадлежит проекту, поэтому одно и то же имя может означать число в одном и дату в
другом. Если ваш поиск достаёт до нескольких проектов, вы получите ошибку с объяснением, а не
догадку. Операторы здесь — in, notIn и empty.
me означает владельца ключа для assignee и creator. today и thisWeek вычисляются на
каждый запрос в часовом поясе вызывающего — передайте его как "timezone": "Europe/Moscow", если
это важно.
Скоупы
| Скоуп | Что позволяет ключу |
|---|---|
tasks:read | читать задачи, их подзадачи, значения их своих полей |
tasks:write | создавать и изменять задачи, исполнителей, метки, значения полей |
tasks:delete | удалять задачи (обратимо тридцать дней) |
comments:read / comments:write | читать / писать комментарии |
attachments:read / attachments:write | читать / добавлять вложения — зарезервировано, операций пока нет |
structure:read | видеть рабочие пространства, проекты, списки, статусы, описания полей |
structure:write | создавать и изменять их |
structure:delete | удалять или архивировать их — зарезервировано, ни одна операция пока не использует |
views:read / views:write | читать / писать подборки — зарезервировано, операций пока нет |
members:read | видеть, кто состоит в рабочем пространстве — нужно, прежде чем кого-то назначать |
audit:read | читать журнал аудита |
Скоупа для выпуска ключей намеренно нет. Ключ никогда не может выпустить другой ключ: иначе утёкший ключ перевыпускает себя с более широкими правами, и отзыв перестаёт что-либо значить.
Когда что-то идёт не так
Ошибки — документы RFC 7807 с устойчивым машиночитаемым
code:
{
"type": "https://errors.mbc.studio/validation_error",
"title": "Unprocessable Entity",
"status": 422,
"detail": "В этом проекте нет статуса «В работах»; доступны: [Открыта, В работе, Готово]",
"code": "validation_error",
"instance": "/api/v1/tasks/PROD-12",
"timestamp": "2026-08-18T10:15:00Z"
}
Ветвитесь по code, показывайте detail — он написан, чтобы его читали, и обычно говорит, что
отправить вместо этого.
| Статус | Значит |
|---|---|
401 | ключа нет, он истёк или отозван |
403 | ключу не хватает скоупа; detail называет какого |
404 | этого не существует — или ваш ключ огорожен от него, что намеренно отвечает так же |
409 | конфликт, например ключ проекта уже занят |
422 | запрос понят и отклонён; detail говорит почему |
429 | слишком быстро — см. лимиты |
Каждый ответ несёт X-Request-Id. Приводите его, если нужно, чтобы кто-то что-то посмотрел.
Что изменится, а что нет
/api/v1 только дополняется. Новые эндпойнты, новые необязательные поля запроса и новые поля
ответа могут появиться в любой момент — поэтому игнорируйте незнакомые поля, а не падайте на них.
Ничто не удаляется, не переименовывается, не сужается и не становится обязательным. Ломающее
изменение стало бы /api/v2 рядом с этим, с объявленным периодом сосуществования.
Это проверяется механически: сгенерированное описание /api/v1 лежит в репозитории, и сборка
падает на любом изменении, которое обещание запрещает.
Отказ от поддержки, если он когда-нибудь случится, придёт заголовками Deprecated и Sunset и
пометкой в документе OpenAPI, а не письмом.
Как безопасно повторять
Таймаут не говорит вам ничего о том, произошла работа или нет. Отправляйте на записи
Idempotency-Key, и повтор получит первый ответ вместо того, чтобы сделать всё заново:
curl -X POST https://dash.mbc-apps.com/api/v1/spaces/PROD/tasks \
-H "Authorization: Bearer $KEY" -H 'Content-Type: application/json' \
-H 'Idempotency-Key: nightly-sync-2026-08-18-item-7' \
-d '{"title":"Ровно одна"}'
Повтор отвечает тем же статусом и тем же телом, плюс Idempotent-Replay: true, чтобы вы могли
отличить. Записи хранятся сутки.
Один ключ на один отдельный вызов. Повторное использование ключа с другим телом отклоняется с
409, а не отвечается прежним результатом: почти всегда это ключ, вынесенный из цикла, и ответить
на него значило бы, что вторая сущность молча никогда не появилась. Два одинаковых запроса,
пришедших одновременно, тоже получают 409 на проигравшем, с сообщением, что первый ещё
выполняется; повторите его.
Ключи ваши, а не общие: другая интеграция может использовать ту же строку и иметь в виду другое.
Лимиты
На ключ, в минуту, тремя ярусами:
| По умолчанию | |
|---|---|
| Чтения | 600/мин |
| Записи | 120/мин |
| Удаления | 20/мин |
Сверх лимита — 429; притормозите, а не повторяйте немедленно.
Удаления намеренно самые тугие, и массового удаления в API нет — поэтому «удалить всё выполненное» стоит одного вызова на задачу и упирается в этот лимит задолго до конца списка. Это задуманное поведение, а не препятствие, которое надо обойти.
Человека в браузере эти лимиты не касаются; они для машин.
Как быть хорошим соседом
- Спрашивайте, что изменилось, а не всё подряд:
updated after <прошлый запуск>— это одна страница вместо всех. - Храните uuid, если не готовы сломаться от переименования; пишите имена, если предпочитаете, чтобы вызовы читались.
- Сужайте скоупы и огораживайте ключи проектами. Радиус поражения утёкшего ключа — ровно то, что вы ему дали.
Чего здесь пока нет
Записано, чтобы вы не искали:
- Вебхуков. API работает только на вытягивание: узнать, что что-то изменилось, нельзя. Это следующая работа.
- Вложения и подборки имеют скоупы, но пока не имеют операций.
Почему каждое отложено — в описании решений.