REST API

Everything the app and the MCP server do goes through this API. The full contract, including the database and scheduler, is in the architecture reference.

Everything the web app and the MCP server do goes through this API. This page is the overview; the full contract (request bodies, scopes, the database and the scheduler) is in ARCHITECTURE.

Errors#

All endpoints are under /api/v1. Errors look like this:

{"error":{"code":"SOCIAL_ACCOUNT_EXPIRED","message":"LinkedIn authorization has expired","request_id":"…"}}

Endpoints#

AreaEndpoints
AuthPOST /auth/register (needs accept_terms: true) · POST /auth/login · POST /auth/logout · GET /me (user, scopes, csrf_token) · POST /auth/verify-email · POST /auth/verify-email/resend · POST /auth/password/forgot · POST /auth/password/reset · POST /auth/password/change
SocialGET /social/providers · GET /social/accounts · GET /social/accounts/{id} · GET /social/{provider}/connect · GET /social/{provider}/callback · POST /social/telegram/connect (no body, returns a link code) · GET /social/telegram/connect/{id} (link status) · DELETE /social/accounts/{id}
PostsPOST /posts · GET /posts?status=&from=&to=&cursor= · GET /posts/{id} · PATCH /posts/{id} · DELETE /posts/{id} · POST /posts/{id}/publish · /schedule · /unschedule · /cancel · /retry · GET /posts/{id}/status
MediaPOST /media (multipart; images ≤ 10 MB, video ≤ 100 MB; MIME sniffed) · GET /media · GET /media/{id} · DELETE /media/{id}
AccountGET /account/usage · POST /account/delete · POST /account/delete/cancel · POST /account/exports · GET /account/exports · GET /account/exports/{id} (export and deletion are session only; see ARCHITECTURE)
InsightsGET /dashboard/summary · GET /analytics · GET /audit-logs
DeveloperGET/POST /developer/api-keys · DELETE /developer/api-keys/{id} · GET/POST /developer/mcp-connections · DELETE /developer/mcp-connections/{id} · GET /developer/usage
OpsGET /health · GET /ready · GET /metrics · GET /version (public: {"version":"0.4.0","commit":"abc1234","built_at":"2026-10-10T12:00:00Z"}, cached 60 s)
WebhookPOST /webhooks/telegram (only when TELEGRAM_UPDATES_MODE=webhook; authenticated by the X-Telegram-Bot-Api-Secret-Token header, not by session or key)

Post lifecycle#

Posts move draft → scheduled → publishing → published | partially_published | failed, and draft|scheduled → cancelled. Invalid transitions return 409 INVALID_STATE_TRANSITION. Every attempt is recorded in publication_attempts with its number, times, status, error and response metadata.

Idempotency#

Each target is published at most once:

  1. The worker locks the target and skips it if it is already published.
  2. It writes the attempt row and passes IdempotencyKey = target.id to the adapter.
  3. If an attempt was left started by a crash, the target becomes needs_review instead of being re-posted blindly. That prefers a visible missed post over a duplicate.