Every error from the API is JSON with a stable code and a human-readable
English error:
{ "error": "Unauthorized: Session has been revoked.", "code": "session_revoked" }
Branch on code, never on the text. The text may change; codes will not.
New codes may be added, so treat an unknown code by its HTTP status.
code |
HTTP | Meaning | What the app does |
|---|---|---|---|
invalid_api_key |
403 | The gateway's key was revoked or disabled (an unknown key from an unregistered gateway gets the HTML 404 of section 2) |
"Service unavailable". It is a gateway problem, not the user's |
method_not_allowed |
405 | Wrong HTTP method | Fix the client |
missing_credentials |
400 | login without username or password |
Ask again |
invalid_credentials |
401 | Wrong username or password | Ask again |
account_disabled |
403 | Line disabled or banned | Show it. Keep the session token |
account_expired |
403 | Line expired | Show it. Keep the session token: after the reseller renews the line, refresh-session works again |
restreamer_not_allowed |
403 | Restreamer lines cannot use this API | Show it |
wrong_reseller |
403 | The reseller's key no longer serves this session's line | Show it. Keep the session token |
access_denied |
403 | Access refused from where the device is (temporary IP block, reseller's domain lock) | Show it. Keep the session token and try again later |
token_missing |
401 | No Authorization: Bearer header |
Fix the client |
session_expired |
401 | The session token expired but can still be renewed | Call refresh-session once, then retry |
session_invalid |
401 | The session token is not valid here (malformed, from another key, or too old to renew) | Sign in / pair again |
session_revoked |
401 | This device was signed out or unlinked, or logout-all was used |
Sign in / pair again |
credentials_changed |
401 | The line's username or password changed (also seen some time after a logout-all) |
Sign in / pair again |
account_not_found |
401 | The line no longer exists | Sign in / pair again |
invalid_parameter |
400 | A parameter is missing or out of range | Fix the request |
not_in_package |
403 | The content exists but this line's package does not include it | "Not included in your plan" |
not_found |
404 | No movie or series with that id | Treat as gone |
unknown_endpoint |
404 | No such action | Fix the client |
rate_limited |
429 | Too many history-update reports for the line, or more than one diagnostics batch a minute from the device (Retry-After) |
history-update: drop that report, do not retry it. diagnostics: keep the records and send them after Retry-After |
temporarily_unavailable |
503 | Try again shortly | Retry with backoff |
Not every failure is JSON. The 404 HTML page of section 2 (gateway not
recognized), your gateway's own rate limit (429/503) and server errors
(5xx) come without code. When there is no code, go by the status, and
treat 429 and 5xx as temporary: retry with backoff, and never sign the
user out because of them. A 429 with code rate_limited is the panel's
own limit on history and diagnostics reports (above).
The streaming nodes answer with bare HTTP status codes, not JSON (section 7.4).
API responses carry Cache-Control: no-store (except the channel map of
playback-routes, which has its own max-age and ETag): do not cache them
in shared caches.