Справочник API
Полный справочник пользовательского REST API — в репозитории:
docs/API.md. Здесь — то, что нужно знать до первого запроса.
База и формат
Все пути относительно /api/v1, формат JSON. Ответы и коды ошибок на
английском; язык интерфейса — забота клиента. Живость сервера —
GET /healthz (вне /api/v1).
Аутентификация
| Субъект | Механизм |
|---|---|
| Человек | Authorization: Bearer <access-токен>, 15 минут |
| Браузер | тот же заголовок + refresh в httpOnly-cookie |
| Identity | свой токен из /machine/login или /machine/enroll, скоуп «проект × окружение», TTL настраивается от 60 до 86400 с |
Заголовок X-Client (web, portal, cli, sdk, mobile) попадает в
аудит и решает, где окажется refresh-токен: браузеру он выдаётся только в
cookie.
Машинные маршруты:
| Маршрут | Что делает |
|---|---|
POST /machine/login | client ID + client secret → access-токен |
POST /machine/enroll | enrollment-токен + публичный ключ → постоянные учётные данные |
GET /machine/entries?project=&env= | записи окружения в скоупе identity |
POST /machine/heartbeat | отметка «жив» в lastUsedAt identity |
Оба подробно разобраны на странице Сервисы и identity.
Ошибки
{ "error": { "code": "VALIDATION", "message": "..." } }
Ветвиться следует по code, а не по тексту. Каждый ответ несёт
X-Request-Id — это единственное, что нужно процитировать в обращении.
| HTTP | Код | Когда на деле |
|---|---|---|
| 400 | VALIDATION | тело или параметры не прошли проверку; текст говорит, что именно |
| 401 | UNAUTHENTICATED | нет токена, токен не тот, неверные client ID / client secret, неизвестный enrollment-токен |
| 401 | TOKEN_EXPIRED | access-токен протух; войдите заново |
| 402 | QUOTA_EXCEEDED | упёрлись в лимит тарифа — дело не в правах |
| 403 | FORBIDDEN | роли не хватает, IP вне allowedCidrs, скоуп identity не тот |
| 403 | IDENTITY_REVOKED | identity отозвана; токены по ней не принимаются |
| 403 | ENROLLMENT_EXPIRED | enrollment-токену больше 10 минут, им не воспользовались |
| 403 | ENROLLMENT_USED | enrollment-токен уже использован — тревога, см. identity |
| 403 | ORG_BLOCKED | организация заблокирована оператором |
| 404 | NOT_FOUND | нет такого ресурса (или нет прав его видеть) |
| 409 | CONFLICT | slug занят, identity уже отозвана, откатывать нечего |
| 413 | PAYLOAD_TOO_LARGE | тело запроса больше лимита (по умолчанию 1 МиБ) |
| 429 | RATE_LIMITED | слишком часто; ждите Retry-After |
| 500 | INTERNAL | ошибка на стороне сервера; в обращении укажите X-Request-Id |
Лимиты по частоте — на странице Безопасность.
Пагинация
{ "items": [...], "nextCursor": "..." }. Курсор непрозрачный: передайте
его обратно в ?cursor=, пока он приходит.
Ротация
Политика вешается на запись; прогоны идут по расписанию фоновым воркером
или запускаются вне очереди. Фазы, стратегии и метки pending/current
разобраны на странице Ротация секретов.
| Метод | Путь | Роль |
|---|---|---|
| PUT | /entries/:id/rotation-policy | admin проекта |
| GET | /entries/:id/rotation-policy | viewer проекта |
| DELETE | /entries/:id/rotation-policy | admin проекта |
| POST | /rotation-policies/:id/run-now | admin проекта |
| GET | /rotation-runs?policyId=<id> | viewer проекта |
| GET | /orgs/:id/rotations | участник организации |
Тело PUT:
{
"rotator": "postgres",
"strategy": "dual-credential",
"intervalSeconds": 604800,
"config": {
"adminDsnEntryRef": "my-org/billing-api/production/DB_ADMIN_DSN",
"usernames": ["app_a", "app_b"]
},
"enabled": true
}
rotator— сейчас толькоpostgres;strategy—dual-credentialилиsingle-user;intervalSeconds— целое, не меньше 60;config— разбирает ротатор; ссылки на секреты в нём должны лежать в той же организации, иначеVALIDATION, а на проект каждой из них у вас должна быть роль не нижеmember, иначеFORBIDDEN.PUTзаменяетconfigцеликом: при правке пересылайтеactiveUsernameизGET, иначе ротатор начнёт с первого пользователя в списке;enabled— необязательный, по умолчаниюtrue.
PUT создаёт политику или заменяет существующую и возвращает её:
{ id, entryId, rotator, strategy, intervalSeconds, config, enabled, nextRotationAt, createdAt }. GET возвращает политику записи, DELETE —
204; если политики нет, оба отвечают NOT_FOUND.
POST /rotation-policies/:id/run-now запускает прогон немедленно и
возвращает его. Если прогон этой политики уже идёт, ответ —
409 CONFLICT: ручной запуск и фоновый воркер делят одну аренду политики.
Приостановленная (enabled: false) политика run-now выполняется — это
явная воля, а не расписание; каждый такой запуск пишется в журнал событием
rotation.run.requested. GET /rotation-runs?policyId=<id> — { items } с
последними прогонами политики (до 50, новые первыми). Прогон:
{ id, policyId, phase, status, error?, resultVersion?, startedAt, completedAt? }, где
phase — одна из create, set, test, finish, а status — running,
testing, succeeded или failed; текст error есть только у failed,
а resultVersion — номер версии записи, которую создал прогон (есть, когда
прогон дошёл до записи значения).
GET /orgs/:id/rotations — сводка по организации: до 5 последних прогонов
на политику, всего до 50, по проектам, где у вас есть роль (владелец и
администратор организации видят все проекты). В каждом элементе
дополнительно entryKey — имя ключа записи.
Частая ошибка
GET /projects требует ?orgId= — без него ответ будет VALIDATION.