# Jellyfin server API delta: 10.11.x → next major Research date: **2026-09-08**. All claims verified against live sources; no claim below is from model memory. Method: GitHub Releases/Tags API, the official release blog, the published OpenAPI spec, and a **byte-level diff of the actual C# source trees** at tags `v10.11.5` and `v12.0` (downloaded from `codeload.github.com`, extracted locally). --- ## Section 1 — Version reality check ### 🔴 Jellyfin 11.0 does not exist and never did. The complete tag list of `jellyfin/jellyfin` contains **zero** `v11.*` tags. The project went directly from the `10.11.x` branch to `12.0`. Source: `https://api.github.com/repos/jellyfin/jellyfin/tags` (all 8 pages; 116 tags total). Major-version histogram: `v10` × 107, `v12` × 8, `v3` × 1. `11.x tags: []`. ### What actually exists today (2026-09-08) | Version | Status | Published | Source | |---|---|---|---| | **12.0** | **Current stable / `releases/latest`** | **2026-09-08T01:38:39Z** (today) | `https://api.github.com/repos/jellyfin/jellyfin/releases/latest` | | 12.0-rc1 … rc7 | prereleases | 2026-06 → 2026-08-31 | `https://api.github.com/repos/jellyfin/jellyfin/releases` | | 10.11.11 | last release on the 10.11 branch | 2026-06-06T16:18:54Z | `https://api.github.com/repos/jellyfin/jellyfin/releases/tags/v10.11.11` | | 10.11.5 | **what JellyTau targets** | 2025-12-15 (file mtime in tag tarball) | `https://codeload.github.com/jellyfin/jellyfin/tar.gz/refs/tags/v10.11.5` | | 10.11.0 | 10.11 branch opened | 2025-10-20 | `https://jellyfin.org/posts/jellyfin-release-10.11.0` | **v12.0 was released roughly 18 hours before this research was performed.** Treat "12.0 in the wild" as approximately zero installs today, rising over the coming months. ### Why the number jumped 10.11 → 12.0 Official rationale, quoted from the release blog: > "The most visible change in this release is the one in its name: we are dropping the major > version '10' from our naming scheme. What would have been 10.12.0 is simply 12.0, and the > server reports its version as `12.0.0`. 10.11.x was the last release branch to use the old > scheme. […] Jumping to 11.0 would still look like a minor increment […]" > "**If you maintain anything that parses Jellyfin version strings** — a client, a monitoring > check, a deployment script, a container tag pin — **this is the item to look at before > upgrading.**" Source: `https://jellyfin.org/posts/jellyfin-release-12.0` (dated September 7, 2026) So: `12.0` *is* `10.12` under the old scheme. It is one release-branch step from 10.11, not two. **"Two server generations from one build" means 10.11.x and 12.x.** There is no third thing. ⚠️ Direct consequence for JellyTau: `/System/Info/Public` returns `Version: "12.0.0"` on the new generation and `"10.11.5"` on the old. Any version comparison must not assume a leading `10.`. --- ## Section 2 — Confirmed changes ### 2.1 Routes: the legacy user-scoped family SURVIVES intact **The `/Users/{userId}/…` route family that JellyTau depends on in ~17 call sites is NOT removed in 12.0.** Every route the task listed still exists and still functions. Verified by diffing every `[HttpGet|Post|Delete|Put|Patch|Head]` attribute across `Jellyfin.Api/Controllers/` in both tags (369 routes in 10.11.5, 364 in 12.0). **Complete list of routes removed in 12.0 — all six:** | Route | Handler | |---|---| | `POST /Users/{userId}/EasyPassword` | `UpdateUserEasyPassword` | | `GET /Items/{itemId}/CriticReviews` | `GetCriticReviews` | | `GET /Environment/NetworkShares` | `GetNetworkShares` | | `POST /System/MediaEncoder/Path` | `UpdateMediaEncoderPath` | | `GET /LiveTv/Recordings/Groups/{groupId}` | `GetRecordingGroup` | | `GET /QuickConnect/Initiate` | `InitiateQuickConnectLegacy` | **Complete list of routes added in 12.0 — one:** `GET /Items/{itemId}/Collections` (`GetItemCollections`). Sources: - Route diff computed from `https://codeload.github.com/jellyfin/jellyfin/tar.gz/refs/tags/v10.11.5` and `.../v12.0`, directory `Jellyfin.Api/Controllers/`. - Corroborated verbatim by the release notes: "Removed obsolete API routes: `POST /Users/{userId}/EasyPassword` (the EasyPassword feature is gone), `GET /Items/{itemId}/CriticReviews`, `GET /Environment/NetworkShares`, `POST /System/MediaEncoder/Path`, `GET /LiveTv/Recordings/Groups/{groupId}`, and `GET /QuickConnect/Initiate`" — `https://api.github.com/repos/jellyfin/jellyfin/releases/tags/v12.0` **Confirmed present and functional in v12.0** (`Jellyfin.Api/Controllers/`, tag `v12.0`): | Route | File:line in v12.0 | |---|---| | `GET /Users/{userId}/Items` | `ItemsController.cs:721` | | `GET /Users/{userId}/Items/Resume` | `ItemsController.cs:1027` | | `GET /Users/{userId}/Items/Latest` | `UserLibraryController.cs:619` | | `GET /Users/{userId}/Views` | `UserViewsController.cs:107` | | `GET /Users/{userId}/Items/{itemId}` | `UserLibraryController.cs:117` | | `POST /Users/{userId}/FavoriteItems/{itemId}` | `UserLibraryController.cs:252` | | `DELETE /Users/{userId}/FavoriteItems/{itemId}` | `UserLibraryController.cs:300` | | `POST /Users/{userId}/PlayedItems/{itemId}` | `PlaystateController.cs:120` | | `DELETE /Users/{userId}/PlayedItems/{itemId}` | `PlaystateController.cs:185` | ### 2.2 …but the whole family was ALREADY deprecated in 10.11.5, and 12.0 hardens the policy This is **not a new deprecation**. Every one of those methods already carried `[Obsolete("Kept for backwards compatibility")]` **and** `[ApiExplorerSettings(IgnoreApi = true)]` in 10.11.5, at the same positions. Nothing changed about their status between the two versions. Confirmed: the 12.0 OpenAPI spec contains only these `/Users` paths — `/Users`, `/Users/AuthenticateByName`, `/Users/AuthenticateWithQuickConnect`, `/Users/Configuration`, `/Users/ForgotPassword`, `/Users/ForgotPassword/Pin`, `/Users/Me`, `/Users/New`, `/Users/Password`, `/Users/Public`, `/Users/{userId}`, `/Users/{userId}/Policy`. **None of the item/view/favorite/played routes appear.** Source: `https://api.jellyfin.org/openapi/jellyfin-openapi-stable.json` (`info.version` = `"12.0.0"`, `x-jellyfin-version` = `"12.0.0"`, 294 paths). What *is* new in 12.0 is the written removal policy: > "If an endpoint isn't listed in the OpenAPI specification it should not be used by clients. > There are certain endpoints that are still exposed for legacy reasons despite being excluded > from the OpenAPI spec. **These can be removed in any major release without warning.**" > "As a general rule, any deprecations will be marked as such for an entire (major) release cycle > before the deprecated endpoint or parameter is liable for removal." Source: `https://api.github.com/repos/jellyfin/jellyfin/releases/tags/v12.0` **Assessment:** the user-scoped family needs no migration to run on 12.0, but it is now formally removable without notice in 13.0. The replacements (`/Items?userId=`, `/UserViews?userId=`, `/UserFavoriteItems/{itemId}`, `/UserPlayedItems/{itemId}`) **already exist in 10.11.5**, so migrating is a one-generation-compatible change, not a branch. Verified: `GET /Items` accepts `[FromQuery] Guid? userId` in v12.0 (`ItemsController.cs:171-174`), and non-user-scoped twins exist in *both* trees (`UserLibraryController.cs`: `UserFavoriteItems/{itemId}`, `UserItems/{itemId}/Rating`). ### 2.3 🔴 AUTHENTICATION — the one genuinely breaking change for JellyTau **`X-Emby-Authorization` is disabled by default in 12.0, including on upgraded servers. `api_key` as a query parameter is disabled by default in 12.0.** The authoritative accepted/deprecated table, from the Jellyfin core team's canonical client-developer gist (last updated 2026-09-08): | Type | Name | Method | Deprecated | |---|---|---|---| | Header | `Authorization` | Schema | **No** | | Query | `ApiKey` | Token only | **No**, but discouraged | | Query | `api_key` | Token only | **yes** | | Header | `X-Emby-Token` | Token only | **yes** | | Header | `X-MediaBrowser-Token` | Token only | **yes** | | Header | `X-Emby-Authorization` | Schema | **yes** | Source: `https://gist.github.com/nielsvanvelzen/ea047d9028f676185832e51ffaf12a6f` (referenced from PR #13306 and from the 12.0 release notes) **Verified in source.** `Jellyfin.Server.Implementations/Security/AuthorizationContext.cs` is **byte-identical between v10.11.5 and v12.0** except one whitespace change (`authorizationHeader[start.. i]` → `[start..i]`). The gating logic in **both** versions: ```csharp // always read, no gate: var auth = httpReq.Headers[HeaderNames.Authorization]; if (_configurationManager.Configuration.EnableLegacyAuthorization && string.IsNullOrEmpty(auth)) { auth = httpReq.Headers["X-Emby-Authorization"]; } ... var validName = name.Equals("MediaBrowser", StringComparison.OrdinalIgnoreCase); // always OK validName = validName || (…EnableLegacyAuthorization && name.Equals("Emby", …)); // gated ... if (…EnableLegacyAuthorization && string.IsNullOrEmpty(token)) { token = headers["X-Emby-Token"]; } if (…EnableLegacyAuthorization && string.IsNullOrEmpty(token)) { token = headers["X-MediaBrowser-Token"]; } if (string.IsNullOrEmpty(token)) { token = queryString["ApiKey"]; } // NOT gated if (…EnableLegacyAuthorization && string.IsNullOrEmpty(token)) { token = queryString["api_key"]; } // gated ``` Source: `https://raw.githubusercontent.com/jellyfin/jellyfin/v12.0/Jellyfin.Server.Implementations/Security/AuthorizationContext.cs` (and the `v10.11.5` path of the same file) **The only difference between the two versions is the default of the gate:** - `v10.11.5` — `MediaBrowser.Model/Configuration/ServerConfiguration.cs:290`: `public bool EnableLegacyAuthorization { get; set; } = true;` - `v12.0` — same file, same line: `public bool EnableLegacyAuthorization { get; set; }` (no initializer → C# default `false`) Source: `https://raw.githubusercontent.com/jellyfin/jellyfin/v10.11.5/MediaBrowser.Model/Configuration/ServerConfiguration.cs` and `.../v12.0/...` **Existing installs are flipped too**, by a migration that runs on first boot: ```csharp [JellyfinMigration("2026-05-31T16:00:00", nameof(DisableLegacyAuthorization), …)] public class DisableLegacyAuthorization : IAsyncMigrationRoutine { public Task PerformAsync(CancellationToken cancellationToken) { _serverConfigurationManager.Configuration.EnableLegacyAuthorization = false; _serverConfigurationManager.SaveConfiguration(); ``` Source: `tree/jellyfin-12.0/Jellyfin.Server/Migrations/Routines/20260531160000_DisableLegacyAuthorization.cs` (from `https://codeload.github.com/jellyfin/jellyfin/tar.gz/refs/tags/v12.0`) Release-note wording: "Legacy authorization is now disabled by default, and a migration disables it on existing installs as well." Source: `https://api.github.com/repos/jellyfin/jellyfin/releases/tags/v12.0` Blog wording: "the deprecated way of signing in is now disabled, including on existing servers." Source: `https://jellyfin.org/posts/jellyfin-release-12.0` Change history (all merged): - PR #13306 "Add option to disable deprecated legacy authorization options", merged 2025-01-11, shipped in 10.11 with default `true`. Body: *"The only method we'll allow is the `Authorization` header with `MediaBrowser` scheme and the `ApiKey` query parameter. The other headers (`X-Emby-Authorization`, `X-Emby-Token`, `X-MediaBrowser-Token`), query parameter (`api_key`) and authorization scheme (`Emby`) are all deprecated."* `https://api.github.com/repos/jellyfin/jellyfin/pulls/13306` - PR #15559 "Disable legacy authorization methods by default", merged 2025-11-27. Body: *"We'll remove this configuration option (and the authorization methods) in a future release, likely 10.13."* `https://api.github.com/repos/jellyfin/jellyfin/pulls/15559` - PR #16754 "Keep legacy authorization enabled" (temporary revert), merged 2026-05-05. `https://api.github.com/repos/jellyfin/jellyfin/pulls/16754` - PR #16992 "Re-disable legacy authorization methods by default", merged 2026-06-01 — the state that shipped. `https://api.github.com/repos/jellyfin/jellyfin/pulls/16992` #### 🟢 The critical good news: query-param auth for media players is SAFE `ApiKey` (capital A, capital K, no underscore) as a **query parameter** is **not** deprecated and **not** gated in either version. The server itself generates it — identically in both trees: - `v10.11.5` `MediaBrowser.Model/Dlna/StreamInfo.cs:1042` → `sb.Append("&ApiKey=");` - `v12.0` `MediaBrowser.Model/Dlna/StreamInfo.cs:1034` → `sb.Append("&ApiKey=");` - `v12.0` `StreamInfo.cs:1279-1280` → `// Use "?ApiKey=" as seen in HEAD and other parts of the code` So the load-bearing requirement — handing stream URLs to mpv / ExoPlayer / HTML5 `