> ## Documentation Index
> Fetch the complete documentation index at: https://docs.overshoot.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Chat completions

> OpenAI-compatible chat completions.

Text-only requests are allowed. To reference live stream media, put
`ovs://streams/<id>?...` inside an `image_url` or `video_url` content part. Unknown
fields are accepted for SDK compatibility.

Set `stream: true` to receive `text/event-stream`. When
`stream_options.include_usage` is also `true`, the stream may include a final
usage chunk.


## Referencing a stream

The `messages[].content[]` array accepts standard OpenAI content parts plus two Overshoot-specific URL shapes:

* **`image_url`** — points at a single frame of a stream.
* **`video_url`** — points at a window of frames.

Both wrap an `ovs://` reference of the form:

```
ovs://streams/{stream_id}?<query>
```

The `ovs://` scheme is a reference identifier — the server parses it to pull out `stream_id` and the query, then resolves frames internally. It is not a fetchable URL. The `<query>` is what selects the moment you want. Different keys for single frames vs. windows.

### Image URL — query params

For `type: "image_url"`. **Exactly one** anchor is required.

| Param          | Type     | Required        | Description                                                                                                                                                 |
| -------------- | -------- | --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `frame_index`  | int      | Anchor (one of) | Lifetime-indexed frame number. Negative = relative to live edge; `-1` is the most recent frame.                                                             |
| `timestamp_ms` | int      | Anchor (one of) | Absolute stream-clock ms since `first_frame_at_ms`.                                                                                                         |
| `offset_ms`    | int      | Anchor (one of) | Offset relative to "now" (live edge at request time). Negative = past.                                                                                      |
| `tolerance_ms` | int (>0) | Optional        | How far the resolver may snap to find a frame. **Default `100`. Ignored when `frame_index` is set.**                                                        |
| `direction`    | enum     | Optional        | `nearest` \| `forward` \| `backward`. Resolution preference when no exact match within tolerance. **Default `nearest`. Ignored when `frame_index` is set.** |

```json theme={null}
{ "type": "image_url",
  "image_url": { "url": "ovs://streams/{id}?frame_index=-1" }
}
```

### Video URL — query params

For `type: "video_url"`. Requires **one start anchor**, accepts **one optional end anchor** (defaults to the live edge), plus an optional `max_fps`.

| Param                | Type       | Required              | Description                                                                                                   |
| -------------------- | ---------- | --------------------- | ------------------------------------------------------------------------------------------------------------- |
| `start_frame_index`  | int        | Start anchor (one of) | Lifetime index where the segment begins.                                                                      |
| `start_timestamp_ms` | int        | Start anchor (one of) | Absolute stream-clock ms where the segment begins.                                                            |
| `start_offset_ms`    | int        | Start anchor (one of) | Offset from now where the segment begins. Negative = past (e.g. `-5000` is "5s ago").                         |
| `end_frame_index`    | int        | End anchor (optional) | Lifetime index where the segment ends.                                                                        |
| `end_timestamp_ms`   | int        | End anchor (optional) | Absolute stream-clock ms where the segment ends.                                                              |
| `end_offset_ms`      | int        | End anchor (optional) | Offset from now where the segment ends.                                                                       |
| `max_fps`            | float (>0) | Optional              | Cap on frames per second sampled from the segment. **Default `1.0`.** Halving `max_fps` halves visual tokens. |

Start and end anchor types may differ — `start_offset_ms=-30000&end_frame_index=523` is valid.

```json theme={null}
{ "type": "video_url",
  "video_url": { "url": "ovs://streams/{id}?start_offset_ms=-5000&max_fps=2" }
}
```

### Resolution rules

* **Negative `frame_index` / `offset_ms`** are evaluated against `last_frame_index` / now at request time. The same URL can resolve to different frames on consecutive calls.
* **Old frames clamp.** A `frame_index` (or `start_frame_index`) older than `first_available_frame_index` clamps up to the oldest available frame. Request **succeeds**, possibly on a different frame than asked.
* **Future frames fail.** A `frame_index` newer than `last_frame_index` returns `422`. There is no "wait until that frame arrives".
* **Duplicate query keys** (`?frame_index=1&frame_index=2`) → `422`.
* **Setting more than one anchor** of the same kind (e.g. two `start_*`, or `frame_index` + `timestamp_ms`) → `422`.

### Example — single-frame question

```json theme={null}
{
  "model": "Qwen/Qwen3.6-27B-FP8",
  "messages": [{
    "role": "user",
    "content": [
      { "type": "text", "text": "What is the person doing right now?" },
      { "type": "image_url",
        "image_url": { "url": "ovs://streams/{id}?frame_index=-1" }
      }
    ]
  }]
}
```

### Example — last-N-seconds question

