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#
| Area | Endpoints |
|---|---|
| Auth | POST / (needs accept_terms: true) · POST / · POST / · GET / (user, scopes, csrf_token) · POST / · POST / · POST / · POST / · POST / |
| Social | GET / · GET / · GET / · GET / · GET / · POST / (no body, returns a link code) · GET / (link status) · DELETE / |
| Posts | POST / · GET / · GET / · PATCH / · DELETE / · POST / · / · / · / · / · GET / |
| Media | POST / (multipart; images ≤ 10 MB, video ≤ 100 MB; MIME sniffed) · GET / · GET / · DELETE / |
| Account | GET / · POST / · POST / · POST / · GET / · GET / (export and deletion are session only; see ARCHITECTURE) |
| Insights | GET / · GET / · GET / |
| Developer | GET/ · DELETE / · GET/ · DELETE / · GET / |
| Ops | GET / · GET / · GET / · GET / (public: {"version":"0.4.0","commit":"abc1234","built_at":"2026-10-10T12:00:00Z"}, cached 60 s) |
| Webhook | POST / (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:
- The worker locks the target and skips it if it is already published.
- It writes the attempt row and passes
IdempotencyKey = target.idto the adapter. - If an attempt was left
startedby a crash, the target becomesneeds_reviewinstead of being re-posted blindly. That prefers a visible missed post over a duplicate.