API
The endpoints
Ask for somewhere to put a broadcast. Creates nothing and analyses nothing — it hands back a path and a resumable upload session.
Body
| Field | Type | Required | Notes |
|---|---|---|---|
filename | string | yes | Reduced to a safe basename. Only the name is used, never a path. |
sizeBytes | number | yes | The exact size. Checked against your plan now — including anything you have already uploaded and not yet analysed — and against the object itself when you start the analysis. |
Answers
201 { path, sessionUri, expiresAt }. Keep `path` — it is what you name to start the analysis.
| Status | error | When |
|---|---|---|
| 400 | — | filename is missing, or sizeBytes is not a positive number. |
| 413 | file-too-large | The file is larger than a single file may be on your plan. |
| 409 | period-bytes-exhausted | It would not fit in what your plan allows this month. Uploads you have not analysed count toward that, so clean them up or analyse them. |
| 503 | — | Uploads are unavailable because the deployment has no cloud credentials. |
Send the bytes, straight to Google Cloud Storage. This one does not go to KAIROS at all, and takes no KAIROS key — the session URI is the credential.
Answers
200 or 201 when the last chunk lands. 308 after every earlier chunk, carrying a `Range` header.
| Status | error | When |
|---|---|---|
| 308 | — | Normal. More bytes wanted — read the `Range` header for how much was actually kept. |
| 404 | — | The session has expired or was cancelled. Ask for a new one and start again. |
Analyse an object you have uploaded. This is what creates the broadcast and queues the work.
Body
| Field | Type | Required | Notes |
|---|---|---|---|
path | string | yes | The `path` from POST /api/uploads, exactly as it was given. |
title | string | yes | What you will see it called. Trimmed at 300 characters. |
domain | 'sport' | 'news' | 'auto' | yes | `news` also covers talks and podcasts: bulletins, radio shows, talking-head formats. `auto` lets the analyser classify it. **This cannot be changed afterwards** — the pipeline it selects is the one that runs. |
Answers
201 { assetId, status, sizeBytes, container }. Keep `assetId`: progress and the timeline are both under it.
| Status | error | When |
|---|---|---|
| 400 | — | The path is not one this workspace can analyse, or the title is missing. |
| 400 | domain-required | No domain was given. It is required, and there is no default. |
| 400 | domain-not-in-plan | Your plan does not carry the sport pipeline. `auto` needs it too, because the answer may be sport. |
| 400 | mime-not-allowed | The container is not a video type. In practice the 415 below fires first. |
| 409 | — | There is no object at that path, or that object has already been analysed. |
| 413 | file-too-large | The object is larger than a single file may be on your plan. |
| 409 | period-bytes-exhausted | Your plan’s bytes for this month are spent. |
| 409 | lifetime-minutes-exhausted | Your plan’s lifetime minutes are spent. |
| 409 | monthly-minutes-exhausted | Your plan’s minutes for this month are spent. |
| 415 | — | The first bytes are not a video container. The object is deleted, and nothing is created or charged. |
Where one analysis has got to, and whether the machine running it is still alive. Poll this.
Answers
200 { phase, generation, heartbeatAgeSeconds, cancelRequested, startedAt, uploadedBytes }. See the phases below.
| Status | error | When |
|---|---|---|
| 404 | — | No such broadcast in your workspace. Not yours and not existing are one answer. |
The same answer for every analysis still in flight, in one call. Use it instead of polling per broadcast when you have several running.
Answers
200 { "<assetId>": { phase, heartbeatAgeSeconds, cancelRequested } , … }, up to 50.
The finished analysis: segments with their start, end, kind and description, their key moments, and the highlights found.
Query
| Parameter | Type | Notes |
|---|---|---|
offset | number | First segment to return. Default 0. |
limit | number | How many. Default 50, capped at 200. |
Answers
200 { id, title, domain, durationSeconds, total, returned, offset, segments, keyMoments }.
| Status | error | When |
|---|---|---|
| 404 | — | No such broadcast in your workspace. |
| 409 | — | It has not been analysed yet. Poll progress until the phase is `done`. |
The timeline file exactly as the analysis wrote it — `sport-timeline.json` or `news-timeline.json` — before any edits made in the editor. Sent as a download.
Answers
200, the file itself, with Content-Disposition: attachment.
| Status | error | When |
|---|---|---|
| 404 | — | No such broadcast in your workspace. |
| 409 | — | It has not been analysed yet. Poll progress until the phase is `done`. |
Ask for a running analysis to stop. Intent, not an instant stop — the machine notices on its next check-in, up to 30 seconds later.
Answers
200 { ok, cancelRequested }.
| Status | error | When |
|---|---|---|
| 404 | — | No such broadcast, or it has no analysis to cancel. |
| 409 | — | That analysis has already finished. |
Delete a broadcast and its bytes. A broadcast that was analysed keeps counting toward your lifetime minutes — deleting is not a refund.
Answers
200 { ok }.
| Status | error | When |
|---|---|---|
| 404 | — | No such broadcast in your workspace. |
Is KAIROS up and can it still reach its database. No credential needed, and it says nothing about your workspace.
Answers
200 { ok: true, database: "up", checkedAt }, or 503 with database: "down".
| Status | error | When |
|---|---|---|
| 503 | — | KAIROS is up but cannot reach its database. Nothing will progress until this clears. |
Branch on the code in error, not on the sentence beside it. The codes above are the contract and will not change under you. The wording is written for people and does change.