Skip to content

fix(api): update OpenAPI schema to match actual API responses#2700

Open
electather wants to merge 4 commits intoseerr-team:developfrom
electather:fix/api-schema-updates
Open

fix(api): update OpenAPI schema to match actual API responses#2700
electather wants to merge 4 commits intoseerr-team:developfrom
electather:fix/api-schema-updates

Conversation

@electather
Copy link

@electather electather commented Mar 15, 2026

Description

Updates seerr-api.yml to align schema definitions with actual API responses. Discrepancies were discovered while building https://github.com/electather/seer-cli, an MCP server and CLI for Seerr.

  • PlexDevice: renamed type → mediaType
  • User: added missing fields (settings, displayName, jellyfinUsername, jellyfinUserId, plexId, warnings, avatarETag, avatarVersion,
    quota fields, etc.); relaxed required
  • UserUpdatePayload: new schema; PUT /user/{userId} request body now references it instead of User
  • MediaRequest: added type, languageProfileId, tags, isAutoRequest, seasons, seasonCount, profileName, canRemove
  • MediaInfo: added imdbId, mediaType, status4k, service IDs/slugs, Jellyfin fields, downloadStatus, mediaUrl, etc.
  • Person: fixed gender and popularity types (string → number); added birthday; made several fields nullable
  • WatchProviders: fixed from array-of-objects to a single object
  • Issue: added status field
  • OverrideRule: added id, users, genre, language, keywords, profileId, rootFolder, tags, service IDs, timestamps
  • POST /overrideRule & PUT /overrideRule/{ruleId}: response changed from array to OverrideRule

I used claude code as an assistant.

How Has This Been Tested?

Validated by consuming the live API through https://github.com/electather/seer-cli and comparing actual response payloads against the schema.

Screenshots / Logs (if applicable)

Checklist:

  • I have read and followed the contribution guidelines.
  • Disclosed any use of AI (see our policy)
  • I have updated the documentation accordingly.
  • All new and existing tests passed.
  • Successful build pnpm build
  • Translation keys pnpm i18n:extract
  • Database migration (if required)

Summary by CodeRabbit

  • New Features
    • User profiles enhanced with settings, display name, connected accounts, warnings, avatar/version and quota limits; PUT user now accepts a simplified update payload
    • Media details expanded with IMDB IDs, mediaType, service/external IDs, rating keys, added dates, 4K/status fields, download status and media URLs
    • Override rules accept more filters (users, genres, languages, keywords, profiles, folders, tags) and now return a single rule
    • Watch provider data restructured by region with buy/flat-rate lists (object)
    • Watchlist/Blocklist entries now include explicit mediaType
    • Person/cast and other metadata expanded with nullable/read-only fields for broader metadata exposure

electather and others added 2 commits March 15, 2026 10:36
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The endpoint rejects email as read-only; confirmed via live API test.
@electather electather requested a review from a team as a code owner March 15, 2026 11:10
@coderabbitai
Copy link

coderabbitai bot commented Mar 15, 2026

📝 Walkthrough

Walkthrough

The OpenAPI spec seerr-api.yml was updated: added UserUpdatePayload; expanded User, MediaInfo, PersonDetails, OverrideRule, Issue and related schemas with many nullable/readOnly fields and additionalProperties; changed WatchProviders from an array to an object; PUT /user/{userId} now accepts UserUpdatePayload; POST/PUT /overrideRule now return a single OverrideRule; various endpoints expose mediaType in watchlist/blocklist items.

Changes

Cohort / File(s) Summary
User & Auth Schemas
seerr-api.yml
Added UserUpdatePayload (username, permissions). Extended User with settings, displayName, jellyfinUsername, jellyfinUserId, plexId, warnings, recoveryLinkExpirationDate, avatarETag, avatarVersion, movieQuotaLimit, movieQuotaDays, tvQuotaLimit, tvQuotaDays; adjusted required/readOnly semantics. PUT /user/{userId} now consumes UserUpdatePayload.
MediaInfo & Result Models
seerr-api.yml
Expanded MediaInfo (e.g., imdbId, mediaType, status4k, lastSeasonChange, mediaAddedAt, serviceId*, externalServiceId*, externalServiceSlug*, ratingKey*, jellyfinMediaId*, serviceUrl, downloadStatus*, mediaUrl) and allowed additionalProperties. MovieResult, TvResult, and related models updated to surface these fields; many fields nullable/readOnly.
Watch Providers
seerr-api.yml
WatchProviders schema changed from an array to a single object with iso_3166_1, link, buy[], and flatrate[] (using WatchProviderDetails[]); public references adjusted.
Override Rules & Endpoints
seerr-api.yml
OverrideRule extended (id, users, genre, language, keywords, profileId, rootFolder, tags, radarrServiceId, sonarrServiceId, createdAt, updatedAt). POST /overrideRule and PUT /overrideRule/{ruleId} responses switched from arrays to a single OverrideRule.
Watchlist / Blocklist
seerr-api.yml
Added/replaced mediaType fields in watchlist/blocklist item schemas (replacing prior type usage) across payloads and endpoints.
Person & People Models
seerr-api.yml
PersonDetails adjusted: birthday/deathday nullable; gender and popularity numeric; placeOfBirth/profilePath nullable; related person models updated.
Issues & Misc Schema Hygiene
seerr-api.yml
Added numeric status to Issue. Numerous schemas updated to mark fields nullable/readOnly or allow additionalProperties to accommodate richer/optional metadata.
Endpoint Response Signatures
seerr-api.yml
Multiple endpoints adjusted to return single-resource responses (notably override rule endpoints); payload shapes updated where noted.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 I hopped through YAML, adding fields galore,
IDs and quotas, and 4K to adore.
WatchProviders cuddled into one cozy nest,
Override rules trimmed to a single-best.
A tiny rabbit cheer — the schema’s more blessed!

🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: updating OpenAPI schema definitions to match actual API responses, which aligns with all substantive changes in the changeset.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@seerr-api.yml`:
- Around line 76-77: The inline watchlist item schemas still use the field name
"type" while the top-level schema uses "mediaType", causing inconsistent
generated clients; locate the inline watchlist item definitions that declare
"type" (the watchlist item objects referenced by the watchlist endpoints) and
either rename those inline properties from "type" to "mediaType" to match the
existing schema or refactor by extracting a single shared WatchlistItem schema
and reference it from each endpoint so the contract for the watchlist item field
name is defined in one place.
- Around line 139-141: The settings property currently places nullable: true
alongside a $ref (settings with $ref '#/components/schemas/UserSettings' and
nullable: true), which OpenAPI 3.0.2 ignores; change the settings schema to use
an allOf composition that contains the $ref to
'#/components/schemas/UserSettings' and set nullable: true on the allOf wrapper
so the reference becomes properly nullable (i.e., replace the direct $ref +
nullable with an allOf array containing the $ref and apply nullable: true to the
allOf object).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ce9bbb14-f934-46a0-8b3d-9f87b4e15c79

📥 Commits

Reviewing files that changed from the base of the PR and between 0be1896 and cef9fcc.

📒 Files selected for processing (1)
  • seerr-api.yml

- Rename inline `type` property to `mediaType` in watchlist item
  schemas for /user/{userId}/watchlist and /discover/watchlist to
  match the top-level Watchlist schema
- Replace $ref + nullable: true on User.settings with allOf
  composition to comply with OpenAPI 3.0.2 (nullable on $ref is
  ignored without allOf)
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@seerr-api.yml`:
- Around line 175-177: The OpenAPI schema declares User.avatarVersion as integer
but runtime/DB uses a varchar; update the schema to match runtime by changing
the avatarVersion property in seerr-api.yml (User.avatarVersion) from type:
integer to type: string (keeping nullable: true), or alternatively change the
model/serializer that emits avatarVersion to an actual integer—ensure both the
OpenAPI field "avatarVersion" and the runtime serialization agree on string vs
integer to avoid client/validator breakage.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e28b62bf-918b-46ab-980e-38decbcfc90c

📥 Commits

Reviewing files that changed from the base of the PR and between cef9fcc and 459c266.

📒 Files selected for processing (1)
  • seerr-api.yml

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
seerr-api.yml (1)

1322-1340: Tighten free-form object arrays to preserve generated client typing.

MediaRequest.seasons and MediaInfo.downloadStatus* use items: { type: object }, which makes the contract too loose and reduces client/typegen value. Consider introducing explicit item schemas.

♻️ Suggested schema tightening
     MediaRequest:
       type: object
       properties:
@@
         seasons:
           type: array
           items:
-            type: object
+            $ref: '#/components/schemas/RequestSeason'
@@
     MediaInfo:
       type: object
       properties:
@@
         downloadStatus:
           type: array
           items:
-            type: object
+            $ref: '#/components/schemas/DownloadStatusEntry'
         downloadStatus4k:
           type: array
           items:
-            type: object
+            $ref: '#/components/schemas/DownloadStatusEntry'
+
+    RequestSeason:
+      type: object
+      additionalProperties: true
+
+    DownloadStatusEntry:
+      type: object
+      additionalProperties: true