```json theme={null}
{
  "model": "google/gemma-4-26B-A4B-it",
  "messages": [{
    "role": "user",
    "content": [
      { "type": "text", "text": "Did anything happen in the last 5 seconds?" },
      { "type": "video_url",
        "video_url": { "url": "ovs://streams/{id}?start_offset_ms=-5000" }
      }
    ]
  }]
}
```

For more usage patterns, see the [Chat Completion guide](/chat-completion).


## OpenAPI

````yaml POST /chat/completions
openapi: 3.0.3
info:
  title: Overshoot API
  version: 1.0.0-beta
  description: >
    Real-time video understanding API. Create a live video stream, push frames
    over

    WebRTC (LiveKit), then ask a vision-language model questions about what's
    happening

    using an OpenAI-compatible chat completions endpoint.


    Billing endpoints are mounted on the same host under `/billing`.
servers:
  - url: https://api.overshoot.ai/v1beta
security:
  - bearerAuth: []
tags:
  - name: Streams
    description: Create, inspect, keep alive, and delete live video streams.
  - name: Models
    description: List available vision-language models.
  - name: Chat
    description: Ask models questions about a stream's frames.
  - name: Billing
    description: Pricing, prepaid balance, and checkout.
paths:
  /chat/completions:
    post:
      tags:
        - Chat
      summary: Chat completions
      description: >
        OpenAI-compatible chat completions.


        Text-only requests are allowed. To reference live stream media, put

        `ovs://streams/<id>?...` inside an `image_url` or `video_url` content
        part. Unknown

        fields are accepted for SDK compatibility.


        Set `stream: true` to receive `text/event-stream`. When

        `stream_options.include_usage` is also `true`, the stream may include a
        final

        usage chunk.
      operationId: chatCompletions
      parameters:
        - $ref: '#/components/parameters/RegionHeader'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ChatCompletionRequest'
            examples:
              text_only:
                summary: Plain text completion
                value:
                  model: google/gemma-4-26B-A4B-it
                  messages:
                    - role: user
                      content: 'Reply with exactly: ok'
                  max_completion_tokens: 8
              stream_video_qa:
                summary: Ask about the last 5 seconds of a stream
                value:
                  model: google/gemma-4-26B-A4B-it
                  messages:
                    - role: user
                      content:
                        - type: text
                          text: What does it say on my shirt?
                        - type: video_url
                          video_url:
                            url: >-
                              ovs://streams/cc3e3f79-c5c4-4d1c-985e-028b42030569?start_offset_ms=-5000
              streaming:
                summary: Server-sent events with usage chunk
                value:
                  model: google/gemma-4-26B-A4B-it
                  messages:
                    - role: user
                      content: 'Reply with exactly: ok'
                  stream: true
                  stream_options:
                    include_usage: true
      responses:
        '200':
          description: >
            Completion response. JSON by default; if the request sets `stream:
            true`,

            the response is an OpenAI-style SSE stream (`text/event-stream`)
            terminated by

            `data: [DONE]`.
          headers:
            X-Overshoot-Region:
              $ref: '#/components/headers/RegionResponseHeader'
            x-ratelimit-limit:
              $ref: '#/components/headers/RateLimitLimit'
            x-ratelimit-remaining:
              $ref: '#/components/headers/RateLimitRemaining'
            x-ratelimit-reset:
              $ref: '#/components/headers/RateLimitReset'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ChatCompletionResponse'
            text/event-stream:
              schema:
                $ref: '#/components/schemas/ChatCompletionStreamChunk'
        '400':
          description: >-
            Invalid stream URL/query, invalid segment, unsupported model/media
            combination, or provider safety block.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ChatError'
        '401':
          description: Missing or invalid bearer API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '402':
          description: Billing denied inference.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ChatError'
        '403':
          description: Valid key, but the requested resource belongs to another user.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ChatError'
        '404':
          description: >-
            Stream missing, stream deleted, lease expired, no retained frames
            matched, or pricing/model resource not found.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ChatError'
        '409':
          description: >-
            Wrong region, multiple stream regions, or requested lifetime frame
            index has not arrived yet.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ChatError'
        '410':
          description: Requested exact lifetime frame index has been evicted.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ChatError'
        '422':
          description: Request validation failed.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationError'
        '429':
          description: >-
            Per-user inference rate limit exceeded, or the model provider
            rate-limited the request.
          headers:
            x-ratelimit-limit:
              $ref: '#/components/headers/RateLimitLimit'
            x-ratelimit-remaining:
              $ref: '#/components/headers/RateLimitRemaining'
            x-ratelimit-reset:
              $ref: '#/components/headers/RateLimitReset'
            retry-after:
              $ref: '#/components/headers/RetryAfter'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ChatError'
        '500':
          description: Internal processing error.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ChatError'
        '502':
          description: >-
            Model provider request failed, unauthorized, or returned a server
            error.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ChatError'
        '503':
          description: Service temporarily unavailable.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '504':
          description: Model provider request timed out.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ChatError'
