Getting started .md
Quickstart
Two ways in. If you are writing something for yourself, start with an API key and you'll make your first call in about two minutes. If you are building an app that other people will sign in to, use the device-code flow in track two.
All the JavaScript on this page uses top-level await: save it as script.mjs and run node script.mjs. Python examples run as plain python3 script.py and need the requests package.
Track one: an API key (for your own scripts)#
1. On flicklist.tv, open Settings, then Apps, and create an API key with the read scope. Keys look like fs_live_…. Treat them like passwords, and keep them out of browser code you ship.
2. Call the API. A bearer token here just means the credential rides in the Authorization header, in the form Bearer <value>:
API_KEY="fs_live_your_key_here"
curl -H "Authorization: Bearer $API_KEY" \
"https://flicklist.tv/api/v3/sync/watched/shows" | head -c 400
echo
echo "It works."const apiKey = 'fs_live_your_key_here';
const res = await fetch('https://flicklist.tv/api/v3/sync/watched/shows', {
headers: { Authorization: `Bearer ${apiKey}` }
});
const shows = await res.json();
console.log(`It works: ${shows.length} watched shows on this account.`);import requests
api_key = "fs_live_your_key_here"
shows = requests.get(
"https://flicklist.tv/api/v3/sync/watched/shows",
headers={"Authorization": f"Bearer {api_key}"},
).json()
print(f"It works: {len(shows)} watched shows on this account.")That's the whole track. Every watched show on your account, each with a full ids object. Quick scripts takes this straight into a worked example, and the API reference has every endpoint you can point this key at.
Track two: the device-code flow (for apps)#
This is how an app on a TV, a Kodi box, or a CLI signs a user in without a password form: show the person a short code, they approve it on their phone, your app polls until a token appears.
One path quirk to know before you start: the auth endpoints live at https://flicklist.tv/api/auth/…, one level above /v3. Everything else in these docs hangs off https://flicklist.tv/api/v3.
And one mechanical note: the four steps below build a single script. Each snippet reuses variables from the one before (code, then token), so append them to the same script.mjs or script.py as you go.
Step 1: request a device code#
Send your client_id. You get back a user_code to show the person and a device_code your app keeps private.
curl -X POST "https://flicklist.tv/api/auth/device/code" \
-H "Content-Type: application/json" \
-d '{"client_id": "your_client_id"}'const clientId = 'your_client_id';
const res = await fetch('https://flicklist.tv/api/auth/device/code', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ client_id: clientId })
});
const code = await res.json();
console.log(`Tell the user: enter ${code.user_code} at ${code.verification_uri}`);import requests
client_id = "your_client_id"
code = requests.post(
"https://flicklist.tv/api/auth/device/code",
json={"client_id": client_id},
).json()
print(f"Tell the user: enter {code['user_code']} at {code['verification_uri']}"){
"user_code": "A1B2C3D4",
"device_code": "b2f1c9e4-…",
"verification_uri": "https://flicklist.tv/link",
"expires_in": 900,
"interval": 5
}
Step 2: show the code#
Display user_code and tell the person to enter it at flicklist.tv/link on any signed-in device. The code pair lives for 15 minutes (expires_in).
Step 3: poll for the token#
Poll POST /auth/device/token with the device_code, waiting at least interval seconds between polls. The endpoint answers 200 for every state, including while the person has not approved yet, so check the body's error field, not the status code. While pending you get "error": "authorization_pending"; once approved you get an access_token. Two other codes can appear: access_denied (the person declined, stop polling) and expired_token (the 15-minute window lapsed, go back to step 1 for a fresh code).
DEVICE_CODE="the device_code from step 1"
INTERVAL=5 # the "interval" from step 1
while true; do
RES=$(curl -s -X POST "https://flicklist.tv/api/auth/device/token" \
-H "Content-Type: application/json" \
-d "{\"device_code\": \"$DEVICE_CODE\"}")
TOKEN=$(echo "$RES" | grep -o '"access_token":"[^"]*"' | cut -d'"' -f4)
[ -n "$TOKEN" ] && break
sleep "$INTERVAL"
done
echo "Authenticated. Token starts with: ${TOKEN:0:8}"let token = null;
while (!token) {
await new Promise((r) => setTimeout(r, code.interval * 1000));
const res = await fetch('https://flicklist.tv/api/auth/device/token', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ device_code: code.device_code })
});
const body = await res.json();
if (body.access_token) token = body.access_token;
else if (body.error !== 'authorization_pending') throw new Error(body.error);
}
console.log(`Authenticated. Token starts with: ${token.slice(0, 8)}`);import time
token = None
while token is None:
time.sleep(code["interval"])
body = requests.post(
"https://flicklist.tv/api/auth/device/token",
json={"device_code": code["device_code"]},
).json()
if "access_token" in body:
token = body["access_token"]
elif body.get("error") != "authorization_pending":
raise RuntimeError(body.get("error"))
print(f"Authenticated. Token starts with: {token[:8]}")Step 4: make your first call#
The token is good for 30 days (the response's expires_at says exactly when; rotate it with POST /auth/refresh). From here on, everything is back under /v3:
curl -H "Authorization: Bearer $TOKEN" \
"https://flicklist.tv/api/v3/me"const me = await fetch('https://flicklist.tv/api/v3/me', {
headers: { Authorization: `Bearer ${token}` }
}).then((r) => r.json());
console.log(`Signed in as ${me.username}`);me = requests.get(
"https://flicklist.tv/api/v3/me",
headers={"Authorization": f"Bearer {token}"},
).json()
print(f"Signed in as {me['username']}")Where to next#
- Scrobbling, the flagship: report playback in near real time.
- Authentication: scopes, token rotation, and both flows in full.
- The ids object: how items are identified everywhere.
- Quick scripts: the API-key track taken to a finished script.
- API reference: every endpoint, generated from the OpenAPI spec.