Skip to content

HTTP API

All endpoints are JSON under /api/v1. Errors return {"error": {"code": "...", "message": "..."}} with a 4xx/5xx status. The server binds 127.0.0.1 by default; see Hosting.

EndpointDescription
GET /healthLiveness probe, returns {"ok": true}
EndpointDescription
GET /feedsAll subscriptions with unread counts and fetch status
POST /feedsSubscribe. Body {"url": "…"}. Returns 201 with the feed, or 200 with a feeds[] choice list when the URL hosts several feeds
POST /feeds/discoverPreview discoverable feeds at a URL without subscribing
DELETE /feeds/:idUnsubscribe
POST /feeds/:id/refreshPoll now. Returns {"newArticles": n}
POST /feeds/:id/mark-all-readMark every article in the feed read
EndpointDescription
GET /articlesCursor-paginated list. Query: feed_id, list_id, category, before, before_id, limit. Returns {articles, nextCursor}
GET /articles/:idFull record, including listIds and snoozedUntil
POST /articles/:id/readBody {"read": true | false}
POST /articles/:id/snoozeBody {"until": ISO8601 | null}null unsnoozes
EndpointDescription
GET /categoriesSubject counts. Query: feed_id to scope to one feed
EndpointDescription
GET /listsAll saved lists
POST /listsCreate. Body {"title", "visibility": "public" | "private"}
DELETE /lists/:idDelete the list (articles are untouched)
POST /lists/:id/itemsBody {"articleId"} — save an article
DELETE /lists/:id/items/:articleIdRemove an article
GET /lists/:token.xmlRSS for a public list — the sharing URL
EndpointDescription
GET /ingestorsAll ingestors with status and pending digest counts
POST /ingestorsCreate. Body: kind (mastodon | bluesky | reddit), config, optional fetchIntervalMin, digestMode (realtime | hourly | daily), filterThreshold, llmEnabled
PATCH /ingestors/:idUpdate interval, digest mode, threshold, LLM flag
DELETE /ingestors/:idRemove the ingestor
POST /ingestors/testRun one fetch cycle; returns kept and dropped statuses with scores

Credential fields in ingestor configs are accepted but redacted from every response.