Also applies to: 1429-1436

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@seerr-api.yml` around lines 1322 - 1340, The schemas use items: { type:
object } for MediaRequest.seasons and the MediaInfo.downloadStatus* arrays which
produces loose typings; replace those with explicit item schemas (either inline
objects with well-defined properties or references to new components like Season
and DownloadStatusEntry) and update MediaRequest.seasons to use $ref:
'#/components/schemas/Season' (or an equivalent explicit object with properties
such as seasonNumber, episodes, quality, etc.), and change
MediaInfo.downloadStatus* to arrays of a concrete DownloadStatus schema so
generated clients receive precise typings; ensure new schema names match
existing model naming and update any refs where seasons or download status
arrays are used.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@seerr-api.yml`:
- Around line 2244-2276: The OpenAPI schema in seerr-api.yml mismatches the
entity server/entity/OverrideRule.ts: fields users, keywords, tags (now declared
as array<number>) and genre (declared as number) should be strings like the
entity and routes expect. Fix by changing the schema types for users, keywords,
tags to type: string (nullable: true) instead of array items:number, and change
genre (and ensure language) to type: string (nullable: true) so the spec matches
the OverrideRule.ts runtime types and generated clients will expect strings.

---

Nitpick comments:
In `@seerr-api.yml`:
- Around line 1322-1340: The schemas use items: { type: object } for
MediaRequest.seasons and the MediaInfo.downloadStatus* arrays which produces
loose typings; replace those with explicit item schemas (either inline objects
with well-defined properties or references to new components like Season and
DownloadStatusEntry) and update MediaRequest.seasons to use $ref:
'#/components/schemas/Season' (or an equivalent explicit object with properties
such as seasonNumber, episodes, quality, etc.), and change
MediaInfo.downloadStatus* to arrays of a concrete DownloadStatus schema so
generated clients receive precise typings; ensure new schema names match
existing model naming and update any refs where seasons or download status
arrays are used.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: eccc1af2-12ad-48b8-b533-9b2a9b12ff15

📥 Commits

Reviewing files that changed from the base of the PR and between 459c266 and 133e230.

📒 Files selected for processing (1)
  • seerr-api.yml

Comment on lines +2244 to +2276
users:
type: array
nullable: true
items:
type: number
genre:
type: number
nullable: true
language:
type: string
nullable: true
keywords:
type: array
nullable: true
items:
type: number
profileId:
type: number
nullable: true
rootFolder:
type: string
nullable: true
tags:
type: array
nullable: true
items:
type: number
radarrServiceId:
type: number
nullable: true
sonarrServiceId:
type: number
nullable: true
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Locating OverrideRule files..."
entity_file="$(fd 'OverrideRule\.ts$' | head -n1 || true)"
route_file="$(fd 'overrideRule\.ts$' | head -n1 || true)"

echo "Entity file: ${entity_file:-NOT FOUND}"
echo "Route file:  ${route_file:-NOT FOUND}"

if [[ -n "${entity_file:-}" ]]; then
  echo
  echo "== Entity field declarations =="
  rg -n -C2 'users|genre|language|keywords|profileId|rootFolder|tags|radarrServiceId|sonarrServiceId|createdAt|updatedAt' "$entity_file"
fi

if [[ -n "${route_file:-}" ]]; then
  echo
  echo "== Route request typing + assignments =="
  rg -n -C3 'overrideRuleRoutes\.(post|put)|users\?:|genre\?:|language\?:|keywords\?:|profileId\?:|rootFolder\?:|tags\?:|radarrServiceId\?:|sonarrServiceId\?:|res\.status\(200\)\.json' "$route_file"
fi

Repository: seerr-team/seerr

Length of output: 2975


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Check the full entity file for serialization hooks
echo "=== Full OverrideRule.ts Entity ==="
cat -n server/entity/OverrideRule.ts

echo
echo "=== Checking for serialization transformations in routes ==="
rg -n 'toJSON|transform|serialize|exclude|expose|plainToClass' server/routes/overrideRule.ts || echo "No explicit transformations found"

Repository: seerr-team/seerr

Length of output: 1698


Fix schema type mismatch: users, keywords, tags are strings at runtime, not arrays.

The entity (server/entity/OverrideRule.ts) defines users, keywords, tags, genre, and language as string fields with no serialization transformations. The routes accept these as strings in request payloads. However, the schema now declares users/keywords/tags as array<number> and genre as number. Generated clients will expect numeric arrays but receive strings, causing runtime failures.

Either update the schema to match the string types or refactor the entity and routes to handle the numeric array types as intended.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@seerr-api.yml` around lines 2244 - 2276, The OpenAPI schema in seerr-api.yml
mismatches the entity server/entity/OverrideRule.ts: fields users, keywords,
tags (now declared as array<number>) and genre (declared as number) should be
strings like the entity and routes expect. Fix by changing the schema types for
users, keywords, tags to type: string (nullable: true) instead of array
items:number, and change genre (and ensure language) to type: string (nullable:
true) so the spec matches the OverrideRule.ts runtime types and generated
clients will expect strings.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant