§ 7.1

Обзор и авторизация

Базовый адрес, токены, формат запросов и ответов.

обновлено 22 сентября 20269 мин чтениятолько на тарифахКомандаБизнес

REST API DoneBy принимает и отдаёт JSON по HTTPS. Через него задачи создаются из ваших систем, сроки попадают в отчёты, а списки синхронизируются с CRM или трекером. На этой странице — всё общее для всех методов: адрес, токены, формат данных, пагинация и безопасные повторы.

Доступ

API работает на тарифах Команда и Бизнес. На тарифе Старт токены создать нельзя. Лимит — 300 запросов в минуту на Команде и 1 200 на Бизнесе.

Базовый адрес и версия

Все запросы отправляются на https://doneby.app/api/v1. Версия — часть пути: сейчас это v1.

  • Без смены версии мы добавляем новые поля в ответы, новые необязательные параметры, новые методы и новые типы событий вебхуков.
  • Удаление и переименование полей, смена типа или смысла значения — только в новой версии (v2). Администраторы получат письмо заранее, а v1 продолжит работать параллельно.

Совет

Игнорируйте неизвестные поля в ответах и не проверяйте их строгой схемой — тогда добавление нового поля ничего у вас не сломает.

Токены

Доступ к API выдаётся токеном. Токен начинается с dbp_, создаётся в Настройки → API и показывается один раз. Создавать и отзывать токены могут владелец и администраторы пространства.

  1. Откройте Настройки → API и нажмите «Новый токен».
  2. Дайте токену имя, по которому его легко узнать в списке: «CRM → задачи», «Отчёт по срокам».
  3. Отметьте права (скоупы) — только те, что действительно нужны интеграции.
  4. Скопируйте токен и положите в хранилище секретов. После закрытия окна увидеть его снова нельзя — только выпустить новый.

Токен действует от имени участника, который его создал: видит те же списки и не может больше, чем позволяет его роль. Если участника удалят из пространства, его токены отзываются автоматически.

Права токена

СкоупЧто разрешаетМетоды
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 — ваш токен. Обе переменные берутся из окружения, а не из кода.

doneby.js
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=eyJpZCI6InRza184S2QyTHEifQ
Обойти все страницы
export 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 можно повторять и без ключа: повтор приводит к тому же результату.
POST с ключом идемпотентности
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.
см. также
Статья помогла?Отметьте галочкой — так мы понимаем, какие статьи дописать первыми.