REST API

Программный доступ к вашим проектам и ошибкам. Ingest событий — отдельный endpoint.

Base URLhttps://dev-logs.ru/api/v1
Создать API-ключ →REST · JSON · Bearer API key

REST API для программного доступа к **вашим** проектам и ошибкам. Каждый запрос авторизуется личным API-ключом — доступ только к данным владельца ключа.

Базовый URL: https://dev-logs.ru/api/v1

Ingest событий (от SDK) — отдельный endpoint, см. INGEST API.

Аутентификация

  1. Войдите в личный кабинет.
  2. В разделе **API-ключи** создайте ключ (формат dl_live_…).
  3. Передавайте ключ в каждом запросе:
http
Authorization: Bearer dl_live_xxxxxxxx

Ключ показывается **один раз** при создании. Храните его как пароль. Отозванные ключи перестают работать.

Ограничения доступа

  • API-ключ привязан к вашему аккаунту.
  • Проекты, issues и events других пользователей **недоступны** (ответ 404).
  • Лимиты проектов на аккаунт — **100** проектов (бесплатный тариф), те же что в веб-интерфейсе.

Формат ответов

Успешные ответы — JSON с полезной нагрузкой (объект или массив в корне либо в именованном поле).

Ошибки — JSON:

json
{
  "error": "код_ошибки",
  "message": "Человекочитаемое описание на русском"
}

Эндпоинты

Текущий пользователь

GET/api/v1/me

Ответ 200

json
{
  "id": "clx123abc",
  "email": "you@example.com",
  "name": "Иван",
  "createdAt": "2026-06-07T10:00:00.000Z",
  "projectCount": 2
}

Проекты

Список проектов

GET/api/v1/projects

Ответ 200

json
{
  "projects": [
    {
      "id": "clx456def",
      "name": "Моё приложение",
      "slug": "my-app",
      "dsn": "public-dsn-token",
      "collectorKey": "docker:host1:mystack:api",
      "createdAt": "2026-06-07T10:00:00.000Z",
      "updatedAt": "2026-06-07T12:00:00.000Z",
      "stats": {
        "issues": 5,
        "events": 120,
        "unresolvedIssues": 2,
        "issuesByLevel": {
          "error": 4,
          "warning": 1,
          "info": 0
        },
        "sourceMaps": 0,
        "lastIssueAt": "2026-06-07T09:30:00.000Z",
        "lastEventAt": "2026-06-07T09:30:00.000Z"
      },
      "settings": {
        "telegramEnabled": false,
        "telegramConfigured": false,
        "emailEnabled": true,
        "minLevel": "error",
        "s3": {
          "enabled": false,
          "configured": true,
          "endpoint": null,
          "bucket": null,
          "region": null,
          "forcePathStyle": false,
          "prefix": null,
          "source": "platform"
        },
        "updatedAt": "2026-06-07T10:00:00.000Z"
      },
      "urls": {
        "dashboard": "https://dev-logs.ru/dashboard/projects/clx456def",
        "settings": "https://dev-logs.ru/dashboard/projects/clx456def/settings",
        "issues": "https://dev-logs.ru/api/v1/projects/clx456def/issues",
        "ingest": "https://dev-logs.ru/api/ingest"
      }
    }
  ]
}

Поля `stats`

ПолеОписание
issuesВсего групп ошибок (issues)
eventsВсего событий
unresolvedIssuesIssues со статусом unresolved
issuesByLevelРазбивка issues по error / warning / info
sourceMapsЗагруженных source maps
lastIssueAtlastSeen последней группы или null
lastEventAtВремя последнего события или null

Поля `settings`

ПолеОписание
telegramEnabledУведомления Telegram включены
telegramConfiguredЗадан chat id (без раскрытия id)
emailEnabledEmail-уведомления
minLevelМинимальный уровень для алертов
s3S3 для source maps (не для событий ingest), без секретов
updatedAtКогда настройки менялись

Поля `settings.s3`

