REST API

FastAPI routes, response shapes, and server-sent events.

The REST API is the primary programmatic interface to Comicarr. It uses standard HTTP methods and JSON bodies. Most routes require a JWT session cookie; a small set of library browse GETs accept X-Api-Key.

Base URL

http://localhost:8090/api/

Authentication

See Authentication for session cookies, API keys, and CSRF.

# Session (full API)
curl -b cookies.txt http://localhost:8090/api/series

# API key (library browse only)
curl -H "X-Api-Key: YOUR_KEY" http://localhost:8090/api/watchlist

Response format

Responses are not wrapped in a single global envelope. Shapes vary by endpoint:

  • List endpoints often return domain keys plus pagination metadata, e.g. {"comics": [...], "pagination": {...}}
  • Errors typically use FastAPI-style {"detail": "..."} with the appropriate HTTP status code
  • Some handlers return plain lists or status objects

Always check the HTTP status code and the endpoint’s documented fields.

Pagination

Where pagination is supported, clients commonly send limit / offset, or page-style query params depending on the route. Defaults and response field names vary, so inspect the JSON for pagination, total, or similar.

Event stream (SSE)

Real-time updates use server-sent events:

GET /api/events/stream

This endpoint requires a session cookie (not API key). Example:

curl -N -b cookies.txt \
  -H "Accept: text/event-stream" \
  http://localhost:8090/api/events/stream

Full event names and payload fields: Server-Sent Events.

Resources

Series & library (session)

GET    /api/series
GET    /api/series/{comic_id}
POST   /api/series
DELETE /api/series/{comic_id}
PATCH  /api/series/{comic_id}/search-settings
PATCH  /api/series/{comic_id}/content-kind
PUT    /api/series/{comic_id}/pause
PUT    /api/series/{comic_id}/resume
POST   /api/series/{comic_id}/refresh
GET    /api/series/{comic_id}/search-missing/preview
POST   /api/series/{comic_id}/search-missing
POST   /api/series/bulk-delete
POST   /api/series/bulk-pause
POST   /api/series/bulk-resume
PUT    /api/series/issues/{issue_id}/queue
PUT    /api/series/issues/{issue_id}/unqueue
GET    /api/series/issues/{issue_id}/search-preview
POST   /api/series/issues/{issue_id}/search
GET    /api/wanted

PATCH /api/series/{comic_id}/search-settings is a partial update taking booleans allow_packs and ignore_type, plus (since v0.33.0, for manga) bare_number_mode (auto | volumes | chapters) and monitor_mode (blended | volumes | chapters). PATCH /api/series/{comic_id}/content-kind takes {"content_type": "comic" | "manga"} and rejects anything else with 400.

Library browse (API key)

GET /api/watchlist
GET /api/comics
GET /api/comic/{comic_id}
GET /api/comic/{comic_id}/issues
GET /api/comic/{comic_id}/issue/{issue_id}

Import

GET    /api/import
POST   /api/import/match
PATCH  /api/import/{imp_id}
POST   /api/import/ignore
DELETE /api/import
POST   /api/import/refresh
POST   /api/import/comic/scan
GET    /api/import/comic/progress
POST   /api/import/comic/confirm
POST   /api/import/manga/scan
GET    /api/import/manga/progress
POST   /api/import/manga/confirm
POST /api/search/comics
POST /api/search/manga
POST /api/search/add
POST /api/search/add-manga
POST /api/search/force
POST /api/search/rss/force
GET  /api/search/providers
GET  /api/search/health
GET  /api/search/runs/{run_id}
POST /api/search/runs/{run_id}/retry
POST /api/search/interactive
GET  /api/search/interactive/{session_id}
POST /api/search/interactive/{session_id}/candidates/{candidate_id}/grab

POST /api/search/interactive takes {"entity_type": "issue" | "annual" | "story_arc_issue" | "series", "entity_id": "..."} and returns 202 with a session_id. entity_type: "series" (v0.34.0) searches the series' eligible missing issues as one session. Candidates include packs and report which missing issues each release would satisfy. Poll the session for state, progress, provider_failures, and candidates; each candidate carries a verdict with accepted, overrideable, reason_code, and human-readable reasons.

Grabs take {"override": true} to accept an overrideable rejection. Sessions are bound to the browser session that created them and expire. An expired session returns 410, one you do not own returns 404, and a candidate that went stale before you confirmed returns 409. Grab handoff runs off the request loop (v0.34.0); a grab confirmed while another is still processing is answered immediately with "Another release grab is already being processed".

Downloads

GET    /api/downloads/history
DELETE /api/downloads/history
POST   /api/downloads/process
POST   /api/downloads/process/issue
GET    /api/downloads/queue
POST   /api/downloads/{item_id}/requeue
POST   /api/downloads/ddl
DELETE /api/downloads/{item_id}
GET    /api/downloads/file/{issue_id}

Needs attention

Since v0.31.0 one attention API sits behind every needs-attention surface. The Activity preview, the Dashboard count, the triage view, and the resolution actions all share it.

GET  /api/attention
POST /api/attention/resolve

GET /api/attention returns the unresolved actionable obligations, grouped for triage; optional scope_type / scope_id query parameters narrow it to one scope. POST /api/attention/resolve applies one action to one or many rows:

{
  "action": "retry" | "search_again" | "stop_wanting" | "import",
  "release_keys": ["..."],
  "import_source": { "nzb_name": "...", "nzb_folder": "..." }
}

import_source is optional and only valid for a single-key import. A request in which no row could be resolved returns 409 with per-row results; partial success returns 200 with partial: true.

