Обзор и авторизация
Базовый адрес, токены, формат запросов и ответов.
REST API DoneBy принимает и отдаёт JSON по HTTPS. Через него задачи создаются из ваших систем, сроки попадают в отчёты, а списки синхронизируются с CRM или трекером. На этой странице — всё общее для всех методов: адрес, токены, формат данных, пагинация и безопасные повторы.
Доступ
API работает на тарифах Команда и Бизнес. На тарифе Старт токены создать нельзя. Лимит — 300 запросов в минуту на Команде и 1 200 на Бизнесе.
Базовый адрес и версия
Все запросы отправляются на https://doneby.app/api/v1. Версия — часть пути: сейчас это v1.
- Без смены версии мы добавляем новые поля в ответы, новые необязательные параметры, новые методы и новые типы событий вебхуков.
- Удаление и переименование полей, смена типа или смысла значения — только в новой версии (
v2). Администраторы получат письмо заранее, аv1продолжит работать параллельно.
Совет
Игнорируйте неизвестные поля в ответах и не проверяйте их строгой схемой — тогда добавление нового поля ничего у вас не сломает.
Токены
Доступ к API выдаётся токеном. Токен начинается с dbp_, создаётся в Настройки → API и показывается один раз. Создавать и отзывать токены могут владелец и администраторы пространства.
- Откройте Настройки → API и нажмите «Новый токен».
- Дайте токену имя, по которому его легко узнать в списке: «CRM → задачи», «Отчёт по срокам».
- Отметьте права (скоупы) — только те, что действительно нужны интеграции.
- Скопируйте токен и положите в хранилище секретов. После закрытия окна увидеть его снова нельзя — только выпустить новый.
Токен действует от имени участника, который его создал: видит те же списки и не может больше, чем позволяет его роль. Если участника удалят из пространства, его токены отзываются автоматически.
Права токена
| Скоуп | Что разрешает | Методы |
|---|---|---|
tasks:read | Читать задачи, подзадачи и чек-листы | GET /tasks, GET /tasks/{id} |
tasks:write | Создавать, менять, выполнять, возвращать в работу и удалять задачи | POST /tasks, PATCH /tasks/{id}, POST /tasks/{id}/complete, POST /tasks/{id}/reopen, DELETE /tasks/{id} |
lists:read | Читать списки и разделы | GET /lists, GET /lists/{id}/sections |
lists:write | Создавать, менять и архивировать списки, управлять разделами | POST /lists, PATCH /lists/{id}, POST /lists/{id}/archive, POST, PATCH, DELETE для разделов |
comments:read | Читать комментарии к задачам | GET /tasks/{id}/comments |
comments:write | Добавлять комментарии от имени владельца токена | POST /tasks/{id}/comments |
members:read | Видеть участников пространства и их роли | GET /members |
webhooks:write | Подключать, просматривать и удалять адреса вебхуков | GET /webhooks, POST /webhooks, DELETE /webhooks/{id} |
Право на запись не включает чтение: интеграции, которая создаёт задачи и потом ищет их через GET /tasks, нужны оба скоупа — tasks:write и tasks:read. Ответ на запрос записи при этом всегда содержит изменённый объект.
Важно
Токен — это пароль к данным пространства. Не храните его в коде фронтенда, мобильного приложения или в репозитории. Если токен утёк, отзовите его в Настройки → API: запросы с ним сразу начнут получать 401 unauthorized.
Совет
Заводите отдельный токен на каждую интеграцию. Тогда одну можно отключить, не трогая остальные, а в списке токенов видно, какая из них когда последний раз обращалась к API.
Авторизация
Передавайте токен в заголовке Authorization по схеме Bearer. В параметрах адреса токен не принимается — так он не окажется в логах прокси и истории браузера.
curl "https://doneby.app/api/v1/lists?limit=1" \
-H "Authorization: Bearer $DONEBY_TOKEN"Нет заголовка, токен неверный или отозван — ответ 401 unauthorized. Токен верный, но не хватает скоупа, роли или тариф без API — 403 forbidden. Все коды — в разделе Коды ошибок.
Формат запросов и ответов
- Только HTTPS. Запросы по HTTP отклоняются, а не перенаправляются.
- Тела запросов и ответов — JSON в UTF-8. В запросах с телом передавайте
Content-Type: application/json. GET— чтение,POST— создание и действия (/complete,/archive),PATCH— частичное изменение,DELETE— удаление.PATCHменяет только переданные поля. Чтобы очистить поле, передайтеnull.- Имена полей — в
snake_case. Идентификаторы — строки с префиксом типа:tsk_,lst_,sec_,cmt_,usr_,whk_,evt_. - Один объект возвращается как есть, коллекция — в обёртке
{ "data": [...], "next_cursor": ... }. - Коды ответа:
200— успех,201— объект создан,204— успех без тела,4xxи5xx— ошибка в едином формате. - В каждом ответе есть заголовок
X-Request-Id. Укажите его, если пишете в поддержку.
Даты и часовые пояса
Метки времени (created_at, updated_at, completed_at) — в формате ISO 8601 с часовым поясом. В ответах время всегда в UTC: 2026-09-14T09:30:00Z. В запросах можно указывать любое смещение — 2026-09-14T12:30:00+03:00. Время без пояса отклоняется с 400 validation_error, чтобы задача не уехала на три часа.
Срок задачи хранится иначе, потому что «пятница, 15:00» — это время в конкретном городе. У задачи три поля: due_date (YYYY-MM-DD), due_time (HH:MM или null, если срок на весь день) и timezone (IANA, например Europe/Moscow). Подробнее — в описании объекта задачи.
Минимальный клиент на JavaScript
Обёртка над fetch для Node.js 18 и новее. В примерах ниже DONEBY_API_URL — это https://doneby.app/api/v1, а DONEBY_TOKEN — ваш токен. Обе переменные берутся из окружения, а не из кода.
const BASE = process.env.DONEBY_API_URL;
const TOKEN = process.env.DONEBY_TOKEN;
export async function api(method, path, { body, query, key } = {}) {
const params = Object.entries(query || {}).filter(([, v]) => v != null);
const qs = params.length ? '?' + new URLSearchParams(params) : '';
const res = await fetch(BASE + path + qs, {
method,
headers: {
Authorization: `Bearer ${TOKEN}`,
'Content-Type': 'application/json',
...(key ? { 'Idempotency-Key': key } : {}),
},
body: body ? JSON.stringify(body) : undefined,
});
if (res.status === 204) return null;
const data = await res.json();
if (!res.ok) {
const err = new Error(data.error.message);
throw Object.assign(err, data.error, { status: res.status });
}
return data;
}Пагинация
Методы, которые возвращают коллекции (GET /tasks, GET /lists, GET /members, GET /tasks/{id}/comments), отдают данные страницами с курсором. Параметр limit — от 1 до 100, по умолчанию 50. В ответе — массив data и строка next_cursor. Если next_cursor равен null, страниц больше нет.
curl -G https://doneby.app/api/v1/tasks \
-H "Authorization: Bearer $DONEBY_TOKEN" \
-d list_id=lst_R4m2Vx \
-d limit=50{
"data": [
{
"id": "tsk_5Rb1Tc",
"title": "Выкатить релиз 2.4",
"due_date": "2026-09-17",
"completed": false
},
{
"id": "tsk_8Kd2Lq",
"title": "Прогнать регрессию на тестовом стенде",
"due_date": "2026-09-16",
"completed": false
}
],
"next_cursor": "eyJpZCI6InRza184S2QyTHEifQ"
}Следующая страница — тот же запрос с теми же фильтрами и параметром cursor. Курсор непрозрачный: не разбирайте и не собирайте его сами, просто передавайте обратно.
curl -G https://doneby.app/api/v1/tasks \
-H "Authorization: Bearer $DONEBY_TOKEN" \
-d list_id=lst_R4m2Vx \
-d limit=50 \
-d cursor=eyJpZCI6InRza184S2QyTHEifQexport async function* allTasks(filters = {}) {
let cursor = null;
do {
const query = { ...filters, limit: 100, cursor };
const page = await api('GET', '/tasks', { query });
yield* page.data;
cursor = page.next_cursor;
} while (cursor);
}
for await (const task of allTasks({ list_id: 'lst_R4m2Vx', completed: false })) {
console.log(task.due_date, task.title);
}Идемпотентность
Сеть рвётся в самый неудобный момент: запрос ушёл, ответ не пришёл, и непонятно, создалась ли задача. Чтобы повтор не создал дубль, передавайте с каждым POST заголовок Idempotency-Key — уникальную строку, удобнее всего UUID.
- Повтор с тем же ключом и тем же телом вернёт сохранённый ответ первого запроса и ничего не создаст заново. Ключ помнится 24 часа.
- Тот же ключ с другим телом —
409 conflict. Так DoneBy защищает от случайного переиспользования ключа. - Если первый запрос с этим ключом ещё выполняется, повтор получит
409 conflictсdetails.reason=in_progress. Подождите пару секунд и повторите. GET,PATCHиDELETEможно повторять и без ключа: повтор приводит к тому же результату.
curl -X POST https://doneby.app/api/v1/tasks \
-H "Authorization: Bearer $DONEBY_TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 6f0f8a8e-3c1d-4b8e-9a51-2b7c1d9e4a10" \
-d '{
"title": "Сверка с бухгалтерией за квартал",
"list_id": "lst_Op5Nw1",
"due_date": "2026-09-30"
}'Важно
Генерируйте ключ один раз на действие и сохраняйте его вместе с задачей в своей очереди. Новый ключ на каждую попытку ломает всю защиту от дублей.
Лимиты запросов
Лимит считается на рабочее пространство, по всем токенам вместе: 300 запросов в минуту на тарифе Команда и 1 200 на тарифе Бизнес. Остаток видно в заголовках X-RateLimit-Limit, X-RateLimit-Remaining и X-RateLimit-Reset каждого ответа. При превышении приходит 429 rate_limited с заголовком Retry-After. Как правильно ждать и повторять — в разделе Лимиты.
Что дальше
- Задачи — объект задачи и все методы: получить, создать, изменить, выполнить, удалить, прокомментировать.
- Списки и участники — списки, разделы и участники пространства.
- Вебхуки — узнавать об изменениях сразу, без опроса API.
- Коды ошибок — что означает каждый ответ с ошибкой. Не нашли ответ — пишите на support@doneby.app.