ПолеОписание
enabledУ проекта включено своё S3 (override)
configuredХранилище доступно: свой bucket или platform S3_* на сервере
endpointURL S3 (только для source: "project")
bucketИмя bucket (только для source: "project")
regionРегион
forcePathStylePath-style URLs (MinIO и аналоги)
prefixПрефикс ключей объектов
sourceproject — свои creds в кабинете; platform — из .env сервера; none — не настроено

Настройку S3 в кабинете меняют на странице **Настройки проекта** (не через REST). REST отдаёт только статус.

**Поля urls** — ссылки для интеграций (кабинет, API issues, ingest).

Пустой аккаунт: { "projects": [] }.

Query-параметры

ПараметрОписание
orgФильтр организации (all или id)
teamФильтр команды
collectorKeyПоиск одного проекта по ключу коллектора (для агентов)
GET/api/v1/projects?collectorKey=docker:host1:mystack

См. также публичную документацию: /docs/collectors.

Ensure проект (коллекторы)

Идемпотентное создание проекта для DevLogs Collector. Если проект с collectorKey уже есть в организации — **200**, иначе **201**.

По умолчанию Docker-коллектор создаёт **один проект на compose stack**:

POST/api/v1/projects/ensure
Content-Type: application/json

{
  "name": "docker / mystack",
  "collectorKey": "docker:host1:mystack",
  "environment": "production"
}

Legacy (отдельный проект на service): collectorKey=docker:host1:mystack:api при DEVLOGS_DOCKER_PROJECT_MAP=service.

POST/api/v1/projects/ensure
Content-Type: application/json

{
  "name": "docker / mystack / api",
  "collectorKey": "docker:host1:mystack:api",
  "environment": "staging"
}
ПолеТипОбязательноОписание
namestringдаОтображаемое имя проекта
collectorKeystringдаСтабильный ключ источника (1–256 символов, a-z0-9:._/-)
environmentstringнетПодсказка для агента (не сохраняется в проекте)

Ответ 200 / 201

json
{
  "project": {
    "id": "clx789ghi",
    "name": "docker / mystack",
    "slug": "docker-mystack",
    "dsn": "auto-generated-dsn",
    "collectorKey": "docker:host1:mystack",
    "urls": { "ingest": "https://dev-logs.ru/api/ingest" }
  },
  "created": true
}

**Ответ 410** — проект с этим collectorKey был удалён пользователем; повторное auto-provision запрещено (collector_key_revoked). Коллектор должен прекратить ingest для этого ключа.

Восстановить ключ коллектора

POST/api/v1/collector-keys/restore
Authorization: Bearer dl_live_xxxxxxxx
Content-Type: application/json

{ "collectorKey": "docker:host1:mystack" }

Ответ 200

json
{ "ok": true, "collectorKey": "docker:host1:mystack" }

После восстановления агент снова может вызвать POST /api/v1/projects/ensure. Если ключ уже записан в локальный revoked-keys.json на хосте коллектора, удалите его оттуда или перезапустите агент.

В кабинете: **Коллекторы → Отозванные ключи → «Включить снова»** (роли owner, admin, member).

Создать проект

POST/api/v1/projects
Content-Type: application/json

{ "name": "Новый проект" }

Тело запроса

ПолеТипОбязательноОписание
namestringдаНазвание проекта (не пустое после trim)

Ответ 201

json
{
  "project": {
    "id": "clx789ghi",
    "name": "Новый проект",
    "slug": "novyj-proekt",
    "dsn": "auto-generated-dsn",
    "createdAt": "2026-06-07T14:00:00.000Z",
    "updatedAt": "2026-06-07T14:00:00.000Z",
    "stats": {
      "issues": 0,
      "events": 0
    },
    "settings": {
      "telegramEnabled": false,
      "minLevel": "error"
    }
  }
}

**Ответ 400** — пустое имя:

json
{
  "error": "validation_error",
  "message": "Поле name обязательно"
}

**Ответ 403** — лимит проектов:

json
{
  "error": "limit_exceeded",
  "message": "Достигнут лимит проектов для бесплатного аккаунта (100)"
}

Получить проект