Deprecated needs-attention routes

GET /api/downloads/needs-attention was removed in v0.31.0 with no deprecation window. Poll GET /api/attention instead. The per-key resolution routes below still exist but are deprecated and slated for removal; move to POST /api/attention/resolve. {release_key} is a path parameter and may itself contain slashes.

POST /api/downloads/needs-attention/batch
POST /api/downloads/needs-attention/{release_key}/retry
POST /api/downloads/needs-attention/{release_key}/search-again
POST /api/downloads/needs-attention/{release_key}/stop-wanting
POST /api/downloads/needs-attention/{release_key}/import

Metadata

POST /api/metadata/search
POST /api/metadata/search/manga
GET  /api/metadata/comic/{comic_id}
GET  /api/metadata/issue/{issue_id}
GET  /api/metadata/art/{comic_id}
GET  /api/metadata/image-proxy
GET  /api/metadata/series-image/{series_id}
POST /api/metadata/metatag
POST /api/metadata/metatag/bulk
POST /api/metadata/metatag/group

Story arcs & reading lists

GET    /api/storyarcs
GET    /api/storyarcs/{arc_id}
DELETE /api/storyarcs/{arc_id}
POST   /api/storyarcs/generate
POST   /api/storyarcs/generate/save
PUT    /api/storyarcs/{arc_id}/issues/{issue_arc_id}/status
DELETE /api/storyarcs/{arc_id}/issues/{issue_arc_id}
POST   /api/storyarcs/{arc_id}/want-all
POST   /api/storyarcs/{arc_id}/refresh
GET    /api/readlist
POST   /api/readlist
DELETE /api/readlist/{issue_id}
DELETE /api/readlist
GET    /api/upcoming

Weekly & dashboard

The dashboard is four separate reads. The page fetches only the panels it renders.

GET  /api/weekly
POST /api/weekly/refresh
GET  /api/dashboard/library
GET  /api/dashboard/activity
GET  /api/dashboard/upcoming
GET  /api/dashboard/scan-targets

Activity

GET  /api/activity/timeline
GET  /api/activity/status
GET  /api/activity/in-flight
POST /api/activity/in-flight/cancel
GET  /api/activity/band        (deprecated)

GET /api/activity/in-flight (v0.32.0) lists exactly the rows the status bar counts as in-flight: running search runs plus open download/post-processing journal items. POST /api/activity/in-flight/cancel stops one of them, moving it to cancelled. GET /api/activity/band is the deprecated pre-attention preview; use GET /api/attention.

AI

GET    /api/ai/status
POST   /api/ai/test
GET    /api/ai/activity
POST   /api/ai/chat/stream
POST   /api/ai/chat/turns/stream
GET    /api/ai/chat/threads
GET    /api/ai/chat/threads/{thread_id}
PATCH  /api/ai/chat/threads/{thread_id}
DELETE /api/ai/chat/threads/{thread_id}
GET    /api/ai/chat/threads/{thread_id}/attachments/{attachment_id}
GET    /api/ai/suggestions

System & config

POST /api/auth/login
POST /api/auth/logout
GET  /api/auth/check-session
GET  /api/auth/check-setup
POST /api/auth/setup
GET  /api/events/stream
GET  /api/config
PUT  /api/config
POST /api/config/api-key/regenerate
GET  /api/config/providers
PUT  /api/config/providers
GET  /api/system/version
POST /api/system/version/check
GET  /api/system/release-notes
GET  /api/system/whats-new/archive
POST /api/system/whats-new/dismiss
GET  /api/system/logs
POST /api/system/logs/rotate
GET  /api/system/jobs
GET  /api/system/diagnostics
POST /api/system/support-bundle
POST /api/system/migration/preview
POST /api/system/migration/start
GET  /api/system/migration/progress
POST /api/system/shutdown
POST /api/system/restart

GET /api/config/providers returns Newznab and Torznab identities without credentials. Each provider reports api_key_set, never the key itself. PUT /api/config/providers takes {"type": "newznab" | "torznab", "enabled": bool, "providers": [...]}; omitting api_key on an existing provider keeps the stored one, unless the host's origin changed, in which case a new key is required.

GET /api/system/logs returns the log tail and the resolved level triple: the level running now, the level saved in config.ini, and the level the next restart would resolve to, plus whether a startup argument or environment variable is pinning it. Report all three; they are allowed to differ. See Logging.

POST /api/system/logs/rotate (v0.35.0) starts a new comicarr.log, keeping the previous file as a rotated archive under your MAX_LOGFILES retention. It returns rotated: false when logging runs without a file sink, in which case only the Web UI buffer was cleared. It backs the New log button in Settings → Logs and needs a session cookie.

Acquisition health & repair

GET  /api/search/health
POST /api/system/acquisition/reconciliation/ready
POST /api/system/acquisition/maintenance/abort
POST /api/system/acquisition/repair/preview
GET  /api/system/acquisition/repair/{run_id}
POST /api/system/acquisition/repair/{run_id}/confirm
POST /api/system/acquisition/repair/{run_id}/apply
POST /api/system/acquisition/repair/{run_id}/rollback
POST /api/system/acquisition/repair/{run_id}/canary
GET  /api/system/acquisition/canary/{permit_id}
POST /api/system/acquisition/canary/{permit_id}/release

Repair is deliberately multi-step: preview, confirm, apply, with rollback and a canary permit available. These back Settings → Acquisition, and casual scripting against them is a bad idea.

OPDS

OPDS is a separate catalog under /opds (not under /api). See the Reading (OPDS) guide.

On this page