Every API here is available over the APIs.io API and to AI agents over MCP.
openapi: 3.2.0
info:
title: BeatAPI Developer Usage 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: Usage
description: Inspect task totals and account concurrency.
paths:
/v1/usage:
get:
operationId: getUsage
tags:
- Usage
x-apidog-folder: Reference/Usage & Limits
summary: Get account usage and concurrency
description: The account's balance, spend and breakdowns. Without `period` the counts cover the whole account history; with `period` they cover the window ending now, and the reply repeats `period`, `since` and `until` so a caller can tell which figure it got. `credit_balance` and `concurrency` are always current. A query parameter other than `period`, or a period outside the set, is refused with `400` rather than ignored. Authenticate with an API key or the account's personal access token (`usage:read`); both read the same account-wide summary.
security:
- BearerAuth: []
- PersonalAccessToken: []
parameters:
- in: query
name: period
required: false
schema:
type: string
enum:
- 24h
- 7d
- 30d
- all
default: all
description: The window the counts and breakdowns cover, ending now. `all` (the default) is the whole account history.
responses:
'200':
description: Usage summary
content:
application/json:
schema:
$ref: '#/components/schemas/UsageResponse'
example:
data:
object: usage
period: all
credit_balance: 21.6
total_tasks: 12
credits_settled: 14.4
credits_refunded: 9
concurrency:
limit: 2
active: 1
realtime:
sessions: 3
credits: 1.8
active: 1
by_workflow:
- workflow: music-video
tasks: 8
credits_settled: 9.6
- workflow: ecommerce-video
tasks: 4
credits_settled: 4.8
by_capability:
- task_kind: image
capability_id: seedream-5-pro
tasks: 3
credits_settled: 0.42
- task_kind: video
capability_id: veo-3.1
tasks: 2
credits_settled: 14
by_model:
- media_type: image
model: seedream-5-pro
tasks: 3
credits_settled: 0.42
by_api_key:
- api_key_id: key_abc123
title: Production
key_prefix: sk_live_abcd
tasks: 12
credits_settled: 14.4
'400':
$ref: '#/components/responses/BadRequest'
'401':
$ref: '#/components/responses/Unauthorized'
/v1/account/usage/records:
get:
operationId: listUsageRecords
tags:
- Usage
x-apidog-folder: Reference/Usage & Limits
summary: List usage records
description: The account's billed requests, newest first, one record per task or text request, with the amount paid in USD. Authenticate with the account's personal access token; an API key is refused with `403`. A query parameter this endpoint does not know is refused with `400` rather than ignored.
security:
- PersonalAccessToken: []
parameters:
- in: query
name: start
required: false
schema:
type: string
example: '2026-10-01T00:00:00Z'
description: Earliest `created_at` to include, as unix seconds or an RFC 3339 timestamp.
- in: query
name: end
required: false
schema:
type: string
example: '2026-11-01T00:00:00Z'
description: Exclusive upper bound for `created_at`, as unix seconds or an RFC 3339 timestamp.
- in: query
name: model
required: false
schema:
type: string
example: seedream-5-pro
description: Public model ID.
- in: query
name: type
required: false
schema:
type: string
enum:
- text
- image
- video
- workflow
- data
- realtime
- other
description: Record type.
- in: query
name: api_key_id
required: false
schema:
type: string
example: '1287'
description: Numeric ID of the API key that paid, as in `api_key.id`.
- in: query
name: limit
required: false
schema:
type: integer
minimum: 1
maximum: 100
default: 20
description: Records per page.
- in: query
name: cursor
required: false
schema:
type: string
description: The `next_cursor` of the previous page.
responses:
'200':
description: One page of usage records
content:
application/json:
schema:
$ref: '#/components/schemas/UsageRecordListResponse'
example:
data:
object: list
data:
- object: usage_record
id: 20261029041512987654321b3f9a1c2eQm8Rt4Lw
type: text
model: deepseek-v4.1-flash
request_id: 20261029041512987654321b3f9a1c2eQm8Rt4Lw
api_key:
id: '1287'
title: production
key_prefix: sk-Ab3d
status: succeeded
created_at: 1793247312
currency: USD
credits_charged: 0.002468
credits_refunded: 0
usage:
input_tokens: 1200
output_tokens: 350
cached_tokens: 1024
has_more: true
next_cursor: eyJ0IjoxNzkzMjQ3MzEyLCJpIjo5ODc2NTQzMn0
'400':
$ref: '#/components/responses/BadRequest'
'401':
$ref: '#/components/responses/PersonalAccessTokenUnauthorized'
'403':
$ref: '#/components/responses/PersonalAccessTokenForbidden'
/v1/account/usage/records/{id}:
get:
operationId: getUsageRecord
tags:
- Usage
x-apidog-folder: Reference/Usage & Limits
summary: Get a usage record
description: One usage record by task ID, or by the request ID a response carried in `X-BeatAPI-Request-Id` (`chatcmpl-` also works). A task's amounts match `GET /v1/tasks/{task_id}`, including any settlement. Authenticate with the account's personal access token.
security:
- PersonalAccessToken: []
parameters:
- in: path
name: id
required: true
schema:
type: string
example: task_7Qm2Xc9LpR4vT8sKa1Nf6YbH3eWdJ0uZ
description: Task ID or request ID.
responses:
'200':
description: The usage record
content:
application/json:
schema:
$ref: '#/components/schemas/UsageRecordResponse'
example:
data:
object: usage_record
id: task_7Qm2Xc9LpR4vT8sKa1Nf6YbH3eWdJ0uZ
type: image
model: seedream-5-pro
task_id: task_7Qm2Xc9LpR4vT8sKa1Nf6YbH3eWdJ0uZ
request_id: 202610290330051234567893f9a1c2eXy7Kp2Qd
api_key:
id: '1287'
title: production
key_prefix: sk-Ab3d
status: succeeded
created_at: 1793244605
currency: USD
credits_charged: 0.06
credits_refunded: 0
usage:
images: 2
'401':
$ref: '#/components/responses/PersonalAccessTokenUnauthorized'
'403':
$ref: '#/components/responses/PersonalAccessTokenForbidden'
'404':
description: No usage record with this ID on the account (`not_found`), including another account's ID.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
components:
schemas:
UsageRecordResponse:
type: object
required:
- data
properties:
data:
$ref: '#/components/schemas/UsageRecord'
UsageRecord:
type: object
required:
- object
- id
- type
- model
- api_key
- status
- created_at
- currency
- credits_charged
- credits_refunded
- usage
properties:
object:
type: string
enum:
- usage_record
id:
type: string
description: The task ID for a task, otherwise the request ID.
type:
type: string
enum:
- text
- image
- video
- workflow
- data
- realtime
- other
model:
type: string
description: Public model ID.
task_id:
type: string
description: Present for tasks.
request_id:
type: string
description: Request ID of the call that created the record, when known.
api_key:
type:
- object
- 'null'
description: The API key that paid; `null` for Dashboard playground use.
required:
- id
- title
properties:
id:
type: string
title:
type: string
key_prefix:
type: string
description: The first four characters of the key.
status:
type: string
enum:
- queued
- processing
- succeeded
- failed
- refunded
description: '`refunded` means the whole charge came back.'
created_at:
type: integer
description: Unix seconds.
currency:
type: string
enum:
- USD
credits_charged:
type: number
format: double
description: What the account paid in USD, after discounts and any settlement; up to six decimal places.
credits_refunded:
type: number
format: double
description: USD returned to the balance.
usage:
type: object
description: Billable quantities; each member appears only for the record types it describes.
properties:
input_tokens:
type: integer
output_tokens:
type: integer
cached_tokens:
type: integer
cache_write_tokens:
type: integer
images:
type: integer
seconds:
type: integer
resolution:
type: string
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.
UsageResponse:
type: object
required:
- data
properties:
data:
$ref: '#/components/schemas/Usage'
UsageRecordListResponse:
type: object
required:
- data
properties:
data:
type: object
required:
- object
- data
- has_more
properties:
object:
type: string
enum:
- list
data:
type: array
items:
$ref: '#/components/schemas/UsageRecord'
has_more:
type: boolean
next_cursor:
type: string
description: Pass as `cursor` to read the next page; absent on the last page.
Usage:
type: object
required:
- object
- period
- credit_balance
- total_tasks
- credits_settled
- credits_refunded
- concurrency
- by_workflow
- by_capability
- by_model
- by_api_key
properties:
object:
type: string
enum:
- usage
period:
type: string
enum:
- all
- 24h
- 7d
- 30d
description: The window `total_tasks`, `credits_settled`, `credits_refunded` and the breakdowns cover. `credit_balance` and `concurrency` are always current.
since:
type: integer
description: Unix start of the window, inclusive. Absent when `period` is `all`.
until:
type: integer
description: Unix end of the window, exclusive. Absent when `period` is `all`.
credit_balance:
type: number
format: double
multipleOf: 0.01
description: Current USD balance. The compatibility field name is retained; 1 Credit equals $1 USD. The balance may be negative.
total_tasks:
type: integer
credits_settled:
type: number
format: double
multipleOf: 0.01
credits_refunded:
type: number
format: double
multipleOf: 0.01
concurrency:
type: object
required:
- limit
- active
properties:
limit:
type: integer
example: 2
active:
type: integer
description: Active processing tasks currently using BeatAPI processing resources. Music Video storyboard_ready and requires_action tasks can have settled USD usage without counting toward this value.
by_workflow:
type: array
description: Compatibility view containing workflow tasks only. Image, video, and Effect tasks are reported under by_capability instead.
items:
type: object
required:
- workflow
- tasks
- credits_settled
properties:
workflow:
type: string
enum:
- music-video
- ecommerce-video
- video-analysis
tasks:
type: integer
credits_settled:
type: number
format: double
multipleOf: 0.01
by_capability:
type: array
items:
type: object
required:
- task_kind
- capability_id
- tasks
- credits_settled
properties:
task_kind:
type: string
enum:
- workflow
- effect
- image
- video
capability_id:
type: string
tasks:
type: integer
credits_settled:
type: number
format: double
multipleOf: 0.01
by_model:
type: array
items:
type: object
required:
- media_type
- model
- tasks
- credits_settled
properties:
media_type:
type: string
enum:
- image
- video
model:
type: string
tasks:
type: integer
credits_settled:
type: number
format: double
multipleOf: 0.01
by_api_key:
type: array
items:
type: object
required:
- api_key_id
- title
- key_prefix
- tasks
- credits_settled
properties:
api_key_id:
type: string
title:
type: string
key_prefix:
type: string
tasks:
type: integer
credits_settled:
type: number
format: double
multipleOf: 0.01
realtime:
type: object
required:
- sessions
- credits
- active
properties:
sessions:
type: integer
description: Total BeatAPI realtime sessions for this account.
credits:
type: number
format: double
multipleOf: 0.01
description: USD amount settled by connected realtime sessions.
active:
type: integer
description: Realtime sessions in ready, connecting, or active state.
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
BadRequest:
description: 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.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
error:
code: bad_request
message: images must contain 1-7 public HTTPS URLs.
retryable: false
request_id: req_xxx
PersonalAccessTokenUnauthorized:
description: 'No personal access token, or one that is unknown or expired (`unauthorized`). Send it as `Authorization: Bearer <token>`. Not retryable.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
PersonalAccessTokenForbidden:
description: An API key was sent instead of the personal access token, or the token lacks the permission this endpoint needs (`forbidden`; the message names it). Not retryable.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
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