Skip to navigation

BeatAPI Quick Guide

Quick Guide

BeatAPI uses one server-side API key across Text, Workflow, Realtime, Video, Image, and Effect APIs. Start with the three steps below, then use the rest of this guide for synchronous text responses, shared task fields, uploads, limits, and production errors.

First task in three steps

1. Create an API key

Create a key in Dashboard → API Keys, then load it into your shell without placing it in command history:

read -rsp "BeatAPI API key: " BEATAPI_API_KEY && echo
export BEATAPI_API_KEY

All requests use the https://api.beatapi.io base URL and this header:

Authorization: Bearer <BEATAPI_API_KEY>

2. Create a task

This minimal image request uses POST /v1/images/tasks:

curl https://api.beatapi.io/v1/images/tasks \
-X POST \
-H "Authorization: Bearer $BEATAPI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "nano-banana",
"prompt": "Editorial product photograph on a warm stone pedestal."
}'

A valid request returns 201 Created. Save the returned data.id.

3. Poll the result

curl https://api.beatapi.io/v1/tasks/task_8K2qA \
-H "Authorization: Bearer $BEATAPI_API_KEY"

Replace task_8K2qA with the data.id from step 2. Wait data.poll_after_seconds between polls (5 for images, 8 for video and effects, 10 for data and workflows; it is present while the task runs). On succeeded, read data.output.media and stop polling. On failed, read data.error_code and data.error_message, then stop polling.

Keep permanent API keys on trusted servers. Never place them in browser code, mobile code, scripts, logs, or screenshots. Realtime browsers receive only a short-lived client_secret created by your server.

Choose an API

APICreate operationInputResult
Text (GPT-5.6)POST /v1/responsesText, images, tools, and reasoning controlsSynchronous JSON or streamed text response
Workflow — Music VideoPOST /v1/music-video/tasksAudio and tier-specific visual referencesComplete Music Video and storyboard metadata
Workflow — EcommercePOST /v1/ecommerce-video/tasksProduct images, duration, creative briefComplete product video
Workflow — Video AnalysisPOST /v1/video-analysis/tasksUploaded video, analysis prompt, and depthAnalysis text and token usage
RealtimePOST /v1/realtime/sessionsBrowser origin and fixed duration; then live MediaStreamLive generated WebRTC video
VideoPOST /v1/videos/tasksModel-specific prompt and media referencesOne hosted video
ImagePOST /v1/images/tasksModel-specific prompt and optional referencesOne hosted image
EffectPOST /v1/effects/tasksPublished Effect ID, images, supported optionsOne hosted image or video effect result

Text calls return synchronously or as a server-sent event stream. Realtime creates a short-lived Session. Workflow, Video, Image, and Effect create operations return an asynchronous Task: store data.id, then poll the shared task endpoint. Polling GET /v1/tasks/{task_id} is not rate limited; wait poll_after_seconds between polls.

For GPT model selection, request formats, and streaming examples, see the GPT guide.

Get task status

GET /v1/tasks/{task_id}

ParameterLocationTypeRequiredRules
task_idPathstringYesUse data.id from a create response

Status values

StatusMeaningClient action
queuedAccepted and waitingContinue polling
processingGeneration is runningContinue polling
storyboard_readyMusic Video storyboard is availableAuto flow may continue; inspect if needed
requires_actionMusic Video manual review is waitingEdit or compose shots
editingMusic Video shot edit is runningContinue polling
composingMusic Video composition is runningContinue polling
succeededHosted output is readyRead data.output and stop polling
failedTask ended with an error; the answer is still HTTP 200Read error_code, error_message and retryable, then stop polling

Image and video tasks only use queued, processing, succeeded and failed. The other statuses belong to Music Video.

Normalized Task fields

FieldTypePresentMeaning
idstringAlwaysStable task ID
objectstringAlwaystask
task_kindstringAlwaysworkflow, effect, image, video, or data
capability_idstringAlwaysStable workflow, Effect, or generation model ID
capability_versionintegerAlwaysAlways 1
workflowstringWorkflow tasksmusic-video or ecommerce-video
effect_idstringEffect tasksStable effect ID
effect_versionintegerEffect tasksImmutable selected effect version
media_typestringImage/video tasksimage or video
modelstringImage/video tasksStable model alias
statusstringAlwaysCurrent lifecycle status
stagestringAlwaysRepeats status; kept for compatibility
storyboardobjectMusic VideoShot metadata when available
created_atintegerAlwaysUnix timestamp
updated_atintegerAlwaysUnix timestamp
completed_atinteger or nullAlwaysTerminal Unix timestamp
poll_after_secondsintegerWhile the task runsSeconds to wait before the next poll: 5 for image, 8 for video and effect, 10 for data and workflows
typical_secondsobjectWhile the task runs, and only with enough historyp50, p90, samples and window: how long this model recently took. Past p90 the task is running long.
outputobject or nullAlwaysnull until success
usageobjectAlwaysCredits and billable duration
request_idstringAlwaysSupport/debug correlation ID
error_codestring or nullAlwaysMachine-readable task failure
error_messagestring or nullAlwaysHuman-readable task failure
retryablebooleanFailed tasks onlyWhether submitting the task again could succeed

