---
title: "Ask a video a question"
method: POST
path: "/v1/watch_video"
tags: ["Video"]
---

# Ask a video a question

`POST /v1/watch_video`

## Request

- Base URL: `https://api.tryplayhead.com`
- URL: `https://api.tryplayhead.com/v1/watch_video`
- Auth: HTTP bearer

The endpoint everything else is built on. Ask a question about a video and get the answer in words, with the second of every moment it names.

Omit `question` and the answer covers the complete video, second zero to the end.

The answer carries a `session_id`. Pass it with the next question about the same video and that question reads what was already found instead of watching the video again: a few hundred tokens where the first one was a few thousand, and a second rather than a minute.

A first question takes 30 to 90 seconds, because nobody has looked at the video yet. Every question after it is short.

## Request body

- AskRequest: A question about a video. Name the video with `url` or `upload_id` on the first question, then carry the `session_id` that came back.
  - `url` string: A platform link, a direct media URL, or an `upl_…` id from an upload. Omit it when you pass a `session_id`.
  - `upload_id` string: The id returned by POST /v1/uploads.
  - `session_id` string: The conversation about one video, from an earlier answer. It is what makes a follow-up cheap.
  - `question` string: What you want to know. Omit it for what happens across the complete video.
  - `context` string[]: What you already know and the video cannot show: what the person is building, and what they asked. Plain sentences. It costs almost nothing and the answer is better for it.
  - `window` object: The part of the recording to read, in seconds from the start of the file. Omit it for the whole video. Only these seconds are fetched, decoded, transcribed and read, so a question about three minutes of a two hour podcast costs three minutes.
    - `from` number, required
    - `to` number, required
  - `region` number[]: The part of the picture to read, as [x0, y0, x1, y1] in fractions of the frame. Use it with `window` for a follow-up about one corner of one moment: `window` says when, `region` says where. [0.5, 0, 1, 0.5] is the top right quarter. Fractions rather than pixels, so the same question works on a landscape recording and a vertical one.
  - `instructions` string: How the answer should read. Replaces our own wording rules.
  - `schema` object: A JSON Schema. The answer then comes back in `value`, in that shape, and a field the video cannot fill is null with its reason in `unanswered`.
  - `rewatch` boolean: Watch the whole video again and pay for it again. Only after an answer stated the price.
  - `idempotency_key` string: Replaying the same key returns the first answer rather than charging twice.

## Response `200`

The answer, in words.

- AskResult
  - `session_id` string: Pass this with the next question about the same video.
  - `answer` string: The reading, in words, with the second of every moment it names.
  - `value` object, nullable: Present when a `schema` was passed.
  - `moments` object[]: Present only beside `value`. Every action the reading wrote, with its second, because an object holds only the seconds its schema asked for. At most 300, spread across the whole video.
    - `t` number
    - `label` string
  - `unanswered` object[]: What the question asked for and the video does not show. Named rather than guessed at.
    - `field` string
    - `reason` string
  - `unresolved` object[]: The stretches the reading could not resolve, and what to send to resolve them: `from` and `to` go back as `window`, `region` goes back as `region`. `region` is null where nothing was measured near those seconds, because a corner invented for it would point the second look at the wrong quarter of the frame. Asking again costs the seconds you name, not the video.
    - `from` number
    - `to` number
    - `reason` string
    - `region` number[], nullable
  - `cached` boolean: True when this exact question had been answered before. It then costs nothing.
  - `seen_at` number[]: The seconds this answer was read from.
  - `credits_charged` number
  - `out_of_credits` boolean: True when this answer cost more than the balance held. You were charged what was left, and the next reading is refused until you add credits.
  - `ms` integer: Wall-clock milliseconds.

## Other responses

- `400`: The request cannot be run as written. A malformed `schema` is refused here, before any work and with no charge.
- `401`: Missing, malformed or expired credential.
- `402`: Out of credits. Buying more is a different action, not a retry.
- `403`: Authenticated, but this credential may not do this. A `session_id` belonging to another organization answers here.
- `422`: The video could not be fetched: private, geo-blocked, deleted, or behind a login. Upload the file instead.
- `429`: Rate limited, or too many jobs at once for this plan.

---

[API](https://skmtc.dev/tryplayhead/apis/playhead-api.md) · [All operations](https://skmtc.dev/tryplayhead/apis/playhead-api/llms.txt) · [OpenAPI document](https://skmtc.dev/tryplayhead/apis/playhead-api/revisions/21dfb775b852?raw)
