Add Ratings
Apply user ratings (1-10) to movies, shows, or anime. Same auth model and batching rules as the rest of the Sync API. Ratings come back on every GET /sync/all-items item as user_rating, so reading them needs no extra request — see Read side below.
Body shape
Top-level keys per media type, each carrying an array of items:
Per-item fields:
| Field | Type | Required | Notes |
|---|---|---|---|
rating | int 1-10 | yes | Out-of-range values (0, 11, negatives) are silently ignored — see Out-of-range below. |
ids | object | yes | Any supported ID: simkl, imdb, tmdb, tvdb, mal, anidb, anilist, kitsu, livechart, anisearch, animeplanet. Plus optional title+year fallback. |
rated_at | ISO-8601 | no | Defaults to “now”. Use to back-date imports from another tracker. |
Re-rating an item overwrites the prior value — no need to call /sync/ratings/remove first.
Auto-move side effect
Rating an item that’s not yet on the user’s list auto-files it based on airing status:
| Item kind | New status |
|---|---|
| Released movie | completed |
| Unreleased / upcoming movie | plantowatch |
| Single-episode show | completed |
| Multi-episode show or anime (any other case) | watching |
The corresponding list timestamp on /sync/activities bumps, so a rated item shows up in the next date_from delta even though the user only rated it. Treat the delta as authoritative.
Response (201 Created)
added.anime does NOT exist. Anime items are folded into the shows counter — apps must not look for a separate anime slot in added or not_found. If you need to know which items landed, walk added.statuses[] (the request.ids echo back what you sent).
response.status per item is the watchlist status the auto-move applied (completed, watching, plantowatch, etc.) — useful for updating local UI without a follow-up /sync/activities poll.
Out-of-range ratings
Any rating outside 1-10 (including 0, 11, -1, 100) is silently rejected — the item lands in not_found.<type> and the HTTP status is still 201. No 400 is returned; the rejection is reported in the response body, not the status code. Clients must validate client-side; never trust that a 2xx response means the rating was applied. Always inspect added.statuses[] (or not_found) to confirm.
Read side
No separate read is needed during sync. Every item from GET /sync/all-items already carries user_rating and user_rated_at. GET /sync/ratings returns those same watchlist rows, keyed by media type — call it only when rated_at moved in GET /sync/activities, or to have the server filter by score:
Each item carries the standard watchlist record (status, episode counts, dates) plus user_rating (int 1-10 or null) and user_rated_at (ISO-8601 UTC or null).
To filter by score, use GET /sync/ratings/:type/:rating. For public catalog ratings (the community average + IMDb/MAL score for any title, no token required), the rating data is in the per-title detail endpoints — GET /movies/:id, GET /tv/:id, GET /anime/:id — under the ratings field. Resolve external IDs first via GET /redirect.
Removing a rating
Use POST /sync/ratings/remove with the same body shape minus the rating field (the value is ignored on remove). Removing the rating does not remove the item from the user’s watchlist — only the score is cleared.
Rate alongside a watch event
If you’re recording a watch event and want to attach a rating in the same call, use POST /sync/history — it accepts a rating field per item. One round-trip instead of two.
Sync guide — full walkthrough
Two-phase model (initial pull -> activities-checked delta loop), date_from semantics, deletion reconciliation, edge cases, and reference implementations in Node and Python.
Authorizations
Preferred form: your client_id as a URL query parameter on every request. Self-describing in logs and curl commands. See Headers and required parameters.
A user access_token, sent as Authorization: Bearer .... Required for endpoints that read or modify the user's library, scrobble session, ratings, settings, or playbacks. Every flow returns the same kind of token. See Set up authentication.
Headers
Descriptive identifier for your app, ideally name/version. Examples: PlexMediaServer/1.43.1.10540, kodi-simkl/0.9.2, MyApp/2.4.1 (https://myapp.com).
Query Parameters
Your client_id from your Simkl developer settings. Required on every request.
Short, lowercase identifier for your app (e.g. plex-scrobbler, kodi-bridge). Helps Simkl identify which apps are using the API.
Your app's current version (e.g. 1.0, 2.4.1). Helps Simkl debug issues you report.
Body
Request body for adding/updating ratings. Each item must include rating (1–10 integer). To unset a rating without re-rating, use POST /sync/ratings/remove instead. Items go under movies[], shows[], or anime[] — Simkl resolves anime titles correctly under either shows[] or anime[], so match the field to your data type when known.
Response
OK
Response from POST /sync/ratings.