> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.beatapi.io/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.beatapi.io/_mcp/server.

# Video Analysis

> Analyze an uploaded MP4 or MOV with standard or deep timestamp-aware multimodal reasoning.

`POST https://api.beatapi.io/v1/video-analysis/tasks`

Analyze an uploaded MP4 or MOV with standard or deep timestamp-aware multimodal reasoning.

## Authorization

`Authorization`   `string`   **required**

Send your BeatAPI API key as a Bearer token. Create one on the [Dashboard](https://beatapi.io/dashboard).

```
Authorization: Bearer <BEATAPI_API_KEY>
```

Keep permanent API keys on trusted servers. `Content-Type: application/json` is required for the request body. `Idempotency-Key` is optional when the endpoint exposes it and is recommended for safe retries with the exact same body.

## Request body

`video_url`   `string`   **required**

BeatAPI-hosted MP4 or MOV input URL returned by POST /v1/files for the current account. Maximum verified duration is 600 seconds.

**Format:** `uri`

---

`prompt`   `string`   **required**

Analysis instruction. Ask for timestamped output when temporal precision matters.

**Length:** 1 to 12000 characters

---

`analysis_depth`   `enum<string>`   **optional**

Standard is the default low-cost route; deep uses the higher-reasoning route.

**Available options:** `standard`, `deep`  \
**Default:** `"standard"`

---

`max_output_tokens`   `integer`   **optional**

Requested answer budget. Provider-reported output usage can include hidden reasoning tokens above this value; BeatAPI records the variance for audit and settles actual reported usage within the task reservation.

**Default:** `2048`  \
**Range:** 256 to 8192

## Response

A successful request returns HTTP `201`.

```json
{
  "data": {
    "id": "task_va8K2qA",
    "object": "task",
    "task_kind": "workflow",
    "capability_id": "video-analysis",
    "capability_version": 1,
    "workflow": "video-analysis",
    "status": "queued",
    "stage": "queued",
    "created_at": 1787385600,
    "updated_at": 1787385600,
    "completed_at": null,
    "output": null,
    "usage": {
      "credits_reserved": 0.01,
      "credits_charged": 0.01,
      "billable_duration_seconds": 60,
      "credits_settled": 0,
      "credits_refunded": 0
    },
    "request_id": "req_va123",
    "error_code": null,
    "error_message": null
  }
}
```

## Analysis depth and billing

`standard` is the default route for summaries, segmentation, timestamps, and extraction. Use `deep` when the task needs denser reasoning about motion, contact, continuity, or ambiguous events.

BeatAPI accepts only MP4 or MOV inputs of up to 600 seconds uploaded by the same account through `POST /v1/files`. The verified track duration determines a conservative input-token reservation; the completed task settles from validated provider-reported input and output tokens.

Current unit prices live on the [Video Analysis API page](https://www.beatapi.io/video-analysis-api) and `/pricing`. This page is the request contract only.

The create endpoint returns a queued task after reserving the maximum request envelope. Any unused reservation is returned when validated actual token usage is settled. Each completed task is rounded up to the nearest \$0.01 because the shared USD balance settles in cents.

The model samples ordinary video at roughly 1 FPS by default. Fast actions and dense cuts can be missed, so ask for timestamps and use narrower clips when frame-level motion matters.

## Next step

Read completed analysis from `data.output.text` and token usage from `data.output.usage`. If the task is queued for capacity, poll `GET /v1/tasks/{task_id}` until it succeeds or fails.

## Errors

| Status | Meaning                                                                                                                                                                                                                                                                                    |
| ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `400`  | Malformed JSON or a field, value or combination this endpoint does not accept (`bad_request`; the message names the field), or input refused by moderation (`content_policy_violation`). Not retryable unchanged.                                                                          |
| `401`  | No API key (`missing_api_key`), or a key that is wrong, expired, disabled or exhausted (`invalid_api_key`; the message says which). Send it as `Authorization: Bearer <key>`; the key works with or without the `sk-` prefix. Not retryable.                                               |
| `402`  | Insufficient balance (`insufficient_credits`). The account balance is zero or below the price of this request. Top up, then send it again; not retryable before that.                                                                                                                      |
| `403`  | The key or account is not permitted to make this call (`forbidden`), for example a model that is not available on free credit (a top-up unlocks it), a request from outside the key's IP allowlist, or a model outside the key's group. Not retryable.                                     |
| `409`  | The `Idempotency-Key` was already used with a different request body or path within 24 hours, or the first request with it is still running (`idempotency_conflict`). Not retryable unchanged.                                                                                             |
| `429`  | Too many requests (`rate_limit_exceeded`, including the free-model limits). Retryable after `Retry-After` seconds (also `error.retry_after_seconds`).                                                                                                                                      |
| `500`  | Unexpected internal error (`internal_error`). Retryable; keep `request_id` for support if it persists.                                                                                                                                                                                     |
| `503`  | The request could not be completed (`processing_unavailable`, `processing_timeout`, `processing_failed` or `result_transfer_failed`). Nothing was charged. Retryable with backoff; a 503 carries no `Retry-After` header and no `retry_after_seconds`. BeatAPI does not answer 502 or 504. |