components:
  parameters:
    RegionHeader:
      name: X-Overshoot-Region
      in: header
      required: false
      schema:
        type: string
        enum:
          - us-west1
          - us-central1
      description: >
        Optional hint to route the request to the region that owns the stream.
        If the

        request reaches the wrong region the API returns `409` with a
        `region_error` body.
  schemas:
    ChatCompletionRequest:
      type: object
      description: >
        OpenAI-compatible. Permissive — unknown fields are accepted for SDK
        compatibility.

        To reference a stream's frames, include `video_url` or `image_url`
        content parts

        whose URL uses the `ovs://streams/{stream_id}?...` reference scheme.
      additionalProperties: true
      properties:
        model:
          type: string
          description: >-
            Model identifier from `GET /models`. Must be `ready` at request
            time.
          example: google/gemma-4-26B-A4B-it
        messages:
          type: array
          items:
            $ref: '#/components/schemas/ChatMessage'
        max_completion_tokens:
          type: integer
          nullable: true
          description: Optional output-token cap. OpenAI's preferred name.
        max_tokens:
          type: integer
          nullable: true
          description: Legacy alias for `max_completion_tokens`.
        response_format:
          type: object
          additionalProperties: true
          description: Used when supported by the selected model/provider.
        stream:
          type: boolean
          default: false
          description: When `true`, the response is a server-sent event stream.
        stream_options:
          type: object
          description: 'Only meaningful when `stream: true`.'
          properties:
            include_usage:
              type: boolean
              description: When `true`, the stream may include a final usage chunk.
        tools:
          type: array
          items:
            type: object
            additionalProperties: true
          description: OpenAI-style tool definitions.
        tool_choice:
          oneOf:
            - type: string
            - type: object
              additionalProperties: true
          description: OpenAI-style tool choice.
        parallel_tool_calls:
          type: boolean
          description: OpenAI-style parallel tool-call setting.
        thread_id:
          type: string
          nullable: true
          description: >
            Optional key for prompt-cache reuse across related requests in the
            same user

            conversation and model. See the Prompt cache guide.
      required:
        - model
        - messages
    ChatCompletionResponse:
      type: object
      properties:
        id:
          type: string
        object:
          type: string
          default: chat.completion
        created:
          type: integer
        model:
          type: string
        choices:
          type: array
          items:
            $ref: '#/components/schemas/ChatCompletionChoice'
        usage:
          $ref: '#/components/schemas/ChatCompletionUsage'
        overshoot:
          $ref: '#/components/schemas/OvershootMetadata'
      required:
        - id
        - object
        - created
        - model
        - choices
    ChatCompletionStreamChunk:
      type: object
      description: >
        A single `data:` payload in an SSE response. The stream is terminated by

        `data: [DONE]`. The final chunk (when `stream_options.include_usage:
        true`)

        carries `usage` and `overshoot.cache`.
      properties:
        choices:
          type: array
          items:
            type: object
            properties:
              delta:
                type: object
                properties:
                  role:
                    type: string
                  content:
                    type: string
                  tool_calls:
                    type: array
                    items:
                      type: object
                      additionalProperties: true
              finish_reason:
                type: string
                nullable: true
        usage:
          allOf:
            - $ref: '#/components/schemas/ChatCompletionUsage'
          nullable: true
        overshoot:
          $ref: '#/components/schemas/OvershootMetadata'
    ChatError:
      type: object
      description: >
        Error envelope used by `/chat/completions`. The inner `error.code`
        identifies the

        specific failure (see the Errors guide for the full list of codes such
        as

        `stream_not_found`, `frame_evicted`, `upstream_http_<status>`, etc.).
      properties:
        detail:
          type: object
          properties:
            error:
              type: object
              properties:
                message:
                  type: string
                  example: 'Stream not found: <stream_id>'
                type:
                  type: string
                  enum:
                    - stream_error
                    - validation_error
                    - provider_error
                    - upstream_error
                    - billing_error
                    - rate_limit_error
                    - internal_error
                  example: stream_error
                code:
                  type: string
                  description: >
                    Specific failure code. Known values include:

                    `stream_url_invalid`, `query_param_invalid`,
                    `stream_not_found`,

                    `stream_unauthorized`, `segment_empty`, `segment_invalid`,

                    `frame_evicted`, `frame_not_yet_produced`,
                    `model_unavailable`,

                    `model_video_unsupported`, `provider_safety_block`,
                    `billing_denied`,

                    `upstream_http_<status>`, `upstream_timeout`,

                    `upstream_request_failed`.
                  example: stream_not_found
                upstream:
                  $ref: '#/components/schemas/UpstreamError'
              required:
                - message
                - type
                - code
          required:
            - error
    Error:
      type: object
      description: Standard error body used by stream-lifecycle and billing endpoints.
      properties:
        detail:
          type: string
      required:
        - detail
    ValidationError:
      type: object
      description: Validation failure shape used by chat completions and billing.
      properties:
        error:
          type: string
          example: validation_error
        message:
          type: string
          example: Request validation failed
        details:
          type: array
          items:
            type: object
            properties:
              loc:
                type: array
                items:
                  type: string
              msg:
                type: string
              type:
                type: string
    ChatMessage:
      type: object
      properties:
        role:
          type: string
          enum:
            - system
            - user
            - assistant
            - tool
        content:
          oneOf:
            - type: string
            - type: array
              items:
                $ref: '#/components/schemas/ContentPart'
      required:
        - role
        - content
    ChatCompletionChoice:
      type: object
      properties:
        index:
          type: integer
        message:
          type: object
          properties:
            role:
              type: string
              example: assistant
            content:
              type: string
              nullable: true
            tool_calls:
              type: array
              items:
                type: object
                additionalProperties: true
              description: OpenAI-style tool calls. Present when the model emits any.
          required:
            - role
        finish_reason:
          type: string
          nullable: true
          enum:
            - stop
            - length
            - tool_calls
            - content_filter
      required:
        - index
        - message
    ChatCompletionUsage:
      type: object
      properties:
        prompt_tokens:
          type: integer
          description: >-
            Tokens in the request — text plus visual tokens from any frames or
            segments.
        completion_tokens:
          type: integer
        total_tokens:
          type: integer
    OvershootMetadata:
      type: object
      description: Overshoot-specific response metadata. Observability only.
      properties:
        cache:
          type: object
          properties:
            thread_id:
              type: string
              nullable: true
              description: The `thread_id` you supplied, or `null`.
            cache_hit:
              type: boolean
              description: '`true` when cached prompt tokens were reported.'
            cached_input_tokens:
              type: integer
              description: Prompt tokens served from prefix cache.
    UpstreamError:
      type: object
      nullable: true
      description: >-
        Present on `upstream_*` codes. Preserves the provider status and a
        bounded response body when available.
      properties:
        provider:
          type: string
          example: google
        status:
          type: integer
          example: 400
        body:
          type: object
          additionalProperties: true
          description: Bounded provider response body.
        rate_limits:
          type: object
          nullable: true
          additionalProperties: true
    ContentPart:
      oneOf:
        - $ref: '#/components/schemas/TextPart'
        - $ref: '#/components/schemas/ImageUrlPart'
        - $ref: '#/components/schemas/VideoUrlPart'
    TextPart:
      type: object
      properties:
        type:
          type: string
          enum:
            - text
        text:
          type: string
      required:
        - type
        - text
    ImageUrlPart:
      type: object
      properties:
        type:
          type: string
          enum:
            - image_url
        image_url:
          type: object
          properties:
            url:
              type: string
              description: >
                Either an HTTPS image URL, a `data:` URL, or an Overshoot stream
                frame

                reference like `ovs://streams/{stream_id}?frame_index=-1`. The
                `ovs://`

                URI is a reference identifier the server parses, not a fetchable
                URL.

                Required query: exactly one of `frame_index`, `timestamp_ms`, or

                `offset_ms`.
          required:
            - url
      required:
        - type
        - image_url
    VideoUrlPart:
      type: object
      properties:
        type:
          type: string
          enum:
            - video_url
        video_url:
          type: object
          properties:
            url:
              type: string
              description: >
                HTTPS video URL, `data:` URL, or Overshoot stream segment
                reference like

                `ovs://streams/{stream_id}?start_offset_ms=-5000`. Required
                query:

                exactly one `start_*` anchor. Optional end anchor (defaults to
                live edge),

                optional `max_fps` (default `1.0`).
          required:
            - url
      required:
        - type
        - video_url
  headers:
    RegionResponseHeader:
      description: The region that served this request.
      schema:
        type: string
        enum:
          - us-west1
          - us-central1
    RateLimitLimit:
      description: Current per-user request-per-second limit.
      schema:
        type: integer
    RateLimitRemaining:
      description: Remaining requests in the current second.
      schema:
        type: integer
    RateLimitReset:
      description: Epoch time when the current second window resets.
      schema:
        type: integer
    RetryAfter:
      description: Seconds to wait before retrying. Present on 429; currently `1`.
      schema:
        type: integer
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: API key (e.g. `ovs_...`)
      description: >
        Every public HTTP request requires `Authorization: Bearer <api_key>`,
        except

        `GET /models` and the public `/billing/pricing` endpoints.


        - `401` means the key is missing, unknown, or revoked.

        - `403` means the key is valid but cannot access the requested resource.

        - The publish token returned by `POST /streams` is only for publishing
        media to
          LiveKit. It does not replace the API key for HTTP calls.

````