GET/api/v1/projects/{projectId}

**Ответ 200** — объект { "project": { … } } с теми же полями, что в списке (stats, settings, urls).

json
{
  "project": {
    "id": "clx456def",
    "name": "Моё приложение",
    "slug": "my-app",
    "dsn": "public-dsn-token",
    "createdAt": "2026-06-07T10:00:00.000Z",
    "updatedAt": "2026-06-07T12:00:00.000Z",
    "stats": {
      "issues": 5,
      "events": 120,
      "unresolvedIssues": 2,
      "issuesByLevel": { "error": 4, "warning": 0, "info": 1 },
      "sourceMaps": 0,
      "lastIssueAt": "2026-06-07T09:30:00.000Z",
      "lastEventAt": "2026-06-07T09:30:00.000Z"
    },
    "settings": {
      "telegramEnabled": false,
      "telegramConfigured": false,
      "emailEnabled": true,
      "minLevel": "error",
      "updatedAt": "2026-06-07T10:00:00.000Z"
    },
    "urls": {
      "dashboard": "https://dev-logs.ru/dashboard/projects/clx456def",
      "settings": "https://dev-logs.ru/dashboard/projects/clx456def/settings",
      "issues": "https://dev-logs.ru/api/v1/projects/clx456def/issues",
      "ingest": "https://dev-logs.ru/api/ingest"
    }
  }
}

Ответ 404

json
{
  "error": "not_found",
  "message": "Проект не найден"
}

Переименовать проект

PATCH/api/v1/projects/{projectId}
Content-Type: application/json

{ "name": "Новое имя" }

Тело запроса

ПолеТипОбязательноОписание
namestringдаНовое название

**Ответ 200** — объект { "project": { … } } (та же структура, что при GET).

**Ответ 400 / 404** — как при создании и GET.

Удалить проект

DELETE/api/v1/projects/{projectId}

Ответ 200

json
{
  "ok": true
}

Удаляются все связанные issues, events и source maps.

**Ответ 404** — проект не найден или чужой.


Source maps

Загрузка .map файлов для символизации stack trace в кабинете. Требуется настроенный S3 (platform на сервере или в настройках проекта). Подробнее: SOURCE_MAPS.md.

Список source maps

GET/api/v1/projects/{projectId}/sourcemaps

Ответ 200

json
{
  "sourceMaps": [
    {
      "id": "clxmap01",
      "projectId": "clx456def",
      "release": "1.2.0",
      "filename": "app.js",
      "size": 8421,
      "uploadedAt": "2026-06-07T15:00:00.000Z"
    }
  ]
}

Загрузить source map

POST/api/v1/projects/{projectId}/sourcemaps
Content-Type: multipart/form-data

Поля form-data

ПолеТипОбязательноОписание
releasestringдаВерсия релиза (как в SDK)
filenamestringдаИмя bundle в stack trace
filefileдаJSON source map (.map), макс. 50 МБ

Ответ 201

json
{
  "sourceMap": {
    "id": "clxmap01",
    "projectId": "clx456def",
    "release": "1.2.0",
    "filename": "app.js",
    "size": 8421,
    "uploadedAt": "2026-06-07T15:00:00.000Z"
  }
}

**Ответ 400** — нет S3, неверный JSON или превышен размер:

json
{
  "error": "validation_error",
  "message": "S3 не настроен — включите хранилище в настройках проекта или задайте S3_* на сервере"
}

Удалить source map

DELETE/api/v1/projects/{projectId}/sourcemaps/{mapId}

Ответ 200

json
{
  "ok": true
}

Удаляет объект из S3 и запись в БД.

**Ответ 404** — проект или map не найден.


Issues (группы ошибок)

Список issues проекта

GET/api/v1/projects/{projectId}/issues?status=unresolved&level=error&q=TypeError&page=1&limit=20

Query-параметры

ПараметрОписание
statusunresolved, resolved или all (по умолчанию — все)
levelerror, warning, info или all
qПоиск по типу и тексту (регистронезависимо)
pageСтраница, с 1 (по умолчанию 1)
limitРазмер страницы, макс. 100 (по умолчанию 20)

