> ## 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.

# Create stream

> Create a new video inference stream. Returns connection details for the chosen transport.

**Workflow:** Create stream → connect video source → receive results on WebSocket → send keepalives → close when done.

**Transport options:**
- **Native** (default, recommended): Omit `source`. Response includes `livekit.url` and `livekit.token` for publishing video.
- **WebRTC**: Set `source.type: 'webrtc'` with an SDP offer. Response includes `webrtc` answer and `turn_servers`.
- **LiveKit**: Set `source.type: 'livekit'` with your room URL and token.

**Processing modes:**
- **Clip mode**: Send `target_fps`, `clip_length_seconds`, `delay_seconds` for temporal analysis (motion, actions).
- **Frame mode**: Send `interval_seconds` for static analysis (OCR, object detection).

**Limits:** 5 concurrent streams per API key. Requires credits.

## What you get

The response carries:

* **`id`** — pass this in every later URL: `/v1beta/streams/{id}/...` plus stream URLs you embed in chat completion messages.
* **`publish.url`** + **`publish.token`** — feed these to a [LiveKit client SDK](https://docs.livekit.io/reference/) to connect a video source. Any LiveKit publisher works (browser, native, server-to-server). The token is short-lived; use the one returned by `/keepalive` if your publisher reconnects later.
* **`expires_at_ms`** + **`ttl_seconds`** — the lease deadline. Call `/keepalive` before it elapses (every \~2 minutes is safe). After expiry the stream's `state` flips to `ended` and stays there.

The stream sits in `active` state immediately, even before the first frame arrives. `GET /streams/{id}` returns `last_frame_at_ms: null` until a publisher actually delivers a frame.


## OpenAPI

````yaml POST /streams
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:
  /streams:
    post:
      tags:
        - Streams
      summary: Create stream
      description: >
        Creates a live stream and returns a publish token. The current request
        body is

        empty. The retained frame history is fixed at 600 seconds.


        The publish token is scoped to this stream and grants media publish
        permissions.

        Renew it through [`/keepalive`](#tag/Streams/operation/keepaliveStream)
        before it

        expires.
      operationId: createStream
      parameters:
        - $ref: '#/components/parameters/RegionHeader'
      responses:
        '201':
          description: Stream created.
          headers:
            X-Overshoot-Region:
              $ref: '#/components/headers/RegionResponseHeader'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CreateStreamResponse'
        '401':
          description: Missing or invalid API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: API key has no associated user.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '409':
          description: Wrong region.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RegionError'
        '503':
          description: Stream creation temporarily unavailable.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
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.
  headers:
    RegionResponseHeader:
      description: The region that served this request.
      schema:
        type: string
        enum:
          - us-west1
          - us-central1
  schemas:
    CreateStreamResponse:
      type: object
      properties:
        id:
          type: string
          format: uuid
          description: Unique stream identifier. Use this in every subsequent stream URL.
        state:
          type: string
          enum:
            - active
          description: Always `active` for a freshly created stream.
        publish:
          $ref: '#/components/schemas/PublishInfo'
        expires_at_ms:
          type: integer
          description: >-
            Wall-clock Unix ms when the lease will expire if not renewed via
            `/keepalive`.
        ttl_seconds:
          type: integer
          example: 300
          description: Lease TTL in seconds. Currently `300` for all streams.
      required:
        - id
        - state
        - publish
        - expires_at_ms
        - ttl_seconds
    Error:
      type: object
      description: Standard error body used by stream-lifecycle and billing endpoints.
      properties:
        detail:
          type: string
      required:
        - detail
    RegionError:
      type: object
      description: Returned on `409` when the request reaches the wrong region.
      properties:
        detail:
          type: object
          properties:
            error:
              type: string
              example: region_error
            expected_region:
              type: string
              example: us-west1
            requested_region:
              type: string
              nullable: true
              example: us-central1
    PublishInfo:
      type: object
      description: WebRTC publish target. Connect with the LiveKit client SDK.
      properties:
        type:
          type: string
          enum:
            - livekit
          default: livekit
        url:
          type: string
          description: LiveKit room URL (`wss://...`).
        token:
          type: string
          description: Short-lived publish JWT for the LiveKit client.
      required:
        - type
        - url
        - token
  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.

````