Every API here is available over the APIs.io API and to AI agents over MCP.
openapi: 3.2.0
info:
title: BeatAPI Developer Tasks API
version: 1.0.0-launch
license:
name: BeatAPI Terms of Service
url: https://beatapi.io/terms-of-service
description: 'BeatAPI provides one API key for public text models, image generation, video generation,
video analysis, Effects, asynchronous video workflows, and short-lived Realtime Video Sessions.
For asynchronous operations, create a task, poll the shared task endpoint or receive webhook events,
and read hosted output URLs from `output.media`. For Realtime, create a Session on a trusted server
with your Bearer API key and pass only the returned short-lived `client_secret` to the browser.
Customer balances and usage are USD-denominated. Compatibility fields such
as `credit_balance` and `credits_reserved` remain in the API; 1 Credit = $1 USD.
## 5 minute Quick Start
1. Set your base URL to `https://api.beatapi.io`.
2. Create an API key in Dashboard → API Keys
and send it as
`Authorization: Bearer `.
USD balance top-ups are available from
Dashboard → Billing.
3. Use public HTTPS URLs for input media. If your files are local, upload
them with `POST /v1/files` first.
4. Create a workflow task.
5. Poll every 5-10 seconds until `status` is `succeeded` or `failed`.
6. Add webhooks later if you do not want to poll.
```bash
read -rsp "BeatAPI API key: " BEATAPI_API_KEY && echo
export BEATAPI_API_KEY
curl https://api.beatapi.io/v1/workflows
curl https://api.beatapi.io/v1/music-video/tasks \
-H "Authorization: Bearer $BEATAPI_API_KEY" \
-H "Content-Type: application/json" \
-d ''{
"images": ["https://cdn.beatapi.io/samples/neon-singer.png"],
"audio_url": "https://cdn.beatapi.io/samples/neon-singer-preview.mp3",
"prompt": "Neon rooftop performance with cinematic light trails.",
"language": "en",
"resolution": "720p"
}''
curl https://api.beatapi.io/v1/tasks/task_8K2qA \
-H "Authorization: Bearer $BEATAPI_API_KEY"
```
## How tasks work
A task starts as `queued` or `processing`. Keep polling
`GET /v1/tasks/{task_id}` every 5-10 seconds with a little jitter. Stop when
the task is `succeeded` or `failed`.
- `queued`: accepted and waiting for platform capacity.
- `processing`: generation is running.
- `storyboard_ready`: Music Video storyboard shots are available.
- `requires_action`: choose storyboard shots and call compose.
- `editing`: a storyboard shot edit is running.
- `composing`: selected storyboard shots are being composed.
- `succeeded`: output is ready in `output.media[]`.
- `failed`: no usable output was produced. Inspect `error_code`,
`error_message`, and `usage` for the final task result.
The current 10 minute processing window is an operational timeout for launch
testing, not a completion SLA.
## Inputs and limits
Public workflow inputs must use HTTPS URLs that are reachable from the
public internet. Localhost, private network URLs, and data URLs are rejected.
Use `POST /v1/files` for local images, audio, subtitles, or Motion Control reference videos.
Each verified new user account starts with a $2 welcome balance that never expires and
1 active processing concurrency. Lifetime paid purchases unlock higher limits:
$10+ = 2, $100+ = 5, $1,000+ = 10, $5,000+ = 15, and $20,000+ = 30.
`GET /v1/usage` returns current usage totals, concurrency limit, and active
processing task count. Active concurrency measures tasks that are currently
using BeatAPI processing resources. storyboard_ready and requires_action
tasks can have settled USD usage but do not count toward active processing
concurrency.
## Webhooks are optional
Polling is the simplest integration path. If you add webhooks, BeatAPI sends
`task.succeeded` and `task.failed` events. Webhook delivery failures do not
change task status; polling remains the source of truth.'
servers:
- url: https://api.beatapi.io
tags:
- name: Tasks
description: Poll task status and read output URLs.
paths:
/v1/tasks/{task_id}:
get:
operationId: getTask
tags:
- Tasks
x-apidog-folder: Reference/Task Status
summary: Poll task status
security:
- BearerAuth: []
description: 'Wait `poll_after_seconds` (present while the task runs; 5 for images, 8 for video and Effects, 10 for workflows and data tasks) between calls.
A failed task is still HTTP `200`: read `status: "failed"`, `error_code`, `error_message` and `retryable` in the body. A task that does not exist for this account answers `404 not_found`.'
parameters:
- in: path
name: task_id
required: true
schema:
type: string
example: task_8K2qA
responses:
'200':
description: Task status
content:
application/json:
schema:
$ref: '#/components/schemas/TaskResponse'
examples:
queued:
summary: Accepted and waiting
value:
data:
id: task_8K2qA
object: task
task_kind: workflow
capability_id: music-video
capability_version: 1
workflow: music-video
status: queued
stage: queued
storyboard:
shots: []
created_at: 1782210000
updated_at: 1782210000
completed_at: null
output: null
usage:
credits_reserved: 1.5
credits_charged: 1.5
billable_duration_seconds: 15
credits_settled: 0
credits_refunded: 0
request_id: req_abc123
error_code: null
error_message: null
succeeded:
summary: Storyboard ready with shot metadata
value:
data:
id: task_8K2qA
object: task
task_kind: workflow
capability_id: music-video
capability_version: 1
workflow: music-video
status: storyboard_ready
stage: storyboard_ready
created_at: 1782210000
updated_at: 1782210300
completed_at: null
storyboard:
shots:
- id: shot_xxx
index: 0
status: succeeded
duration_seconds: 5
prompt: Opening lyric shot.
lyric_text: Intro
created_at: 1782210000
updated_at: 1782210300
output: null
usage:
credits_reserved: 1.5
credits_charged: 1.5
billable_duration_seconds: 15
credits_settled: 1.5
credits_refunded: 0
request_id: req_abc123
error_code: null
error_message: null
failed:
summary: Failed with refunded charge
value:
data:
id: task_8K2qA
object: task
task_kind: workflow
capability_id: music-video
capability_version: 1
workflow: music-video
status: failed
stage: failed
storyboard:
shots: []
created_at: 1782210000
updated_at: 1782210600
completed_at: 1782210600
output: null
usage:
credits_reserved: 1.5
credits_charged: 0
billable_duration_seconds: 15
credits_settled: 0
credits_refunded: 1.5
request_id: req_abc123
error_code: processing_timeout
error_message: The task did not complete within the processing window and was stopped. Retry; a task that fails this way is refunded.
retryable: true
'401':
$ref: '#/components/responses/Unauthorized'
'404':
description: Task not found for this account (`not_found`).
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'429':
$ref: '#/components/responses/RateLimited'
components:
schemas:
TaskUsage:
type: object
required:
- credits_reserved
- credits_settled
- credits_refunded
- credits_charged
properties:
credits_reserved:
type: number
format: double
multipleOf: 0.01
description: USD amount reserved for this task. The compatibility field name is retained; 1 Credit equals $1 USD.
credits_charged:
type: number
format: double
multipleOf: 0.01
description: USD amount charged. `0` on a failed task, because the reserved amount was returned.
billable_duration_seconds:
type: integer
description: Server-detected or request-declared billable duration used for USD calculation.
credits_settled:
type: number
format: double
multipleOf: 0.01
description: USD amount settled after successful work.
credits_refunded:
type: number
format: double
multipleOf: 0.01
description: USD amount returned after a failed task. On a failed task `credits_reserved` is the amount held at create, `credits_charged` and `credits_settled` are `0`, and `credits_refunded` is the amount returned.
TaskStatus:
type: string
enum:
- queued
- processing
- storyboard_ready
- requires_action
- editing
- composing
- succeeded
- failed
Error:
type: object
required:
- error
properties:
error:
type: object
description: Structured BeatAPI error. Use `code` (or `retryable`) for program logic and retain `request_id` for support.
required:
- code
- message
- request_id
properties:
code:
type: string
description: 'Stable machine-readable error code. `unauthorized` is the legacy name for a 401; since 2026-09-29 a 401 is `missing_api_key` or `invalid_api_key`, but `unauthorized` may still appear. Treat it like `invalid_api_key`. `result_expired` is returned only by `POST /v1/capabilities/run` with `operation: "result"`.'
enum:
- bad_request
- missing_api_key
- invalid_api_key
- unauthorized
- forbidden
- not_found
- insufficient_credits
- idempotency_conflict
- rate_limit_exceeded
- content_policy_violation
- processing_unavailable
- processing_failed
- processing_timeout
- result_transfer_failed
- result_expired
- not_implemented
- realtime_disabled
- realtime_capacity_unavailable
- realtime_session_expired
- origin_not_allowed
- invalid_client_secret
- transport_not_allowed
- internal_error
message:
type: string
description: English sentence that states the cause; for `bad_request` it names the field. Written for people and logs, not for parsing.
retryable:
type: boolean
description: Whether making the same call again could succeed. Present for every code in the public table; it may be absent only for a code outside the table. True for rate_limit_exceeded, internal_error, processing_unavailable, processing_timeout, processing_failed, result_transfer_failed and realtime_capacity_unavailable. False for a request, key or balance that must change first (bad_request, content_policy_violation, missing_api_key, invalid_api_key, unauthorized, insufficient_credits, forbidden, not_found, idempotency_conflict, result_expired, not_implemented, realtime_disabled and the other realtime credential codes).
request_id:
type: string
description: Correlation ID to retain for BeatAPI support.
retry_after_seconds:
type: integer
description: Seconds to wait before retrying. Sent only with a 429 `rate_limit_exceeded`, and the same value is sent in the `Retry-After` header. No other code carries it.
docs:
type: string
format: uri
description: The public Skill page that says what to do about an error. Present on errors answered by the capability endpoints (`/v1/capabilities/search`, `/v1/capabilities/inspect`, `/v1/capabilities/run`); absent on every other endpoint.
Task:
type: object
required:
- id
- object
- task_kind
- capability_id
- capability_version
- status
- stage
- created_at
- updated_at
- completed_at
- output
- usage
- request_id
- error_code
- error_message
properties:
id:
type: string
description: Stable BeatAPI task ID used for polling and support.
example: task_8K2qA
object:
type: string
enum:
- task
description: Object discriminator; always `task`.
task_kind:
type: string
enum:
- workflow
- effect
- image
- video
- data
description: Public task family that determines which capability fields are present. `data` is a data capability run as a task (`data:web.research`), polled through `POST /v1/capabilities/run`.
capability_id:
type: string
description: Stable BeatAPI workflow, Effect, generation model, or data capability ID (such as `web.research`) selected when the task was accepted.
capability_version:
type: integer
description: Always `1`.
workflow:
type: string
enum:
- music-video
- ecommerce-video
- video-analysis
description: Present for workflow tasks; identifies the selected BeatAPI workflow.
example: music-video
effect_id:
type: string
description: Present for Effect tasks; stable selected Effect ID.
example: video-muscle-max
effect_version:
type: integer
description: Present for Effect tasks; immutable Effect version used for processing.
example: 1
media_type:
type: string
enum:
- image
- video
description: Present when task_kind is image or video.
model:
type: string
description: Stable BeatAPI model alias. It is independent from internal execution routing.
status:
$ref: '#/components/schemas/TaskStatus'
description: Current task lifecycle status. Stop polling at `succeeded` or `failed`; Music Video can also require manual action.
stage:
$ref: '#/components/schemas/TaskStatus'
description: Always repeats `status`. Kept for compatibility; read `status`.
storyboard:
$ref: '#/components/schemas/Storyboard'
description: Music Video storyboard metadata when available.
created_at:
type: integer
description: Unix timestamp when BeatAPI accepted the task.
updated_at:
type: integer
description: Unix timestamp of the latest task update.
completed_at:
type:
- integer
- 'null'
description: Terminal Unix timestamp, or null while work is in progress.
poll_after_seconds:
type: integer
description: 'Present while the task is running: how long to wait before the next status call (5 for images, 8 for video and Effects, 10 for workflows and data tasks). Follow it instead of a fixed interval. Absent on a terminal task.'
example: 8
typical_seconds:
type: object
description: 'Present while the task is running, when enough recent finishes exist: how long this task''s model recently took from accepted to succeeded, measured on this gateway. Past `p90` with no change the task is running long; there is no ETA beyond that.'
required:
- p50
- p90
- samples
- window
properties:
p50:
type: integer
description: Median seconds.
p90:
type: integer
description: Ninetieth-percentile seconds.
samples:
type: integer
description: Finished tasks the figures rest on.
window:
type: string
description: The window measured, such as `7d`.
output:
description: Output is null until the task succeeds.
oneOf:
- type: 'null'
- type: object
required:
- media
- r2_url
properties:
media:
type: array
description: BeatAPI-hosted result assets.
items:
type: object
required:
- type
- url
- mime_type
properties:
type:
type: string
enum:
- image
- video
description: Result asset type.
url:
type: string
format: uri
description: BeatAPI-hosted HTTPS result URL.
mime_type:
type: string
description: Result asset MIME type.
examples:
- video/mp4
- image/png
- image/jpeg
- image/webp
r2_url:
type: string
format: uri
deprecated: true
description: Deprecated — read media[0].url. The primary asset's URL again (the video, else the first image), the same value as that media[].url, kept only for clients that read one URL.
- type: object
required:
- text
- usage
- finish_reason
properties:
text:
type: string
description: Completed video analysis text.
usage:
type: object
description: Measured token usage used for final USD settlement.
required:
- input_tokens
- output_tokens
- total_tokens
properties:
input_tokens:
type: integer
minimum: 0
description: Tokens consumed by the prompt and video input.
output_tokens:
type: integer
minimum: 0
description: Tokens consumed by visible output and model reasoning.
total_tokens:
type: integer
minimum: 0
description: Total measured input and output tokens.
finish_reason:
type:
- string
- 'null'
description: Why the model stopped generating.
- type: object
description: 'A data task''s result: the capability''s own result object, such as `web.research` with `research_notes` and `sources` (in a view: `items`).'
required:
- object
additionalProperties: true
properties:
object:
type: string
description: The result type, such as `web.research`.
usage:
$ref: '#/components/schemas/TaskUsage'
description: USD reservation, settlement, refund, and optional billable duration for this task.
request_id:
type: string
description: Correlation ID to retain for logs and BeatAPI support.
example: req_abc123
error_code:
type:
- string
- 'null'
description: Machine-readable terminal failure code, or null when no task failure is recorded.
example: processing_timeout
error_message:
type:
- string
- 'null'
description: Human-readable terminal failure detail, or null when no task failure is recorded.
retryable:
type: boolean
description: 'Present on a failed task: whether resubmitting could succeed. True when the task failed on our side or timed out (a failed task is not charged); false when it was refused for content or bad input. Same code-to-retryable rule as the error envelope.'
example: true
TaskResponse:
type: object
required:
- data
properties:
data:
$ref: '#/components/schemas/Task'
description: Accepted or current BeatAPI task state.
StoryboardShot:
type: object
required:
- id
- index
- status
- created_at
- updated_at
properties:
id:
type: string
description: BeatAPI shot id. Use this id for media retrieval, edit, and compose operations.
example: shot_xxx
index:
type: integer
description: Zero-based shot order in the storyboard.
example: 0
status:
$ref: '#/components/schemas/TaskStatus'
description: Current lifecycle state for this storyboard shot.
duration_seconds:
type: integer
description: Planned or generated shot duration in seconds.
example: 5
prompt:
type: string
description: Creative instruction used to generate this shot.
example: Opening lyric shot.
lyric_text:
type: string
description: Lyric segment aligned with this shot when available.
example: Intro
media:
type: object
description: Present only after the shot media has been materialized or after a shot edit finishes.
properties:
type:
type: string
description: Hosted media type for the materialized shot.
example: video
url:
type: string
format: uri
description: BeatAPI-hosted HTTPS URL for the materialized shot.
example: https://media.beatapi.io/outputs/task_8K2qA/shots/0.mp4
mime_type:
type: string
description: MIME type of the hosted shot media.
example: video/mp4
created_at:
type: integer
description: Unix timestamp when the shot record was created.
example: 1782210000
updated_at:
type: integer
description: Unix timestamp when the shot record last changed.
example: 1782210300
Storyboard:
type: object
required:
- shots
properties:
shots:
type: array
description: Ordered Music Video storyboard shots. The array may be empty before storyboard generation completes.
items:
$ref: '#/components/schemas/StoryboardShot'
responses:
Unauthorized:
description: '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.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
error:
code: invalid_api_key
message: 'Invalid or inactive API key. Send it as Authorization: Bearer <key>; the key works with or without the sk- prefix.'
retryable: false
request_id: req_xxx
RateLimited:
description: Too many requests (`rate_limit_exceeded`, including the free-model limits). Retryable after `Retry-After` seconds (also `error.retry_after_seconds`).
headers:
Retry-After:
description: Seconds to wait before retrying the request.
schema:
type: integer
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
error:
code: rate_limit_exceeded
message: Too many polling requests. Poll every 5-10 seconds.
retryable: true
request_id: req_xxx
retry_after_seconds: 12
securitySchemes:
BearerAuth:
type: http
scheme: bearer
bearerFormat: sk_xxx
description: 'Send your API key as `Authorization: Bearer <BEATAPI_API_KEY>`.'
PersonalAccessToken:
type: http
scheme: bearer
bearerFormat: nap_xxx
description: 'Send the account''s personal access token as `Authorization: Bearer <token>`. Create it on the Dashboard''s Account security page. API keys are not accepted.'
ApiKeyHeader:
type: apiKey
in: header
name: x-api-key
description: Anthropic-compatible API key header. Use a BeatAPI API key.
GoogleApiKeyHeader:
type: apiKey
in: header
name: x-goog-api-key
description: Gemini-compatible API key header. Use a BeatAPI API key.
GoogleApiKeyQuery:
type: apiKey
in: query
name: key
description: Gemini SDK compatibility only. Prefer the x-goog-api-key header when possible.
externalDocs:
description: BeatAPI documentation
url: https://docs.beatapi.io