Ответ 200

json
{
  "issues": [
    {
      "id": "clxissue01",
      "projectId": "clx456def",
      "type": "TypeError",
      "message": "Cannot read properties of undefined",
      "level": "error",
      "status": "unresolved",
      "eventCount": 47,
      "userCount": 3,
      "firstSeen": "2026-06-06T08:00:00.000Z",
      "lastSeen": "2026-06-07T09:30:00.000Z"
    }
  ],
  "pagination": {
    "page": 1,
    "limit": 20,
    "total": 5,
    "totalPages": 1
  }
}

**Ответ 404** — проект не найден.

Получить issue

GET/api/v1/projects/{projectId}/issues/{issueId}

Ответ 200

json
{
  "issue": {
    "id": "clxissue01",
    "projectId": "clx456def",
    "type": "TypeError",
    "message": "Cannot read properties of undefined",
    "level": "error",
    "status": "unresolved",
    "eventCount": 47,
    "userCount": 3,
    "firstSeen": "2026-06-06T08:00:00.000Z",
    "lastSeen": "2026-06-07T09:30:00.000Z"
  }
}

Ответ 404

json
{
  "error": "not_found",
  "message": "Issue не найден"
}

Изменить статус issue

PATCH/api/v1/projects/{projectId}/issues/{issueId}
Content-Type: application/json

{ "status": "resolved" }

Тело запроса

ПолеТипОбязательноОписание
statusstringдаresolved или unresolved

Ответ 200

json
{
  "issue": {
    "id": "clxissue01",
    "projectId": "clx456def",
    "type": "TypeError",
    "message": "Cannot read properties of undefined",
    "level": "error",
    "status": "resolved",
    "eventCount": 47,
    "userCount": 3,
    "firstSeen": "2026-06-06T08:00:00.000Z",
    "lastSeen": "2026-06-07T09:30:00.000Z"
  }
}

**Ответ 400** — неверный status:

json
{
  "error": "validation_error",
  "message": "status должен быть resolved или unresolved"
}

События (events)

Список событий issue

GET/api/v1/projects/{projectId}/issues/{issueId}/events?page=1&limit=50

Query-параметры

ПараметрОписание
pageСтраница, с 1 (по умолчанию 1)
limitРазмер страницы, макс. 100 (по умолчанию 50)

Ответ 200

json
{
  "events": [
    {
      "id": "clxevent01",
      "groupId": "clxissue01",
      "projectId": "clx456def",
      "timestamp": "2026-06-07T09:30:00.000Z",
      "message": "Cannot read properties of undefined",
      "level": "error",
      "stackTrace": [
        {
          "filename": "app.js",
          "function": "handleClick",
          "lineno": 42,
          "colno": 11
        }
      ],
      "context": {
        "component": "checkout"
      },
      "user": {
        "id": "user-42"
      },
      "tags": {
        "browser": "chrome"
      },
      "breadcrumbs": [],
      "extra": {},
      "sdkVersion": "0.2.4",
      "release": "1.0.0",
      "environment": "production"
    }
  ],
  "pagination": {
    "page": 1,
    "limit": 50,
    "total": 47,
    "totalPages": 1
  }
}

**Ответ 404** — проект или issue не найден.


Cron-мониторы (REST)

Check-in из приложений: POST /api/monitors/checkin с { "dsn", "slug", "status" } (plain DSN).

Список мониторов проекта

GET/api/v1/projects/{projectId}/monitors

Создать монитор

POST/api/v1/projects/{projectId}/monitors
Content-Type: application/json

{
  "name": "Nightly backup",
  "slug": "nightly-backup",
  "scheduleMinutes": 1440,
  "graceMinutes": 30
}

Удалить монитор

DELETE/api/v1/projects/{projectId}/monitors/{monitorId}

Коды ошибок

