REST API v1
Throughline's external API exposes a production's graph — scenes, assets, schedule, approvals, deliveries, people, activity — to tools that live around the production rather than inside the app: pipeline scripts, reporting dashboards, delivery trackers, and similar integrations.
It is a read-mostly, write-carefully surface. The read side mirrors what crew see in the app, scoped to one production. The write side is deliberately narrow: create an asset, attach a note, decide an approval — because nothing in Throughline moves without an accountable person (or a key acting on one's behalf) behind it.
Base URL
https://throughline-backend-idkf.onrender.com/api/v1
This host is provisional for the pilot. All requests and JSON bodies use Content-Type: application/json.
Authentication
Every request carries a Throughline access key as a bearer token:
Authorization: Bearer tl_your_access_key_here
A key is minted by a production's admin, from inside Throughline, for a specific person or integration's use — one key, one label, one production. The full token is shown once, at creation; after that only a recognizable prefix is kept. There is no cross-production surface: a key minted on one production sees that production and nothing else.
Each key carries one or both scopes:
| Scope | Grants |
|---|---|
read | Every GET endpoint below |
write | Every POST endpoint below |
Auth errors
| Status | Meaning |
|---|---|
401 | Missing or malformed Authorization header, or an unknown/revoked key |
403 | The key is valid but lacks the scope the endpoint needs |
Revoking a key from Settings takes effect immediately.
Read endpoints
All of the following require the read scope.
GET /production
The production the key belongs to, with headline counts.
curl -s https://throughline-backend-idkf.onrender.com/api/v1/production \
-H "Authorization: Bearer $TL_KEY"
{
"id": 1,
"title": "Example Production",
"logline": "One line describing the show.",
"status": "active",
"phase": "production",
"accent": "sea-glass",
"format": "single",
"stats": {
"departments": 12,
"open_approvals": 3,
"deliveries_in_flight": 2,
"scenes": 44,
"nodes": 210
}
}
An episodic production also carries "format": "episodic" and a season_number. accent is a key into a small curated palette, never a raw color — never document one you didn't see returned.
GET /departments
Every department on the production.
curl -s https://throughline-backend-idkf.onrender.com/api/v1/departments \
-H "Authorization: Bearer $TL_KEY"
[
{
"id": 7,
"slug": "props",
"name": "Props",
"cluster": "art",
"phases": ["prep", "production"],
"mission": "Every object an actor touches.",
"key_roles": ["Props Master", "Props Assistant"],
"privacy": "open",
"unveiled": true
}
]
GET /departments/{slug}
One department, with its people, its registry, and an asset count.
curl -s https://throughline-backend-idkf.onrender.com/api/v1/departments/props \
-H "Authorization: Bearer $TL_KEY"
{
"id": 7,
"slug": "props",
"name": "Props",
"cluster": "art",
"registry": {},
"people": [
{ "id": 14, "name": "<person name>", "role": "Props Master", "is_hod": true }
],
"assets": 38
}
GET /scenes
The current script breakdown, in script order.
curl -s https://throughline-backend-idkf.onrender.com/api/v1/scenes \
-H "Authorization: Bearer $TL_KEY"
[
{
"node_id": 41,
"number": "12",
"slugline": "EXT. LIGHTHOUSE GALLERY - NIGHT",
"synopsis": "One line describing the scene.",
"status": "active",
"revision_color": "Blue",
"elements": { "props": ["Brass compass"], "cast": ["KEEPER"] }
}
]
On an episodic production, every scene also carries episode_id and episode_code (e.g. "S2E7"); a single-output production's response omits both keys entirely rather than sending them as null.
GET /assets
Non-scene graph nodes — props, locations, characters, shots, and so on. Every optional query parameter narrows the list:
| Parameter | Meaning |
|---|---|
department | Department slug, e.g. props |
kind | Node kind, e.g. asset, character, location |
status | One of planned, active, blocked, done |
curl -s "https://throughline-backend-idkf.onrender.com/api/v1/assets?department=props&status=active" \
-H "Authorization: Bearer $TL_KEY"
[
{
"node_id": 112,
"label": "Brass compass",
"kind": "asset",
"status": "active",
"department": "props",
"versions": 3,
"updated_at": "2026-07-09T17:42:11Z"
}
]
Rows are logistical — labels, statuses, version counts — never media.
GET /assets/{node_id}
One asset in full. Released versions carry media; anything not yet released comes back as a locked stub, the same rule the app applies to anyone outside the owning department.
curl -s https://throughline-backend-idkf.onrender.com/api/v1/assets/112 \
-H "Authorization: Bearer $TL_KEY"
GET /schedule
Shoot days with their scenes.
curl -s https://throughline-backend-idkf.onrender.com/api/v1/schedule \
-H "Authorization: Bearer $TL_KEY"
[
{
"id": 3,
"day_number": 3,
"date": "2026-07-10",
"general_call": "06:30",
"status": "scheduled",
"scenes": [
{ "node_id": 41, "number": "12", "slugline": "EXT. LIGHTHOUSE GALLERY - NIGHT" }
]
}
]
episode_id is a repeatable query parameter (?episode_id=1&episode_id=2) on episodic productions. It marks matching strips rather than dropping anything from the response, and has no effect on a single-output production.
GET /deliveries
Every delivery — inter-department and external — with its gating approval, if it has one.
curl -s https://throughline-backend-idkf.onrender.com/api/v1/deliveries \
-H "Authorization: Bearer $TL_KEY"
GET /approvals
Approval chains. Filter with ?status=pending|approved|changes_requested|rejected.
curl -s "https://throughline-backend-idkf.onrender.com/api/v1/approvals?status=pending" \
-H "Authorization: Bearer $TL_KEY"
GET /script-changes
Detected script-draft differences awaiting a decision. Defaults to ?status=pending; also accepts approved, dismissed, or all. On an episodic production, ?episode_id= scopes to one episode and ?all_episodes=true widens to every episode at once.
GET /activity
The production activity feed, newest first. ?limit= defaults to 50, capped at 200.
GET /people
The crew directory — name, role, department, and HOD/admin flags. No contact details.
GET /jobs
Recent generation jobs (image/video renders). ?limit= as for /activity.
Write endpoints
All of the following require the write scope.
POST /assets
Create a new graph node.
curl -s -X POST https://throughline-backend-idkf.onrender.com/api/v1/assets \
-H "Authorization: Bearer $TL_KEY" \
-H "Content-Type: application/json" \
-d '{"label": "Hero lantern", "kind": "asset", "department": "props", "status": "active"}'
label is required. kind defaults to "asset"; scenes cannot be created here — they come from script breakdown. status must be one of planned, active, blocked, done.
POST /assets/{node_id}/notes
Attach a note to an asset. It lands on the asset's newest version if it has one, or as an activity entry if it doesn't — either way it's on the record.
curl -s -X POST https://throughline-backend-idkf.onrender.com/api/v1/assets/112/notes \
-H "Authorization: Bearer $TL_KEY" \
-H "Content-Type: application/json" \
-d '{"text": "Approved for hero use.", "author": "Editorial pipeline"}'
text is required. author is free text attributed to your integration if omitted.
POST /approvals/{approval_id}/decide
Advance the current step of an approval chain.
curl -s -X POST https://throughline-backend-idkf.onrender.com/api/v1/approvals/12/decide \
-H "Authorization: Bearer $TL_KEY" \
-H "Content-Type: application/json" \
-d '{"decision": "approved", "decided_by": "Dana Whitfield", "note": "Signed off via external review tool."}'
decision must be "approved" or "changes". decided_by names the person making the call, and a write-scoped key is not a signature — if decided_by isn't the person whose step it actually is, the request is refused rather than silently recorded under someone else's name. Decision-mode approvals refuse an anonymous decision outright; multi-step chains permit omitting it.
Not yet in v1
Budget and purchase-order data, and the assistant's chat interface, are part of the in-app surface today and are not yet exposed to external API keys. If your integration needs either, talk to your Throughline contact — the read/write model above is where they'd land.
Versioning
The path prefix is /api/v1. Changes within it are additive only — new endpoints, new optional fields, new query parameters. Nothing is renamed or removed inside v1; a breaking change would ship as /api/v2.
Timestamps are UTC ISO-8601. IDs are integers, stable within a production. Unknown fields may appear in any response at any time — parse leniently.