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.txt indexes every page on this wiki, one line each. Use it to decide what to fetch instead of crawling the whole site.
  • Every page under /dev has a raw Markdown twin at the same URL with .md appended. Fetch /dev/catalog.md instead 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 an api_key query parameter.
  • API keys carry read and/or write scopes. Every /sync/* GET needs read; sync mutations and every /scrobble/* call need write.
  • 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 needs read.
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.fldb is present on every object and never changes. Treat it as the stable join key, not tmdb or imdb.

    { "ids": { "fldb": "flm_c61f0a84", "tmdb": 550, "imdb": "tt0137523" } }
  • The ids object 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" and media_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_found array in a batch response lists items that didn't resolve. It is not an error, and the request still returns 200.

    { "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 the Retry-After header 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/start with 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/stop auto-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 send scrobble/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_at and reuse the same value on retries. History writes are idempotent per item and timestamp (retried duplicates land in the response's existing count); omitting watched_at makes 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_activities before 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.