15 KiB
Update Server API
Этот документ описывает текущий публичный HTTP API сервиса. Его можно передать клиентскому приложению или агенту, который встраивает автообновление.
Примеры ниже используют:
Base URL: https://updates.example.com
API key: upsk_replace_me
Project: desktop-app
В реальной интеграции замени Base URL, API key и project_slug на свои
значения.
Общая модель
Update Server хранит проекты и релизы:
project- приложение, продукт или канал обновлений;release- загруженный файл обновления внутри проекта;api key- клиентский ключ доступа к API.
Администратор работает через web UI:
/admin
/admin/projects
/admin/api-keys
Клиентские приложения работают через JSON API:
/api/v1
На текущий момент JSON API предназначен для чтения и скачивания обновлений. Создание проектов, загрузка релизов и создание API keys выполняются через admin web UI, а не через публичный JSON API.
Авторизация
Защищенные endpoint'ы требуют bearer token:
Authorization: Bearer <api_key>
Пример:
curl -i \
-H "Authorization: Bearer upsk_replace_me" \
https://updates.example.com/api/v1/projects
API key должен быть:
- активным;
- не истекшим по
expires_at, если срок задан; - с разрешением
can_download; - со scope, который разрешает доступ к нужному проекту.
Поддерживаемые scope modes:
all_projects
project_allow_list
project_deny_list
tag_allow_list
tag_deny_list
Полный API key показывается в admin UI только один раз при создании. Сервер хранит только hash ключа.
Формат JSON
Все JSON-ответы возвращаются с:
Content-Type: application/json; charset=utf-8
Поля времени возвращаются строкой в формате RFC3339/RFC3339Nano, например:
"created_at": "2026-06-11T10:15:30Z"
Относительные URL в ответах, например download_url, нужно склеивать с
Base URL клиента.
Health Check
GET /healthz
Публичная проверка готовности HTTP-сервера и SQLite.
curl -i https://updates.example.com/healthz
Успешный ответ:
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{
"database": "ok",
"service": "Update Server",
"status": "ok",
"timestamp": "2026-06-11T10:15:30Z"
}
Если база недоступна:
HTTP/1.1 503 Service Unavailable
{
"database": "unavailable",
"error": "database ping failed",
"service": "Update Server",
"status": "degraded",
"timestamp": "2026-06-11T10:15:30Z"
}
API Index
GET /api/v1
Публичный JSON-index текущей версии API. Авторизация не нужна.
curl -i https://updates.example.com/api/v1
Ответ:
{
"auth": {
"header": "Authorization: Bearer <api_key>",
"type": "bearer"
},
"routes": [
{
"description": "List active projects accessible to the API key.",
"method": "GET",
"path": "/api/v1/projects"
},
{
"description": "Get the latest active release metadata for an accessible project.",
"method": "GET",
"path": "/api/v1/projects/{projectSlug}/releases/latest"
},
{
"description": "Get release metadata for an accessible release.",
"method": "GET",
"path": "/api/v1/releases/{releaseID}"
},
{
"description": "Download the private artifact for an accessible release.",
"method": "GET",
"path": "/api/v1/releases/{releaseID}/download"
}
],
"service": "Update Server",
"status": "client-api-ready",
"version": "v1"
}
List Accessible Projects
GET /api/v1/projects
Возвращает активные проекты, доступные текущему API key.
Требует:
Authorization: Bearer <api_key>
Пример:
curl -i \
-H "Authorization: Bearer upsk_replace_me" \
https://updates.example.com/api/v1/projects
Успешный ответ:
{
"projects": [
{
"id": 1,
"name": "Desktop App",
"slug": "desktop-app",
"description": "Primary desktop updater stream.",
"latest_release_url": "/api/v1/projects/desktop-app/releases/latest"
}
]
}
Если доступных проектов нет:
{
"projects": []
}
Get Latest Release
GET /api/v1/projects/{projectSlug}/releases/latest
Возвращает latest active release для активного и доступного проекта.
Latest release выбирается по:
created_at DESC, id DESC
Пример:
curl -i \
-H "Authorization: Bearer upsk_replace_me" \
https://updates.example.com/api/v1/projects/desktop-app/releases/latest
Успешный ответ:
{
"project": {
"id": 1,
"name": "Desktop App",
"slug": "desktop-app",
"description": "Primary desktop updater stream.",
"latest_release_url": "/api/v1/projects/desktop-app/releases/latest"
},
"release": {
"id": 2,
"version": "1.1.0",
"build": "build-2",
"filename": "desktop-app-1.1.0.zip",
"checksum_sha256": "4bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7c6e64b2f7110b2",
"size_bytes": 12345678,
"content_type": "application/zip",
"release_notes": "Improved desktop rollout.",
"created_at": "2026-06-11T10:15:30Z",
"metadata_url": "/api/v1/releases/2",
"download_url": "/api/v1/releases/2/download"
}
}
Если проект не существует, архивирован или недоступен этому key:
HTTP/1.1 404 Not Found
{
"error": "resource not found"
}
Если проект доступен, но активных релизов нет:
HTTP/1.1 404 Not Found
{
"error": "release not found"
}
Get Release Metadata
GET /api/v1/releases/{releaseID}
Возвращает metadata релиза по ID. Релиз должен быть активным, его проект должен быть активным, и текущий API key должен иметь доступ к проекту релиза.
Пример:
curl -i \
-H "Authorization: Bearer upsk_replace_me" \
https://updates.example.com/api/v1/releases/2
Успешный ответ:
{
"project": {
"id": 1,
"name": "Desktop App",
"slug": "desktop-app",
"description": "Primary desktop updater stream.",
"latest_release_url": "/api/v1/projects/desktop-app/releases/latest"
},
"release": {
"id": 2,
"version": "1.1.0",
"build": "build-2",
"filename": "desktop-app-1.1.0.zip",
"checksum_sha256": "4bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7c6e64b2f7110b2",
"size_bytes": 12345678,
"content_type": "application/zip",
"release_notes": "Improved desktop rollout.",
"created_at": "2026-06-11T10:15:30Z",
"metadata_url": "/api/v1/releases/2",
"download_url": "/api/v1/releases/2/download"
}
}
Если releaseID не число:
HTTP/1.1 400 Bad Request
{
"error": "invalid release id"
}
Если релиз не существует, архивирован или недоступен:
HTTP/1.1 404 Not Found
{
"error": "resource not found"
}
Download Release Artifact
GET /api/v1/releases/{releaseID}/download
Скачивает приватный artifact релиза. Скачивание проходит через приложение, чтобы сервер мог проверить API key, permission и project scope.
Пример:
curl -L \
-H "Authorization: Bearer upsk_replace_me" \
-o desktop-app-1.1.0.zip \
https://updates.example.com/api/v1/releases/2/download
Успешный ответ:
HTTP/1.1 200 OK
Content-Disposition: attachment; filename=desktop-app-1.1.0.zip
Content-Type: application/zip
X-Content-Type-Options: nosniff
Body ответа - bytes загруженного файла.
Если artifact отсутствует на диске:
HTTP/1.1 404 Not Found
{
"error": "release not found"
}
Если релиз недоступен:
HTTP/1.1 404 Not Found
{
"error": "resource not found"
}
Project Object
{
"id": 1,
"name": "Desktop App",
"slug": "desktop-app",
"description": "Primary desktop updater stream.",
"latest_release_url": "/api/v1/projects/desktop-app/releases/latest"
}
Поля:
id- numeric project ID.name- display name.slug- stable URL identifier.description- optional description.latest_release_url- relative URL для latest release lookup.
Release Object
{
"id": 2,
"version": "1.1.0",
"build": "build-2",
"filename": "desktop-app-1.1.0.zip",
"checksum_sha256": "4bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7c6e64b2f7110b2",
"size_bytes": 12345678,
"content_type": "application/zip",
"release_notes": "Improved desktop rollout.",
"created_at": "2026-06-11T10:15:30Z",
"metadata_url": "/api/v1/releases/2",
"download_url": "/api/v1/releases/2/download"
}
Поля:
id- numeric release ID.version- версия, введенная администратором при загрузке.build- build label или build number, если задан.filename- download filename.checksum_sha256- SHA-256 загруженного artifact.size_bytes- размер artifact в bytes.content_type- MIME type artifact.release_notes- release notes.created_at- время загрузки релиза.metadata_url- relative URL metadata endpoint.download_url- relative URL download endpoint.
Ошибки
JSON API возвращает ошибки в формате:
{
"error": "message"
}
Основные статусы:
| Status | Когда |
|---|---|
400 |
Некорректный releaseID, например не число. |
401 |
Нет bearer token, token неверный, key выключен или истек. |
403 |
API key валиден, но нет can_download. |
404 |
Ресурс не найден, архивирован или недоступен текущему key. |
429 |
Сработал rate limit client API. |
500 |
Внутренняя ошибка сервера. |
503 |
Health check: база недоступна; или API key service недоступен. |
401 Unauthorized
Missing header:
WWW-Authenticate: Bearer realm="update-server"
{
"error": "missing bearer api key"
}
Invalid, disabled or expired key:
{
"error": "invalid api key"
}
403 Forbidden
{
"error": "api key permission denied"
}
429 Too Many Requests
Retry-After: 3
{
"error": "rate limit exceeded"
}
По умолчанию client API rate limit настраивается переменными:
APP_CLIENT_RATE_LIMIT_PER_MINUTE=120
APP_CLIENT_RATE_LIMIT_BURST=60
Headers
Для protected API responses сервер добавляет:
Cache-Control: no-store, private, max-age=0
Pragma: no-cache
Expires: 0
Vary: Authorization
X-Robots-Tag: noindex, nofollow
Также на все ответы добавляются security headers, включая:
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
Referrer-Policy: no-referrer
Если APP_BASE_URL использует https://, включается:
Strict-Transport-Security: max-age=31536000
Типовой Client Flow
-
Администратор создает проект в
/admin/projects. -
Администратор загружает release artifact в проекте.
-
Администратор создает API key в
/admin/api-keys. -
Для ключа включает
can_download. -
Для ключа выбирает scope, который разрешает доступ к проекту.
-
Клиент запрашивает latest release:
curl -sS \ -H "Authorization: Bearer upsk_replace_me" \ https://updates.example.com/api/v1/projects/desktop-app/releases/latest -
Клиент сравнивает
release.versionсо своей текущей версией. -
Если версия новая, клиент скачивает
release.download_url. -
Клиент проверяет:
checksum_sha256;size_bytes;- при необходимости свою подпись artifact, если она есть в продукте.
Python Example
В репозитории есть минимальный helper:
example/autoupdate.py
example/update_client.py
Приватный файл рядом со скриптом:
{
"base_url": "https://updates.example.com",
"api_key": "upsk_replace_me",
"project_slug": "desktop-app"
}
Вызов:
from autoupdate import ensure_updated_from_config
ver = "1.0.0"
ensure_updated_from_config(current_version=ver)
Если autoupdate.json отсутствует, helper создаст файл с placeholder values,
не пойдет в сеть и выведет короткое сообщение о настройке конфига.
Чего Сейчас Нет В API
На текущий момент client JSON API не предоставляет:
- создание/редактирование проектов;
- загрузку релизов;
- создание/редактирование API keys;
- список всех релизов проекта;
- release channels вроде
stable/beta; - query parameters вроде
platform,arch,current_version; - публичные downloads без API key.
Эти действия либо выполняются через admin web UI, либо пока являются будущим расширением API.