Usage and output fields

Public response names such as credits_reserved are retained for API compatibility. All credit and balance values are decimal USD ledger amounts: 1 Credit = 1USD.TheDashboarddisplaysthesamevalueswitha‘1 USD. The Dashboard displays the same values with a `` symbol.

FieldTypeMeaning
usage.credits_reservednumberUSD amount reserved for the operation
usage.credits_chargednumberUSD amount charged; 0 on a failed task
usage.billable_duration_secondsinteger, optionalDuration used for USD calculation
usage.credits_settlednumberUSD amount finalized after successful work; 0 on a failed task
usage.credits_refundednumberUSD amount returned after a failed task
output.mediaobject[]Hosted result files
output.media[].typestringimage or video
output.media[].urlstringResult URL. Download and store any result you need to keep.
output.media[].mime_typestringResult MIME type
output.r2_urlstringPrimary hosted result URL

On a failed task, usage.credits_reserved is the amount held at create, usage.credits_charged and usage.credits_settled are 0, and usage.credits_refunded is the amount returned. An accepted task fails with one of six codes: content_policy_violation and bad_request (not retryable), and processing_unavailable, processing_timeout, processing_failed and result_transfer_failed (retryable). See Errors.

Upload an input file

POST /v1/files

Use file upload when an input is local instead of already available at a public HTTPS URL. Every upload must include an exact Content-Length; normal curl, browser, and SDK uploads set it automatically. Chunked uploads without a declared length are rejected before the body is buffered.

Multipart fields

FieldTypeRequiredDefaultRules
filebinaryYes—One supported file; video up to 100 MB, other types up to 50 MB. A multipart part over 100 MB is refused outright
purposestringNoinputIgnored; the response always says input
curl https://api.beatapi.io/v1/files \
-X POST \
-H "Authorization: Bearer $BEATAPI_API_KEY" \
-F "file=@./song.mp3" \
-F "purpose=input"

You may also send the raw file body with its asset Content-Type.

AssetAccepted extensionsAccepted MIME typesAdditional rule
ImagePNG, JPG/JPEG, WebPimage/png, image/jpeg, image/webpMaximum 50 MB
AudioMP3, WAV, AAC, M4Aaudio/mpeg, audio/wav, audio/aac, audio/mp4Maximum 50 MB
SubtitleSRTapplication/x-subrip; text/plain only in a multipart upload whose filename ends in .srtMaximum 50 MB
VideoMP4, MOVvideo/mp4, video/quicktimeMaximum 100 MB

Some common aliases are accepted and stored under the canonical type, for example image/jpg as image/jpeg, audio/mp3 as audio/mpeg, and text/plain (with a .srt filename) as application/x-subrip. PDF, generic text, octet-stream, unsupported video containers, and ZIP uploads are refused with 400 bad_request. The gateway trusts the declared Content-Type; when the filename has an extension, it must agree with that type. It does not inspect the file contents and does not read duration or dimensions. A file accepted by the upload can still be refused by the model or workflow that uses it, for example for duration or size rules, when you create the task. Workflow input URLs cannot be localhost, private-network, or data URLs.

Upload refusals are 400 bad_request with one of these messages:

MessageCause
Content-Length is required for file uploads.No declared length.
Content-Length must be a positive integer.Invalid declared length.
File exceeds the declared upload limit.Declared length is over the upload limit.
No file provided. Use multipart "file" field or a raw body.No file in the request.
The uploaded file is empty.Zero bytes.
Unsupported file type. Supported uploads are png, jpg, jpeg, webp, mp3, wav, aac, m4a, mp4, mov, and srt.Type or extension not accepted.
File exceeds the 50 MB limit.Over 50 MB (File exceeds the 100 MB limit. for video).
File exceeds the 100 MB upload limit.A multipart part over 100 MB.
Could not read the uploaded file.The file body could not be read.
Could not read the multipart upload.The multipart form could not be parsed.

If the file cannot be stored, the upload answers 503 with processing_unavailable (“File storage is temporarily unavailable. Retry later; nothing was stored.”) or result_transfer_failed (“The file could not be stored on our side. Retry; nothing was stored.”). Retry with backoff.

File response

{
"data": {
"id": "file_6f1c2b9e-4d0a-4c58-9a57-2f0a8f3d7b11",
"object": "file",
"url": "https://media.beatapi.io/uploads/1042/6f1c2b9e-4d0a-4c58-9a57-2f0a8f3d7b11.mp3",
"key": "uploads/1042/6f1c2b9e-4d0a-4c58-9a57-2f0a8f3d7b11.mp3",
"mime_type": "audio/mpeg",
"size_bytes": 1048576,
"purpose": "input",
"created_at": 1782210000
}
}
FieldTypePresentMeaning
idstringAlwaysFile ID, file_<uuid>
objectstringAlwaysfile
urlstringAlwaysHTTPS input URL
keystringAlwaysStorage key, uploads/<userId>/<uuid>.<ext>
mime_typestringAlwaysThe canonical MIME type the file is stored and served under (for example image/jpg is reported as image/jpeg)
size_bytesintegerAlwaysUploaded byte size
purposestringAlwaysinput
created_atintegerAlwaysUnix timestamp

Use data.url in the model or workflow request. The model or workflow checks its own limits when you create the task; for example, Standard Music Video accepts 10–180 seconds of audio and Premium accepts 10–300.

Check usage and limits

GET /v1/usage

This authenticated endpoint has no parameters.

curl https://api.beatapi.io/v1/usage \
-H "Authorization: Bearer $BEATAPI_API_KEY"
FieldTypeMeaning
objectstringusage
credit_balancenumberCurrent USD balance; it may be negative
total_tasksintegerAccount task count
credits_settlednumberSettled USD amount
credits_refundednumberRefunded USD amount
concurrencyobjectProcessing-task capacity summary
concurrency.limitintegerAccount processing-task limit
concurrency.activeintegerTasks currently consuming processing capacity
realtimeobject, optionalRealtime Session usage summary
realtime.sessionsintegerTotal Realtime Sessions
realtime.creditsnumberRealtime settled USD amount
realtime.activeintegerSessions in ready, connecting, or active
by_workflow[]object[]Workflow compatibility breakdown
by_capability[]object[]All task kinds by stable capability
by_model[]object[]Image/video tasks by model alias
by_api_key[]object[]Task/credit totals by API key

Breakdown item fields:

ArrayRequired item fields
by_workflowworkflow, tasks, credits_settled
by_capabilitytask_kind, capability_id, tasks, credits_settled
by_modelmedia_type, model, tasks, credits_settled
by_api_keyapi_key_id, title, key_prefix, tasks, credits_settled

Music Video tasks paused at storyboard_ready or requires_action can have settled credits without counting as active processing work.

Errors and retry policy

{
"error": {
"code": "rate_limit_exceeded",
"message": "Rate limit exceeded: at most 60 successful requests per 1 minute(s). Retry after 60 seconds.",
"retryable": true,
"request_id": "req_abc123",
"retry_after_seconds": 60
}
}

Every error carries code, an English message that states the cause, and request_id; only a 429 rate_limit_exceeded also carries retry_after_seconds and the Retry-After header; a 503 has no known wait, so retry it with backoff. retryable is present for every code in the table below. Branch on it: false means the same call will fail again until you change it.

Public error codes

BeatAPI exposes only the stable public codes below. BeatAPI never names the supplier behind a model and does not pass on raw upstream bodies. Errors lists which code each failure produces at create and on an accepted task, and how the text endpoints fail before the model is called (this envelope) and during the call (the SDK’s native error shape, with BeatAPI codes for our own refusals and rewritten codes for failures on the model’s side). These values appear in response error.code. Terminal asynchronous failures may also return the applicable value in task error_code.

