Guides .md
For AI assistants
This page is a brief for an AI coding agent wiring up the FlickList API. It's structured for fast scanning, not a narrative walkthrough.
Machine-readable surfaces#
/dev/llms.txtindexes every page on this wiki, one line each. Use it to decide what to fetch instead of crawling the whole site.- Every page under
/devhas a raw Markdown twin at the same URL with.mdappended. Fetch/dev/catalog.mdinstead of parsing rendered HTML. - The full OpenAPI 3.1 spec lives at
/openapi/v3.yaml. Generate a client from it directly instead of reconstructing request shapes from prose.
Authentication, in five lines#
- Two credential types exist: a bearer token from the device-code flow, and an API key.
- An API key works as
Authorization: Bearer <key>or as anapi_keyquery parameter. - API keys carry
readand/orwritescopes. Every/sync/*GET needsread; sync mutations and every/scrobble/*call needwrite. - Catalog reads need a credential of either kind, with no additional scope requirement.
- A handful of endpoints work with no credential at all: community lists, list search, list tags, a user's public lists, a public list's own items, and the global calendar (
GET /calendar/shows/{start}/{days}). The personal calendar needsread.
| Surface | Credential | Scope |
|---|---|---|
| Catalog reads | required | none |
/sync/* reads |
required | read |
/sync/* writes, /scrobble/* |
required | write |
| Public list reads | optional | none |
Contract subtleties you must not violate#
ids.fldbis present on every object and never changes. Treat it as the stable join key, nottmdborimdb.{ "ids": { "fldb": "flm_c61f0a84", "tmdb": 550, "imdb": "tt0137523" } }The
idsobject gains new keys over time. Ignore any key you don't recognize instead of rejecting the response or failing validation on it.media_type: "tv"andmedia_type: "show"are the same value on write requests. Accept both; don't normalize one away or reject either.When writing multiple identifiers for one item, resolution precedence is
fldb>tmdb>imdb>tvdb. Send whichever ones you have; the API doesn't require a single identifier.A
not_foundarray in a batch response lists items that didn't resolve. It is not an error, and the request still returns200.{ "not_found": [{ "ids": { "imdb": "tt9999999" } }] }The API is additive-only. New fields appear on existing objects without a version bump, and existing fields are never renamed or removed. Parse defensively and don't assume today's field list is final.
On a
429, read theRetry-Afterheader and wait that many seconds before retrying. Don't retry immediately, and don't invent your own backoff schedule.There's no separate heartbeat call for scrobbling. Re-POST
scrobble/startwith updated progress to report ongoing playback. It's an upsert, not a new session each time, and it's also how you resolve a stale session from an earlier one.scrobble/stopauto-marks an item watched at 90% progress or more, provided the session also cleared a minimum watch-time floor. Don't wait for 100% before treating a session as finished.A scrobble target without a TMDB-linked catalog item returns
400. Resolve against the catalog before you sendscrobble/start.Unmarking watched history hides the event. It never deletes underlying account data, so don't build irreversible-delete assumptions on top of it.
When adding history, always send an explicit
watched_atand reuse the same value on retries. History writes are idempotent per item and timestamp (retried duplicates land in the response'sexistingcount); omittingwatched_atmakes a retried request record a second play.Error responses are always
{ "error": "..." }. Check the status code first; don't pattern-match on the message string, since its wording isn't part of the contract.Rate limiting is 1,000 requests per hour per credential. Poll
GET /sync/last_activitiesbefore re-fetching a collection instead of re-fetching it on a fixed timer.
When the spec and this page disagree#
Treat /openapi/v3.yaml as the source of truth for exact request and response shapes. This page exists to flag behavior that trips up integrations even after reading the spec, not to restate every field in it.