NetraFlow
API Reference

Frames

The storyboard in a job's results, and how to fetch its sheets.

A brands or objects job with return_proof on (the default) comes back with a storyboard in results: frames we analyzed, tiled into JPEG sheets, so you can show where a brand or an object was. On a brands job that is up to 150 frames spread across the video.

GET /v1/frames/:key

Returns one storyboard sheet.

curl https://api.netraflow.com/v1/frames/storyboard/job_abc123/sheet_0.jpg \
  -H "X-Api-Key: sk_live_your_key_here" \
  -o sheet_0.jpg
HTTP/1.1 200 OK
Content-Type: image/jpeg
Cache-Control: private, max-age=31536000, immutable

<JPEG bytes>
  • Where the key comes from. Each entry of results.storyboard.sheets is already the whole path, such as /v1/frames/storyboard/job_abc123/sheet_0.jpg. Request it as it is, after https://api.netraflow.com, and don't URL-encode its slashes.
  • Auth. The same X-Api-Key header as every request. The key needs the jobs:read scope.
  • Response. HTTP 200 with the image itself, Content-Type: image/jpeg.
  • Caching. A sheet never changes once it is written, so it is sent with Cache-Control: private, max-age=31536000, immutable: keep it as long as you like.
  • How long it lasts. As long as the job's results: a completed job keeps its storyboard until the workspace is deleted. A failed or cancelled job has none.
  • Errors. NOT_FOUND (404) when the key is not a sheet of a job in your workspace, or the sheet does not exist. The body has the same { error, meta } shape as every other error.

Storyboard

"storyboard": {
  "version": 2,
  "interval_ms": 1000,
  "timestamps_ms": [500, 1500, 2500, 3500],
  "tile": { "w": 580, "h": 326 },
  "grid": { "cols": 8, "rows": 8 },
  "count": 4,
  "duration_ms": 4000,
  "sheets": ["/v1/frames/storyboard/job_abc123/sheet_0.jpg"]
}
PropTypeDescription
version1 | 2How a tile relates to its timestamp. 1: the tile covers from its own timestamp to the next tile's. 2: the timestamp is the middle of the sampled interval, so the tile spans halfway to each neighbour.
interval_msintegerTypical spacing between tiles, in milliseconds.
timestamps_msinteger[] (optional)True timestamp of each tile in milliseconds, ascending, one per tile. Frames are analyzed non-uniformly, so prefer this over interval_ms when present. Absent only on older results, where tile k sits at k × interval_ms.
tile{ w: integer, h: integer }Size of one tile in pixels. The longer side is 580 and the shape follows the video's.
grid{ cols: integer, rows: integer }Tiles per row and rows per sheet (8 × 8 today). Tile k is on sheet floor(k / (cols × rows)), row-major within it.
countintegerTotal tiles across all sheets. The last sheet can be partly empty (black).
duration_msnumberVideo duration in milliseconds.
sheetsstring[]Path of each sheet, in order, to fetch with GET /v1/frames/:key.

The storyboard is the one place the API reports milliseconds. Every other timestamp in a result is in seconds.

The tiles are plain frames with nothing drawn on them. To show where something was, find the tile nearest a detection's timestamp and draw its box over that tile yourself: brands carry theirs in frame_detections, objects in frames.

On this page