HTTPerrorОписание
401unauthorizedНет заголовка Authorization
401invalid_api_keyКлюч неверный, отозван или заблокирован пользователь
403limit_exceededЛимит проектов на аккаунт
404not_foundПроект, issue или пользователь не найден (или чужой)
409conflictДубликат slug монитора
400validation_errorНеверные параметры или тело запроса
400invalid_jsonТело запроса не JSON

Пример 401

json
{
  "error": "unauthorized",
  "message": "Укажите заголовок Authorization: Bearer <api_key>"
}

Примеры

curl — список проектов

bash
curl -s https://dev-logs.ru/api/v1/projects \
  -H "Authorization: Bearer dl_live_YOUR_KEY"

curl — отметить issue решённым

bash
curl -s -X PATCH \
  "https://dev-logs.ru/api/v1/projects/PROJECT_ID/issues/ISSUE_ID" \
  -H "Authorization: Bearer dl_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"status":"resolved"}'

curl — загрузить source map

bash
curl -s -X POST "https://dev-logs.ru/api/v1/projects/PROJECT_ID/sourcemaps" \
  -H "Authorization: Bearer dl_live_YOUR_KEY" \
  -F "release=1.0.0" \
  -F "filename=app.js" \
  -F "file=@dist/app.js.map"

JavaScript (fetch)

javascript
const res = await fetch("https://dev-logs.ru/api/v1/projects", {
  headers: { Authorization: `Bearer ${process.env.DEVLOGS_API_KEY}` },
});
const { projects } = await res.json();

Связь с Ingest API

ЗадачаAPI
Отправка ошибок из приложения (SDK)POST /api/ingest + DSN проекта
Auto-provision для коллекторовPOST /api/v1/projects/ensure + API-ключ
Управление проектами, просмотр issuesGET/POST /api/v1/projects + API-ключ
Cron-мониторыGET/POST/DELETE /api/v1/projects/…/monitors + API-ключ
Загрузка source mapsPOST /api/v1/projects/…/sourcemaps + API-ключ
Пометить issue resolvedPATCH /api/v1/projects/…/issues/…
Server-to-server provisioning (cloud-ide и др.)/api/v1/provisioning/* + сервисный ключ dl_svc_…

DSN проекта возвращается в поле dsn при GET /api/v1/projects и GET /api/v1/projects/{id}.


Provisioning API (server-to-server)

Для интеграции внешних продуктов (например cloud-ide): **1 пользователь IDE → 1 пользователь DevLogs**, **1 проект IDE → 1 проект DevLogs + per-project API-токен**.

Сервисный ключ

  • Префикс: dl_svc_… (отличается от пользовательского dl_live_…)
  • Выпуск: **Настройки организации → Сервисные ключи (provisioning)**
  • Передача: Authorization: Bearer dl_svc_… или заголовок X-DevLogs-Service-Key: dl_svc_…
  • Audience: принимается **только** на /api/v1/provisioning/*; на пользовательских эндпоинтах — 401
  • Скоупы: users:write, users:read, projects:write, api-keys:write, api-keys:read, api-keys:revoke

Эндпоинты

МетодПутьНазначение
POST/api/v1/provisioning/usersСоздать/вернуть пользователя (идемпотентно по externalId)
GET/api/v1/provisioning/users/{userId}Пользователь по внутреннему id
GET/api/v1/provisioning/users/by-external/{externalId}Пользователь по externalId
DELETE/api/v1/provisioning/users/{userId}Каскадное удаление (ключи, проекты)
POST/api/v1/provisioning/users/{userId}/projectsСоздать проект (идемпотентно по collectorKey)
POST/api/v1/provisioning/users/{userId}/api-keysВыпустить per-project ключ dl_live_…
GET/api/v1/provisioning/users/{userId}/api-keysСписок ключей (?projectId= опционально)
DELETE/api/v1/provisioning/api-keys/{keyId}Отозвать ключ

Per-project ключи ограничены одним проектом: чтение issues/events через обычный REST API; мутации — 403.

Формат ошибок provisioning: { "error": "…", "code": "machine_code" }. Коды: 200/201/400/401/403/404/409/410.

Существующий POST /api/v1/projects/ensure (под пользовательским ключом) **не изменён**.