CodeMeaningClient action
bad_requestMalformed JSON, or request fields, combinations, formats, URLs, or limits are invalid — at create, or on an accepted task whose parameter or input the model refused. The message names the fieldCorrect the request before retrying
missing_api_keyNo API key was sentSend Authorization: Bearer <key>
invalid_api_keyThe key is wrong, expired, disabled, or exhausted; the message says whichCheck the active key in the dashboard
unauthorizedLegacy name for a 401, replaced by missing_api_key and invalid_api_key on 2026-09-29; it may still appearTreat it like invalid_api_key
forbiddenThe key or account cannot perform the operation, for example a model not available on free credit, the key’s IP allowlist, or the key’s groupRead the message; a top-up unlocks every model for free-credit accounts
not_foundUnknown model or capability, or a resource that does not exist or is not owned by this API key’s accountCheck the ID and API-key ownership
insufficient_creditsInsufficient balance: the account balance is zero or below the price of this requestTop up before sending another paid request
idempotency_conflictThe idempotency key was already used with a different request bodyReuse the key only for the same logical request, or use a new key
rate_limit_exceededThe API key exceeded a request-rate limit, including the free-model limitsHonor Retry-After or retry_after_seconds
content_policy_violationThe prompt, input media, or result was refused by content moderationRevise the prompt or media before submitting a new request
processing_unavailableThe model is temporarily unavailable or at capacity (not your rate limit)Retry later with backoff; continue polling an already accepted task
processing_failedProcessing failed for a reason on our sideStop polling, inspect error_message and refund fields, then retry with backoff
processing_timeoutProcessing did not finish within the processing windowStop polling, inspect refund fields, and submit a new request if needed
result_transfer_failedBeatAPI could not persist the generated result to first-party storageStop polling, inspect refund fields, and retry the operation if needed
result_expiredPOST /v1/capabilities/run with operation: "result" found no stored result; results are kept for one hour (404)Run the capability again
not_implementedThe endpoint is published but this gateway does not serve it yet (501)Do not retry
realtime_disabledRealtime Video is not enabled on this deploymentRealtime Video is not enabled on this deployment; there is no self-service action, so contact support
realtime_capacity_unavailableRealtime capacity is temporarily unavailableRetry shortly with backoff; no delay is indicated
realtime_session_expiredThe Realtime Session can no longer be usedCreate a new Session and client secret
origin_not_allowedThe browser origin is not allowed for the Realtime SessionUse an exact configured HTTPS origin
invalid_client_secretThe Realtime client secret is invalid or no longer usableCreate a new Session and use its new client secret
transport_not_allowedThe requested Realtime transport is not allowedUse a transport documented by the Realtime API
internal_errorBeatAPI encountered an unexpected internal errorRetain request_id; retry only when safe or contact BeatAPI support
HTTPCoderetryableClient action
400bad_request, content_policy_violationfalseCorrect fields, combinations, formats, URLs, limits, or the input
401missing_api_key, invalid_api_keyfalseSend or replace the Bearer key
402insufficient_creditsfalseTop up before a new paid request
403forbidden or Realtime origin errorfalseCheck permission or exact browser origin
404not_found, result_expiredfalseCheck the model, reference, or ID and API-key ownership
409idempotency_conflictfalseReuse a key only with the same logical request body
429rate_limit_exceededtrueHonor Retry-After or retry_after_seconds
500internal_errortruePreserve request_id; retry once, then contact support
501not_implementedfalseDo not retry
503processing_unavailable, processing_timeout, processing_failed, result_transfer_failedtrueRetry with backoff

BeatAPI does not answer 502 or 504; one you still see came from the network edge, has no JSON body, and is retried like a 503.

Idempotency:

  • Workflow, Image, Video, and Effect task creation accept an optional key, and so does POST /v1/capabilities/run. Realtime Session create requires it (up to 255 characters).
  • A key is remembered for 24 hours. A key longer than 255 characters is 400 bad_request.
  • The same key with a different body or path is 409 idempotency_conflict. So is the same key while the first request is still running.
  • Repeating the identical request returns the stored response with the header Idempotent-Replayed: true.
  • Only 2xx responses are stored, so after a 400 or 402 you can retry with the same key.

Production checklist

  • Use the exact https://api.beatapi.io origin.
  • Keep permanent API keys on trusted servers.
  • Validate required/optional fields, enums, limits, and conditional rules from the selected API page.
  • Store task/Session IDs and request_id before starting background work.
  • Poll every poll_after_seconds and stop at the documented terminal or action state.
  • Download and store the results you need to keep.
  • Honor status codes, Retry-After, and retry_after_seconds.
  • Verify webhook signatures against raw bytes before JSON parsing. Webhooks send only task.succeeded and task.failed, with 3 attempts (retries after 1 minute and 5 minutes). A task failed by the timeout sweep fires no event, so keep polling as the source of truth.
  • Record credit reservations, settlements, refunds, errors, and final output URLs.
  • Review the Privacy Policy and Terms of Service before processing cameras, faces, voices, or reference assets.