Ein fester Vertrag für andere Programme
Nexview, nexbeat und nexdeck sprechen mit nexcrate über dieselbe Schnittstelle, die auch dir offensteht: /api/v1. Sie bleibt, wie sie ist, während sich die Seiten der Oberfläche weiterentwickeln. Diese Seite erklärt, wie man hineinkommt, und listet darunter jede Adresse.
Stand der Referenz: nexcrate 0.2.0, Vertrag v1, Stufe V5, 43 Adressen. Sie wird aus nexcrates Code erzeugt; die Beschreibungen der einzelnen Adressen stehen deshalb auf Englisch, so wie im Code.
Zwei Schnittstellen
Die Oberfläche von nexcrate benutzt selbst eine Schnittstelle unter /api, mit dem Anmelde-Cookie. Die folgt den Seiten der Oberfläche und ändert sich mit ihnen. Andere Programme nehmen /api/v1 und sonst nichts.
/api/v1öffnet sich nur mit einem Schlüssel, nie mit dem Cookie der Oberfläche.- Was sich ändert, braucht dort keinen Kopf
X-Requested-With. - Indexer, Download-Programme, Profile, das Konto und abgelegte Geheimnisse erreicht kein Schlüssel. Für sie gibt es unter
/api/v1keine Adresse.
Jede laufende nexcrate beschreibt sich selbst: /api/openapi.json ist das OpenAPI-Dokument, /api/docs die Seite dazu.
Schlüssel und Umfänge
Unter Einstellungen › System › API-Schlüssel auf Neuer Schlüssel. Gib jedem Programm einen eigenen, dann lässt sich einer widerrufen, ohne die anderen zu stören. Der Schlüssel wird genau einmal gezeigt; nexcrate behält nur seinen Fingerabdruck.
| Umfang | Was er darf |
|---|---|
| Lesen | Bibliothek, Fassungen, Zustände, Speicher, Gesundheit, Warteschlange, Probleme, Verlauf, Kalender, Wertungen und Ereignisse lesen. Jeder Schlüssel hat ihn. |
| Anfragen | Titel anfragen und nachfordern, überwachen oder einfrieren, suchen lassen, zurücknehmen und Dateien in den Papierkorb legen. |
| Bedienen | Hängende Downloads noch einmal versuchen, entfernen oder neu suchen lassen, einen Pfad bestätigen und Dateien von Hand zuordnen. |
Gesendet wird der Schlüssel im Kopf, nie in der Adresse:
Authorization: Bearer nxc_…
Koppeln
Ein Programm kann um einen Schlüssel bitten, statt dass jemand ihn abtippt. So verbinden sich Nexview, nexbeat und nexdeck. Die beiden Adressen dafür sind die einzigen unter /api/v1, die keinen Schlüssel brauchen.
- Bitten
POST /api/v1/pairingmit dem Namen des Programms und den gewünschten Umfängen. Die Antwort trägt einepairing_id, einsecretund einen kurzencode. Das Programm zeigt den Code an. - BestätigenIn nexcrate steht die Bitte oben auf jeder Seite und unter Einstellungen › System › API-Schlüssel bei Programme, die sich verbinden wollen. Der Besitzer vergleicht den Code und klickt Verbinden oder Ablehnen; er darf weniger Umfänge geben als erbeten.
- AbholenDas Programm fragt
GET /api/v1/pairing/{pairing_id}mit dem KopfX-Pairing-Secret, im Abstand vonpoll_seconds. Die erste Antwort mitconfirmedträgt den Schlüssel, genau einmal.
curl -s -X POST http://nexcrate:8390/api/v1/pairing \
-H 'Content-Type: application/json' \
-d '{"app": "Mein Skript", "scopes": ["read", "request"]}'
Die erste Anfrage
Welche Fassungen es gibt und ob sie bereit sind:
curl -s http://nexcrate:8390/api/v1/versions \ -H "Authorization: Bearer $NEXCRATE_KEY"
Einen Film in einer Fassung anfragen und gleich suchen lassen. Zweimal fragen ergibt dasselbe, nie ein Doppel; origin ist deine eigene Kennung und kommt am Titel zurück:
curl -s -X POST http://nexcrate:8390/api/v1/requests \
-H "Authorization: Bearer $NEXCRATE_KEY" \
-H 'Content-Type: application/json' \
-d '{"kind": "movie", "ref": "tmdb:28503", "versions": ["<id der Fassung>"],
"search_now": true, "origin": "mein-skript:1"}'
Regeln der Antworten
- Ein Titel ist
kindplusref.refnennt seine Quelle:tmdb:,imdb:, bei Serien auchtvdb:, bei Musikmbid:. Was nur eine Art betrifft, steht unter einem Schlüssel mit ihrem Namen. - Ein Feld fehlt nie. Ist ein Wert unbekannt, steht
nullda. - Fehler sind flach:
{"code": "…", "message": "…", "params": {…}}. Dercodeist fest, diemessageein englischer Ersatztext. Jede Adresse nennt in der Referenz ihre Fehlercodes. - Jede Antwort trägt
X-Request-Id. Ein Programm darf eine eigene mitschicken; nexcrate schreibt sie in jede Protokollzeile dieser Anfrage. - Je Schlüssel gibt es eine Obergrenze für Anfragen in der Sekunde. Wer sie überschreitet, bekommt
429mitRetry-After. - Stabil heißt: Der Vertrag ändert seine Hauptnummer nur mit einem Bruch, und die steht in der Adresse.
GET /api/v1/systemnennt Hauptnummer und Stufe; eine höhere Stufe bringt nur Neues dazu.
Ereignisse und Webhooks
Was in nexcrate passiert, hat eine Laufnummer. GET /api/v1/events?after=… liefert, was seit einer Nummer kam, und next_after für die nächste Frage. GET /api/v1/events/stream liefert dasselbe als Server-Sent Events. Die Bibliothek selbst lässt sich genauso lesen: GET /api/v1/titles?after=… gibt nur, was sich geändert hat.
Webhooks schickt nexcrate an Adressen, die der Besitzer unter Einstellungen › System › Webhooks einträgt; kein Schlüssel reicht dorthin. Jede Zustellung trägt X-Nexcrate-Event, X-Nexcrate-Delivery und eine Unterschrift:
X-Nexcrate-Signature: t=<Unix-Zeit>,v1=<HMAC-SHA256 über "<t>.<Rumpf>">
Geprüft wird mit dem Geheimnis des Ziels über den rohen Rumpf, so wie er ankam:
import hashlib, hmac def echt(geheimnis: str, kopf: str, rumpf: bytes) -> bool: teile = dict(stueck.split("=", 1) for stueck in kopf.split(",")) erwartet = hmac.new(geheimnis.encode(), teile["t"].encode() + b"." + rumpf, hashlib.sha256).hexdigest() return hmac.compare_digest(erwartet, teile["v1"])
Scheitert eine Zustellung, versucht nexcrate es nach 1, 5, 30 und 120 Minuten wieder. Ein neues Ziel beginnt beim neuesten Ereignis, nicht mit allem, was vorher war.
System und Fassungen
Wer antwortet, welche Fassungen es gibt, wie viel Platz dahinter frei ist und was gerade nicht stimmt.
GET/api/v1/healthWhat is wrong with this nexcrateLesen
Findings from what nexcrate already knows: asking sends no request anywhere and wakes no disk. Translate by code; params carry the names.
Antwort 200 HealthOut
| Feld | Typ | Bedeutung |
|---|---|---|
items * | array of FindingOut | The worst first; empty when nothing is wrong. |
Fehlercodes
- 401
api_key_missing,api_key_invalid - 403
scope_missing - 500
internal_error
GET/api/v1/statesThe states a version, a season or an episode can haveLesen
The list is part of the contract. A later stage may add a state; a program shows one it does not know as unknown instead of failing.
Antwort 200 StatesOut
| Feld | Typ | Bedeutung |
|---|---|---|
items * | array of StateOut | In the order of precedence: the first that applies wins. |
Fehlercodes
- 401
api_key_missing,api_key_invalid - 403
scope_missing - 500
internal_error
GET/api/v1/storageFree space behind every versionLesen
Free and total space of the disk each version's folder lies on. Never a path.
Antwort 200 StorageListOut
| Feld | Typ | Bedeutung |
|---|---|---|
items * | array of StorageOut |
Fehlercodes
- 401
api_key_missing,api_key_invalid - 403
scope_missing - 500
internal_error
GET/api/v1/systemWhat this nexcrate is and can doLesen
The version, the stage of the contract, what works per kind, and the fixed id of the installation. Ask this first: a program that needs more than this nexcrate carries can say so instead of failing.
Antwort 200 SystemOut
| Feld | Typ | Bedeutung |
|---|---|---|
app * | string | |
version * | string | The running nexcrate. |
contract * | Contract | |
installation_id * | string | Fixed for this installation, whatever address it answers at. Tells a moved nexcrate from another. |
scopes * | array of string | What the key of this request may do. |
capabilities * | Capabilities | |
web_url * | string | null | The address the owner gave for reaching nexcrate, sub path included; null without one. |
links * | object of string | The jumps into nexcrate's pages, to put behind web_url (or the address you reach nexcrate at): title, version, profile, download, problems, recycle_bin, calendar. They stay whatever the pages are called. |
update * | app__routers__v1__UpdateOut |
Fehlercodes
- 401
api_key_missing,api_key_invalid - 403
scope_missing - 500
internal_error
GET/api/v1/versionsList the versions and whether they are readyLesen
A version is a named slot per kind, such as HD and 4K for movies. A version that is not ready does nothing by itself: offer only ready ones, and tell the owner the reasons of the others.
Parameter
| Feld | Wo | Typ | Bedeutung |
|---|---|---|---|
kind | query | string | null |
Antwort 200 VersionsOut
| Feld | Typ | Bedeutung |
|---|---|---|
items * | array of VersionOut | Per kind none, one or several: assume no number. |
Fehlercodes
- 401
api_key_missing,api_key_invalid - 403
scope_missing - 422
kind_unsupported,invalid_input - 500
internal_error
Titel lesen
Die Bibliothek als Ganzes oder als Änderung seit einer Marke, ein Titel mit Staffeln und Folgen, sein Verlauf und warum etwas noch fehlt.
GET/api/v1/titlesThe library, whole or what changed since a numberLesen
With after=0 the whole library in pages; afterwards ask with the next_after of the last answer and get only what changed since, and what went away. A title's number moves whenever anything of what this list says about it changes, some seconds after the change. A series carries its seasons; episodes are not in the list: fetch the season when its number moved. marker_too_old: the number is older than 90 days of removals, start over at 0.
Parameter
| Feld | Wo | Typ | Bedeutung |
|---|---|---|---|
after | query | integer | The next_after of the last answer; 0 for everything. |
kind | query | string | null | |
limit | query | integer |
Antwort 200 TitlesOut
| Feld | Typ | Bedeutung |
|---|---|---|
items * | array of ChangedTitleOut | Titles that are new or changed, the oldest change first. |
removed * | array of RemovedOut | Titles that went away. Never part of a fetch from 0. |
next_after * | integer | Ask with this next. |
more * | boolean | True: ask again at once, there is more. |
latest * | integer | The highest number given so far. |
Fehlercodes
- 401
api_key_missing,api_key_invalid - 403
scope_missing - 410
marker_too_old - 422
kind_unsupported,invalid_input - 500
internal_error
POST/api/v1/titles/lookupLook up many titles at onceLesen
Up to 100 titles in one call, for a page of tiles that each need a badge. Answers in the order asked, straight from the library and without the delay of the change numbers. An entry nexcrate cannot answer carries error; the batch never fails for one entry.
Anfrage LookupIn
| Feld | Typ | Bedeutung |
|---|---|---|
items * | array of LookupItemIn |
Antwort 200 LookupOut
| Feld | Typ | Bedeutung |
|---|---|---|
items * | array of LookupItemOut | In the order asked. |
Fehlercodes
- 401
api_key_missing,api_key_invalid - 403
scope_missing - 422
invalid_input - 500
internal_error
GET/api/v1/titles/series/{ref}/seasons/{season}The episodes of one seasonLesen
Every episode TMDB lists for the season, in TMDB's numbers, with every version's state, size and quality. Season 0 holds the specials.
Parameter
| Feld | Wo | Typ | Bedeutung |
|---|---|---|---|
ref * | path | string | |
season * | path | integer |
Antwort 200 SeasonDetailOut
| Feld | Typ | Bedeutung |
|---|---|---|
season * | integer | |
name * | string | null | |
episodes * | array of app__routers__v1__EpisodeOut |
Fehlercodes
- 401
api_key_missing,api_key_invalid - 403
scope_missing - 404
title_not_found,season_not_found - 409
ref_ambiguous - 422
ref_invalid,ref_source_unknown,invalid_input - 500
internal_error
POST/api/v1/titles/whyWhy many titles are not there yetLesen
The same for up to 50 titles, in the order asked; an entry nexcrate cannot answer carries error and breaks nothing else.
Anfrage WhyManyIn
| Feld | Typ | Bedeutung |
|---|---|---|
items * | array of WhyItemIn |
Antwort 200 WhyManyOut
| Feld | Typ | Bedeutung |
|---|---|---|
items * | array of WhyManyItemOut | In the order asked. |
Fehlercodes
- 401
api_key_missing,api_key_invalid - 403
scope_missing - 422
invalid_input - 500
internal_error
GET/api/v1/titles/{kind}/{ref}One title, a series with its seasonsLesen
The title as the list shows it; a series also with every season and, per version, its state, numbers and size on disk. ref takes every source nexcrate knows for the kind: tmdb and imdb, for a series also tvdb.
Parameter
| Feld | Wo | Typ | Bedeutung |
|---|---|---|---|
kind * | path | string | |
ref * | path | string |
Fehlercodes
- 401
api_key_missing,api_key_invalid - 403
scope_missing - 404
title_not_found - 409
ref_ambiguous - 422
kind_unsupported,ref_invalid,ref_source_unknown,invalid_input - 500
internal_error
GET/api/v1/titles/{kind}/{ref}/historyThe history of a titleLesen
Loaded, filed (with the replaced file's quality and size), failed, deleted, restored, requested, taken back, and what programs did, newest first in pages.
Parameter
| Feld | Wo | Typ | Bedeutung |
|---|---|---|---|
kind * | path | string | |
ref * | path | string | |
before | query | integer | null | The next_before of the last page. |
limit | query | integer |
Antwort 200 HistoryOut
| Feld | Typ | Bedeutung |
|---|---|---|
items * | array of HistoryItemOut | Newest first. Entries from before V3 carry only kind and time. |
next_before * | integer | null | Ask with before set to this for older entries; null at the end. |
Fehlercodes
- 401
api_key_missing,api_key_invalid - 403
scope_missing - 404
title_not_found - 409
ref_ambiguous - 422
kind_unsupported,ref_invalid,ref_source_unknown,invalid_input - 500
internal_error
GET/api/v1/titles/{kind}/{ref}/whyWhy a title is not there yetLesen
Per version one reason as a code with params, the weightiest first: loading, stuck, not released yet, the last search found only releases the profile refuses, the next search, waiting out a delay. Build the sentence from the code. Asks no indexer.
Parameter
| Feld | Wo | Typ | Bedeutung |
|---|---|---|---|
kind * | path | string | |
ref * | path | string |
Fehlercodes
- 401
api_key_missing,api_key_invalid - 403
scope_missing - 404
title_not_found - 409
ref_ambiguous - 422
kind_unsupported,ref_invalid,ref_source_unknown,invalid_input - 500
internal_error
Anfragen und zurücknehmen
Einen Titel anfragen oder mehr davon, vorher fragen, was es gäbe, einfrieren, suchen lassen, zurücknehmen und entfernen.
POST/api/v1/previewAsk before a requestAnfragen
Whether the title is there, when it comes out, whether each version would search and load by itself, and with search a search of the indexers without loading (follow it with GET /api/v1/preview/{preview_id}). A title nexcrate does not have comes from TMDB; a series nexcrate does not have cannot be searched yet.
Anfrage app__routers__v1_round__PreviewIn
| Feld | Typ | Bedeutung |
|---|---|---|
kind * | string | |
ref * | string | A title nexcrate does not have only by tmdb:. |
versions | array of string | null | Fixed version ids; left out, every version of the kind. |
search | boolean | Also search the indexers, without loading, within their budget. |
series | PreviewSeriesIn | null |
Fehlercodes
- 401
api_key_missing,api_key_invalid - 403
scope_missing - 409
ref_ambiguous,search_busy,tmdb_not_configured,tmdb_token_unreadable - 422
kind_unsupported,ref_invalid,ref_source_unknown,ref_not_addable,version_unknown,scope_not_for_kind,invalid_input - 500
internal_error - 502
tmdb_token_rejected,tmdb_rate_limited,tmdb_unavailable,tmdb_unreachable,tmdb_http_error - 504
tmdb_timeout
GET/api/v1/preview/{preview_id}What a preview's search foundAnfragen
Per version the release nexcrate would take, or why nothing fits. Kept 30 minutes.
Parameter
| Feld | Wo | Typ | Bedeutung |
|---|---|---|---|
preview_id * | path | string |
Antwort 200 PreviewResultOut
| Feld | Typ | Bedeutung |
|---|---|---|
preview_id * | string | |
state * | string | running or done. |
releases * | integer | Releases of the title found. |
indexers * | array of PreviewIndexerOut | |
versions * | array of PreviewResultVersionOut |
Fehlercodes
- 401
api_key_missing,api_key_invalid - 403
scope_missing - 404
preview_not_found - 422
invalid_input - 500
internal_error
POST/api/v1/requestsRequest a title, or request more of itAnfragen
One call for both: a title nexcrate lacks is added from TMDB, versions it lacks are added, and the seasons and episodes under series are switched on. Asking twice gives the same, never a double. Requesting more never switches anything off, and what the owner switched by hand stays. A version a Radarr or Sonarr connection feeds answers 409. search_now puts the title into the order of the automatic, even with its switch off, within the indexers' budget. 200 when the title was there, 201 when it came with this call.
Anfrage RequestIn
| Feld | Typ | Bedeutung |
|---|---|---|
kind * | string | |
ref * | string | A new title only by tmdb:, a new album or artist by mbid: (its release group or artist). |
versions | array of string | null | Fixed version ids. Needed for a movie or series; an album takes the one music version without it, an artist has none. |
series | SeriesScopeIn | null | Only for a series; a movie answers 422. |
artist | ArtistScopeIn | null | Only for an artist: which albums to watch. |
search_now | boolean | Search as soon as the order of the automatic allows. |
origin | string | null | The program's own reference, at most 100 printable characters; listed back with the title and its versions. |
Antwort 200 RequestOut
| Feld | Typ | Bedeutung |
|---|---|---|
created * | boolean | True when the title came in with this request. |
versions * | array of RequestedVersionOut | |
albums_watched | integer | null | An artist: how many of its albums this request watched; null otherwise. |
search * | string | queued, not_asked, nothing_wanted, or not_possible (an anime series while capabilities.anime is false; the note anime_not_supported says it). |
notes * | array of app__routers__v1_write__NoteOut | |
title * | TitleOut |
Fehlercodes
- 401
api_key_missing,api_key_invalid - 403
scope_missing - 404
title_not_found,version_not_found - 409
ref_ambiguous,version_fed_by_source,tmdb_not_configured,tmdb_token_unreadable - 422
kind_unsupported,ref_invalid,ref_source_unknown,version_unknown,version_kind_mismatch,scope_not_for_kind,season_not_found,episode_not_found,track_not_found,ref_not_addable,invalid_input - 500
internal_error - 502
tmdb_token_rejected,tmdb_rate_limited,tmdb_unavailable,tmdb_unreachable,tmdb_http_error - 504
tmdb_timeout
DELETE/api/v1/titles/{kind}/{ref}Remove a title from the libraryAnfragen
As the button in nexcrate: nexcrate's own versions go, and the title when none is left. Its running downloads are stopped at their client first. With delete_files the files go into the recycle bin before; ⚠️ a title that is gone cannot take them back, so add it again first. Versions a Radarr or Sonarr connection feeds stay, and the answer is 409 title_has_source_versions.
Parameter
| Feld | Wo | Typ | Bedeutung |
|---|---|---|---|
kind * | path | string | |
ref * | path | string | |
delete_files | query | boolean | Move the files into the recycle bin first. |
Fehlercodes
- 401
api_key_missing,api_key_invalid - 403
scope_missing - 404
title_not_found - 409
ref_ambiguous,download_finished,title_has_source_versions - 422
kind_unsupported,ref_invalid,ref_source_unknown,invalid_input - 500
internal_error
POST/api/v1/titles/{kind}/{ref}/delete-filesMove files into the recycle binAnfragen
The files of the scope go into the recycle bin with their subtitles; they come back with POST /api/v1/recycle-bin/{entry_id}/restore until the bin's time is up. A file of a series that holds several episodes goes whole when one of them is named.
Parameter
| Feld | Wo | Typ | Bedeutung |
|---|---|---|---|
kind * | path | string | |
ref * | path | string |
Anfrage app__routers__v1_write__DeleteFilesIn
| Feld | Typ | Bedeutung |
|---|---|---|
versions | array of string | null | Fixed version ids (v_…); without it every version of nexcrate's own. |
series | SeriesScopeIn | null | |
album | AlbumScopeIn | null | Only for an album: single tracks. |
Antwort 200 DeleteFilesOut
| Feld | Typ | Bedeutung |
|---|---|---|
versions * | array of DeletedVersionOut |
Fehlercodes
- 401
api_key_missing,api_key_invalid - 403
scope_missing - 404
title_not_found,version_not_found - 409
ref_ambiguous,version_fed_by_source,download_importing - 422
kind_unsupported,ref_invalid,ref_source_unknown,version_unknown,version_kind_mismatch,scope_not_for_kind,season_not_found,episode_not_found,track_not_found,invalid_input - 500
internal_error
PUT/api/v1/titles/{kind}/{ref}/monitoringFreeze or thawAnfragen
Only the switches: no download stops, no file moves. Freezing a whole series also keeps seasons TMDB names later out; thawing it takes them in again.
Parameter
| Feld | Wo | Typ | Bedeutung |
|---|---|---|---|
kind * | path | string | |
ref * | path | string |
Anfrage MonitoringIn
| Feld | Typ | Bedeutung |
|---|---|---|
monitored * | boolean | False freezes: nothing is searched or upgraded, files stay. True thaws. An artist frozen is Lidarr's unmonitored artist: none of its albums is searched on its own, their switches stay. |
versions | array of string | null | Fixed version ids (v_…); without it every version of nexcrate's own. |
series | SeriesScopeIn | null | |
artist | ArtistMonitoringIn | null |
Antwort 200 MonitoringOut
| Feld | Typ | Bedeutung |
|---|---|---|
versions * | array of MonitoredVersionOut | |
title * | TitleOut |
Fehlercodes
- 401
api_key_missing,api_key_invalid - 403
scope_missing - 404
title_not_found,version_not_found - 409
ref_ambiguous,version_fed_by_source - 422
kind_unsupported,ref_invalid,ref_source_unknown,version_unknown,version_kind_mismatch,scope_not_for_kind,season_not_found,episode_not_found,track_not_found,invalid_input - 500
internal_error
POST/api/v1/titles/{kind}/{ref}/searchAsk for a searchAnfragen
The title goes into the order of the automatic, right after the replacements, even with its switch off, and within the indexers' budget: a hundred asks at once are searched one after the other.
Parameter
| Feld | Wo | Typ | Bedeutung |
|---|---|---|---|
kind * | path | string | |
ref * | path | string |
Antwort 202 app__routers__v1_write__SearchOut
| Feld | Typ | Bedeutung |
|---|---|---|
search * | string | queued, running (a search of it runs already), nothing_wanted, or not_possible (an anime series while capabilities.anime is false). |
Fehlercodes
- 401
api_key_missing,api_key_invalid - 403
scope_missing - 404
title_not_found - 409
ref_ambiguous - 422
kind_unsupported,ref_invalid,ref_source_unknown,invalid_input - 500
internal_error
POST/api/v1/titles/{kind}/{ref}/withdrawTake a request backAnfragen
Watching off for the scope, running downloads that lie wholly in it stopped at their client (never blocklisted), and with delete_files the files moved into the recycle bin. A download being filed away cannot be stopped: then 409 download_finished and nothing changed. A title or version a program brought and that is empty afterwards goes.
Parameter
| Feld | Wo | Typ | Bedeutung |
|---|---|---|---|
kind * | path | string | |
ref * | path | string |
Anfrage WithdrawIn
| Feld | Typ | Bedeutung |
|---|---|---|
versions | array of string | null | Fixed version ids (v_…); without it every version of nexcrate's own. |
series | SeriesScopeIn | null | |
delete_files | boolean | Also move the files of the scope into the recycle bin. |
Antwort 200 WithdrawOut
| Feld | Typ | Bedeutung |
|---|---|---|
title_removed * | boolean | A title a program added goes when nothing of it is watched and no file is left. An album stays in its artist's catalogue; an artist a program added goes when none of its albums is left. |
versions * | array of WithdrawnVersionOut | |
albums | array of WithdrawnAlbumOut | null | An artist: what happened per album. |
Fehlercodes
- 401
api_key_missing,api_key_invalid - 403
scope_missing - 404
title_not_found,version_not_found - 409
ref_ambiguous,version_fed_by_source,download_finished,download_importing - 422
kind_unsupported,ref_invalid,ref_source_unknown,version_unknown,version_kind_mismatch,scope_not_for_kind,season_not_found,episode_not_found,track_not_found,invalid_input - 500
internal_error
Downloads
Was lädt, was hängt, was gescheitert ist, und was ein Programm daran tun darf.
POST/api/v1/downloads/{download_id}/assignAssign the files of a download by handBedienen
A series: each file with its episodes in TMDB's numbers, filed in the background; a file with no episodes is not filed, a file left out keeps its decision. A movie with several videos: exactly one file, the one to file. Replacing a file that is not worse needs confirm: ["not_better"].
Parameter
| Feld | Wo | Typ | Bedeutung |
|---|---|---|---|
download_id * | path | integer |
Anfrage app__routers__v1_back__AssignIn
| Feld | Typ | Bedeutung |
|---|---|---|
files * | array of AssignFileIn | |
album | AssignAlbumIn | null | Only for an album download. |
confirm | array of "not_better" | Replace a file that is not worse all the same, as the owner may. |
Antwort 200 ActOut
| Feld | Typ | Bedeutung |
|---|---|---|
download * | QueueItemOut | The download as it stands after the action. |
Fehlercodes
- 401
api_key_missing,api_key_invalid - 403
scope_missing - 404
download_not_found - 409
action_not_allowed,download_not_assignable,download_busy,assignment_not_better,assignment_covers_more,download_files_changed,download_not_choosable - 422
episode_not_found,episode_twice,scope_not_for_kind,invalid_input,track_not_found,release_not_of_album,track_not_in_release,track_twice,release_fixed - 500
internal_error
POST/api/v1/downloads/{download_id}/clearTake a failed download off the problemsBedienen
It stays in the history, and its release stays on the blocklist.
Parameter
| Feld | Wo | Typ | Bedeutung |
|---|---|---|---|
download_id * | path | integer |
Antwort 200 ActOut
| Feld | Typ | Bedeutung |
|---|---|---|
download * | QueueItemOut | The download as it stands after the action. |
Fehlercodes
- 401
api_key_missing,api_key_invalid - 403
scope_missing - 404
download_not_found - 409
action_not_allowed,download_not_failed - 422
invalid_input - 500
internal_error
POST/api/v1/downloads/{download_id}/confirm-mappingConfirm the proposed path of a downloadBedienen
Stores the proposal of path_not_found with the download client and files the download away again.
Parameter
| Feld | Wo | Typ | Bedeutung |
|---|---|---|---|
download_id * | path | integer |
Antwort 200 ActOut
| Feld | Typ | Bedeutung |
|---|---|---|
download * | QueueItemOut | The download as it stands after the action. |
Fehlercodes
- 401
api_key_missing,api_key_invalid - 403
scope_missing - 404
download_not_found - 409
action_not_allowed,mapping_not_proposed - 422
invalid_input - 500
internal_error
GET/api/v1/downloads/{download_id}/filesThe files of a stuck downloadLesen
Every video with what nexcrate read from its name and decided; for a series every episode in TMDB's numbers with the file the version holds for it. name is relative to the download, never a path of the disk.
Parameter
| Feld | Wo | Typ | Bedeutung |
|---|---|---|---|
download_id * | path | integer |
Fehlercodes
- 401
api_key_missing,api_key_invalid - 403
scope_missing - 404
download_not_found - 422
invalid_input - 500
internal_error
POST/api/v1/downloads/{download_id}/finishFile nothing more of a downloadBedienen
The download counts as filed with what is filed; the rest is not filed.
Parameter
| Feld | Wo | Typ | Bedeutung |
|---|---|---|---|
download_id * | path | integer |
Antwort 200 ActOut
| Feld | Typ | Bedeutung |
|---|---|---|
download * | QueueItemOut | The download as it stands after the action. |
Fehlercodes
- 401
api_key_missing,api_key_invalid - 403
scope_missing - 404
download_not_found - 409
action_not_allowed,download_not_assignable,download_busy - 422
invalid_input - 500
internal_error
POST/api/v1/downloads/{download_id}/removeRemove a downloadBedienen
The download client drops the job (SABnzbd with its files, a torrent without). With search_again the release goes on the title's blocklist and the title into the order of the automatic, even with its switch off. Filed files are never touched.
Parameter
| Feld | Wo | Typ | Bedeutung |
|---|---|---|---|
download_id * | path | integer |
Antwort 200 ActOut
| Feld | Typ | Bedeutung |
|---|---|---|
download * | QueueItemOut | The download as it stands after the action. |
Fehlercodes
- 401
api_key_missing,api_key_invalid - 403
scope_missing - 404
download_not_found - 409
action_not_allowed,download_finished - 422
invalid_input - 500
internal_error
POST/api/v1/downloads/{download_id}/retryTry a download againBedienen
A problem the client reported goes back to the client, any other to filing away.
Parameter
| Feld | Wo | Typ | Bedeutung |
|---|---|---|---|
download_id * | path | integer |
Antwort 200 ActOut
| Feld | Typ | Bedeutung |
|---|---|---|
download * | QueueItemOut | The download as it stands after the action. |
Fehlercodes
- 401
api_key_missing,api_key_invalid - 403
scope_missing - 404
download_not_found - 409
action_not_allowed,download_not_retryable - 422
invalid_input - 500
internal_error
POST/api/v1/downloads/{download_id}/searchSearch the title of a download againBedienen
The title goes into the order of the automatic, even with its switch off, within the indexers' budget. A failed download is taken off the problems with it.
Parameter
| Feld | Wo | Typ | Bedeutung |
|---|---|---|---|
download_id * | path | integer |
Antwort 200 ActOut
| Feld | Typ | Bedeutung |
|---|---|---|
download * | QueueItemOut | The download as it stands after the action. |
Fehlercodes
- 401
api_key_missing,api_key_invalid - 403
scope_missing - 404
download_not_found - 409
action_not_allowed - 422
invalid_input - 500
internal_error
GET/api/v1/foreign-jobsJobs in nexcrate's category that no download followsLesen
Put there by hand, by another program, or handed over without an answer and never matched; read from the clients once a minute. nexcrate never imports them by itself. The owner assigns one to a movie in the interface; a program can remove one. Since 22.09.2026.
Antwort 200 ForeignJobsV1Out
| Feld | Typ | Bedeutung |
|---|---|---|
items * | array of ForeignJobV1Out |
Fehlercodes
- 401
api_key_missing,api_key_invalid - 403
scope_missing - 500
internal_error
POST/api/v1/foreign-jobs/{job_id}/importAssign a foreign job to a title of the library and import itBedienen
As in the interface: the job becomes a download of the version and is filed away when finished. Only titles of the library; a series job is for the episodes its name names. Needs the scope operate. Since 22.09.2026.
Parameter
| Feld | Wo | Typ | Bedeutung |
|---|---|---|---|
job_id * | path | integer |
Anfrage ForeignAdoptV1In
| Feld | Typ | Bedeutung |
|---|---|---|
kind * | "movie" | "series" | "album" | |
ref * | string | The title as everywhere in /api/v1, for example tmdb:603. |
version_id * | string | The public id of the version definition. |
Antwort 201 ForeignAdoptV1Out
| Feld | Typ | Bedeutung |
|---|---|---|
download_id * | integer | The download the job became; follow it in the queue. |
Fehlercodes
- 401
api_key_missing,api_key_invalid - 403
scope_missing - 404
not_found,title_not_found - 409
foreign_job_failed,foreign_same_release,foreign_no_version,foreign_no_episodes,version_owned_by_source - 422
invalid_input,version_unknown,version_kind_mismatch - 500
internal_error
POST/api/v1/foreign-jobs/{job_id}/removeRemove a foreign job with its filesBedienen
The job leaves the download client with its files. Needs the scope operate.
Parameter
| Feld | Wo | Typ | Bedeutung |
|---|---|---|---|
job_id * | path | integer |
Fehlercodes
- 401
api_key_missing,api_key_invalid - 403
scope_missing - 404
not_found - 422
invalid_input - 500
internal_error - 502
client_unreachable
GET/api/v1/problemsDownloads with a problem, and what may be doneLesen
The downloads of the queue with a problem or a hint, those that need somebody first. Each problem names its allowed actions and which of them an automatic may take without a human.
Parameter
| Feld | Wo | Typ | Bedeutung |
|---|---|---|---|
kind | query | string | null |
Antwort 200 QueueOut
| Feld | Typ | Bedeutung |
|---|---|---|
items * | array of QueueItemOut | Newest first. |
Fehlercodes
- 401
api_key_missing,api_key_invalid - 403
scope_missing - 422
kind_unsupported,invalid_input - 500
internal_error
GET/api/v1/queueWhat is loading, stuck or failedLesen
Every download that is not finished, one entry per download with its episodes and one state: running, stuck, and failed ones that wait for the owner. Progress and remaining time are only here, never events.
Parameter
| Feld | Wo | Typ | Bedeutung |
|---|---|---|---|
kind | query | string | null |
Antwort 200 QueueOut
| Feld | Typ | Bedeutung |
|---|---|---|
items * | array of QueueItemOut | Newest first. |
Fehlercodes
- 401
api_key_missing,api_key_invalid - 403
scope_missing - 422
kind_unsupported,invalid_input - 500
internal_error
GET/api/v1/queue/{download_id}One downloadLesen
A download as the queue lists it, also after it finished.
Parameter
| Feld | Wo | Typ | Bedeutung |
|---|---|---|---|
download_id * | path | integer |
Fehlercodes
- 401
api_key_missing,api_key_invalid - 403
scope_missing - 404
download_not_found - 422
invalid_input - 500
internal_error
Ereignisse
Was passiert ist, als Liste mit Laufnummer oder als Strom. Webhooks schicken dasselbe.
GET/api/v1/eventsWhat happened since a numberLesen
Events after after, oldest first; ask again with next_after. Start with the latest of a first call. Events stay 90 days; a number older than that answers 410 marker_too_old: read the library again. Types: title.added, title.changed, title.removed, version.added, version.removed, download.started, download.state, download.imported, download.failed, download.removed, problem.opened, problem.closed, file.deleted, file.restored, request.made, request.withdrawn, series.season_complete, version_definition.added, version_definition.changed, version_definition.removed, health.changed, source.taken_over, source.takeover_undone.
Parameter
| Feld | Wo | Typ | Bedeutung |
|---|---|---|---|
after | query | integer | The next_after of the last answer. |
limit | query | integer |
Antwort 200 EventsOut
| Feld | Typ | Bedeutung |
|---|---|---|
items * | array of EventOut | Oldest first. |
next_after * | integer | Ask with this next. |
more * | boolean | True: ask again at once. |
latest * | integer | The highest number given so far. |
Fehlercodes
- 401
api_key_missing,api_key_invalid - 403
scope_missing - 410
marker_too_old - 422
invalid_input - 500
internal_error
GET/api/v1/events/streamThe events as a streamLesen
The same events as Server-Sent Events: id is the number, event the type, data the event as JSON; a comment every 15 seconds keeps proxies from closing. One way only: nexcrate never needs to reach the program. After a break reconnect with the header Last-Event-ID or after. A stream ends after an hour. At most 5 open streams per key (too_many_streams).
Parameter
| Feld | Wo | Typ | Bedeutung |
|---|---|---|---|
after | query | integer | null | The number to follow; the latest when left out. |
Last-Event-ID | header | string | null |
Fehlercodes
- 401
api_key_missing,api_key_invalid - 403
scope_missing - 410
marker_too_old - 422
invalid_input - 429
too_many_streams - 500
internal_error
Kalender und Wertungen
Was wann erscheint, und die Wertungen von IMDb, Rotten Tomatoes und Metacritic.
GET/api/v1/calendarWhat comes out in a span of daysLesen
Movies with their cinema, digital and disc dates, episodes on the day they air, at most 100 days at once. A movie's date is the one of the region (the one set in nexcrate, or region); without a date there, the earliest anywhere, and country names it.
Parameter
| Feld | Wo | Typ | Bedeutung |
|---|---|---|---|
from * | query | string | YYYY-MM-DD. |
to * | query | string | YYYY-MM-DD. |
kind | query | string | null | |
region | query | string | null | ISO 3166-1; left out, the one set. |
monitored | query | boolean | Only what a version watches. |
missing | query | boolean | Only what has no file yet. |
Antwort 200 CalendarOut
| Feld | Typ | Bedeutung |
|---|---|---|
from * | string | |
to * | string | |
region * | string | The region the movie dates come from; empty is the earliest date anywhere. |
items * | array of CalendarEntryOut | By day. |
truncated * | boolean | The span held more entries than one answer carries: ask a shorter one. |
Fehlercodes
- 401
api_key_missing,api_key_invalid - 403
scope_missing - 422
kind_unsupported,invalid_input - 500
internal_error
POST/api/v1/ratingsIMDb ratings of many titles at onceLesen
Up to 100 titles, also titles that are in no library, from nexcrate's own copy of IMDb's daily file; Rotten Tomatoes and Metacritic from the 30-day store of OMDb answers. A tmdb: title nexcrate does not have is looked up at TMDB once for its IMDb number (kept 30 days); nothing else leaves. Information courtesy of IMDb (https://www.imdb.com). Used with permission.
Anfrage RatingsIn
| Feld | Typ | Bedeutung |
|---|---|---|
items * | array of RatingItemIn |
Antwort 200 RatingsOut
| Feld | Typ | Bedeutung |
|---|---|---|
items * | array of RatingItemOut | In the order asked. |
imdb * | string | loaded, off (the owner switched it off) or not_loaded (not loaded yet). |
attribution * | string | Show it where the ratings show. |
omdb_attribution * | string | null | Show it too when any Rotten Tomatoes or Metacritic value shows; null when none does. |
Fehlercodes
- 401
api_key_missing,api_key_invalid - 403
scope_missing - 422
invalid_input - 500
internal_error
GET/api/v1/ratings/{kind}/{ref}The ratings of one titleLesen
IMDb from nexcrate's copy; with an OMDb key of the owner also Rotten Tomatoes and Metacritic (movies only), kept 30 days and within OMDb's daily limit. Information courtesy of IMDb (https://www.imdb.com). Used with permission.
Parameter
| Feld | Wo | Typ | Bedeutung |
|---|---|---|---|
kind * | path | string | |
ref * | path | string |
Antwort 200 RatingOut
| Feld | Typ | Bedeutung |
|---|---|---|
kind * | string | |
ref * | string | |
imdb_ref * | string | null | |
imdb * | ImdbRatingOut | null | |
rotten_tomatoes * | integer | null | The Tomatometer in percent. |
metacritic * | integer | null | The Metascore, 0 to 100. |
sources * | object of string | imdb: loaded, off or not_loaded. omdb: ok, not_found, no_key, key_invalid, limit (the day's requests are used up), failed, or not_for_kind (OMDb has no such values for series). |
attribution * | array of string |
Fehlercodes
- 401
api_key_missing,api_key_invalid - 403
scope_missing - 404
imdb_unknown - 409
ref_ambiguous - 422
kind_unsupported,ref_invalid,ref_source_unknown,invalid_input - 500
internal_error
Papierkorb
Was ersetzt oder gelöscht wurde und noch zurückgeholt werden kann.
GET/api/v1/recycle-binRead the recycle binLesen
What was deleted, by whom, and whether it can come back: movies, series and albums, one entry per file.
Parameter
| Feld | Wo | Typ | Bedeutung |
|---|---|---|---|
kind | query | string | null |
Antwort 200 RecycleBinOut
| Feld | Typ | Bedeutung |
|---|---|---|
items * | array of RecycleEntryOut | Newest first. |
Fehlercodes
- 401
api_key_missing,api_key_invalid - 403
scope_missing - 422
kind_unsupported,invalid_input - 500
internal_error
POST/api/v1/recycle-bin/{entry_id}/restoreTake a file back out of the recycle binAnfragen
The file goes back where it was and counts again. Refused when something lies there (recycle_target_taken), when the version or episode has another file by now (recycle_slot_taken), when the title or version left the library (recycle_title_gone) or when the file is gone (recycle_file_gone); the file then stays in the bin.
Parameter
| Feld | Wo | Typ | Bedeutung |
|---|---|---|---|
entry_id * | path | integer |
Antwort 200 RestoredOut
| Feld | Typ | Bedeutung |
|---|---|---|
title * | TitleOut |
Fehlercodes
- 401
api_key_missing,api_key_invalid - 403
scope_missing - 404
not_found - 409
recycle_target_taken,recycle_slot_taken,recycle_title_gone,recycle_file_gone,version_fed_by_source - 422
invalid_input - 500
internal_error
Koppeln
Ein Programm bittet um einen Schlüssel, der Besitzer bestätigt in nexcrate. Die einzigen Adressen ohne Schlüssel.
POST/api/v1/pairingAsk to be connectedohne Schlüssel
Needs no key. nexcrate shows the request with its code to the owner, who confirms it with the scopes of the owner's choice or denies it. Ask GET /api/v1/pairing/{pairing_id} with the secret until it is decided; a request lives 10 minutes, at most 5 wait at once.
Anfrage PairingIn
| Feld | Typ | Bedeutung |
|---|---|---|
app * | string | The program's name, shown to the owner. |
scopes * | array of string | read, request, operate; the owner may choose fewer. |
Antwort 201 PairingOut
| Feld | Typ | Bedeutung |
|---|---|---|
pairing_id * | string | |
secret * | string | Send it as X-Pairing-Secret when asking how the request stands. Shown once. |
code * | string | Show it to the owner: nexcrate shows the same. |
expires_at * | string | |
poll_seconds * | integer | Ask again after this many seconds. |
Fehlercodes
- 403
csrf_header_missing - 422
invalid_input - 429
pairing_limit - 500
internal_error
GET/api/v1/pairing/{pairing_id}How a request to be connected standsohne Schlüssel
With the header X-Pairing-Secret. Confirmed, the answer carries the key once; from then on the request is delivered. An unknown request and a wrong secret both answer 404.
Parameter
| Feld | Wo | Typ | Bedeutung |
|---|---|---|---|
pairing_id * | path | string | |
X-Pairing-Secret | header | string | null |
Antwort 200 PairingStateOut
| Feld | Typ | Bedeutung |
|---|---|---|
state * | string | pending, confirmed (this answer carries the key), delivered, denied or expired. |
key * | string | null | The key, exactly once: in the first answer after the owner confirmed. |
scopes * | array of string | null | What the owner granted, with the key. |
expires_at * | string |
Fehlercodes
- 404
pairing_not_found - 422
invalid_input - 500
internal_error