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. To read ratings back, use GET /sync/ratings/:type/:rating — see Read side below.
Body shape
Top-level keys per media type, each carrying an array of items:
{
"movies": [
{
"rating": 8,
"ids": {
"simkl": 53536
}
}
],
"shows": [
{
"rating": 9,
"ids": {
"tmdb": "1399"
}
}
],
"anime": [
{
"rating": 10,
"ids": {
"mal": "11757"
},
"rated_at": "2026-05-15T20:00:00Z"
}
]
}
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": {
"movies": 1,
"shows": 1,
"statuses": [
{
"request": {
"rating": 8,
"ids": {
"simkl": 53536
}
},
"response": {
"status": "completed"
}
}
]
},
"not_found": {
"movies": [],
"shows": []
}
}
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
GET /sync/ratings returns every rated item across all types in one response, keyed by media type:
{
"movies": [ { ..., "user_rating": 8, "user_rated_at": "2026-05-13T..." } ],
"shows": [ { ..., "user_rating": 9, ... } ],
"anime": [ { ..., "user_rating": 10, ... } ]
}
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).
Read ratings back with 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.
OAuth 2.0 or PIN-flow access_token. Required for endpoints that read or modify the user's library, scrobble session, ratings, settings, or playbacks. See 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.