BeatAPI Files API

Upload local assets and use the returned HTTPS URL as workflow input.

Operations 1

POST /v1/files Upload a file for workflow inputs #

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • find_apisBrowse and filter every API in the catalog.
  • get_api_artifactsOne API's artifacts, grouped by type.
  • get_openapiThe primary OpenAPI for this API.
  • find_similar_apisAPIs that look like this one.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/beatapi:beatapi-files-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Discovery needs no key. Ratings and market analysis are Pro.

Get an API key

Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

beatapi-files-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: BeatAPI Developer Files 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: Files
  description: Upload local assets and use the returned HTTPS URL as workflow input.
paths:
  /v1/files:
    post:
      operationId: uploadFile
      tags:
      - Files
      x-apidog-folder: Reference/Upload Files
      summary: Upload a file for workflow inputs
      security:
      - BearerAuth: []
      description: 'Use file upload when your images, videos, audio, or subtitle files are not

        already hosted at public HTTPS URLs. The returned HTTPS URL can be used

        directly in `images`, `reference_videos`, `audio_url`, or `srt_url`.


        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 audio or video duration or image dimensions.


        Limits:

        - Images, audio and subtitles: maximum 50 MB.

        - Videos: maximum 100 MB.

        - Images: `png`, `jpg`, `jpeg`, `webp`

        (`image/png`, `image/jpeg`, `image/webp`).

        - Audio: `mp3`, `wav`, `aac`, `m4a`

        (`audio/mpeg`, `audio/wav`, `audio/aac`, `audio/mp4`).

        - Videos: `mp4`, `mov` (`video/mp4`, `video/quicktime`).

        - Subtitles: `srt` (`application/x-subrip`; `text/plain` only in a

        multipart upload whose filename ends in `.srt`).

        - Some 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`.

        - Anything else is refused with `400 bad_request`: PDF, generic text,

        octet-stream, other video containers and zip files.

        - Send either multipart form-data with a `file` field, or send the raw

        file body with the asset `Content-Type`.

        - `Content-Length` is required and is validated before BeatAPI buffers

        the request body; chunked uploads without a declared length are rejected.

        - `purpose` is ignored; the response always says `input`.

        - A file accepted here can still be refused by the model or workflow that

        uses it (duration, dimensions, format rules). Those checks happen when

        you create the task.

        - Workflow task inputs still require public HTTPS URLs. Localhost,

        private network URLs, and data URLs are not accepted.


        Refusals are `400 bad_request` with one of these messages:

        - `Content-Length is required for file uploads.`

        - `Content-Length must be a positive integer.`

        - `File exceeds the declared upload limit.`

        - `No file provided. Use multipart "file" field or a raw body.`

        - `The uploaded file is empty.`

        - `Unsupported file type. Supported uploads are png, jpg, jpeg, webp, mp3, wav, aac, m4a, mp4, mov, and srt.`

        - `File exceeds the 50 MB limit.` (`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.`

        - `Could not read the multipart upload.`


        If the file cannot be stored, the answer is `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.'
      parameters:
      - in: header
        name: Content-Length
        required: true
        description: Exact request-body length in bytes. For multipart uploads this includes multipart framing overhead.
        schema:
          type: integer
          minimum: 1
          maximum: 105906176
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              required:
              - file
              properties:
                file:
                  type: string
                  format: binary
                purpose:
                  type: string
                  enum:
                  - input
                  description: Ignored by the gateway.
          image/png:
            schema:
              type: string
              format: binary
          image/jpeg:
            schema:
              type: string
              format: binary
          image/webp:
            schema:
              type: string
              format: binary
          audio/mpeg:
            schema:
              type: string
              format: binary
          audio/wav:
            schema:
              type: string
              format: binary
          audio/aac:
            schema:
              type: string
              format: binary
          audio/mp4:
            schema:
              type: string
              format: binary
          video/mp4:
            schema:
              type: string
              format: binary
          video/quicktime:
            schema:
              type: string
              format: binary
          application/x-subrip:
            schema:
              type: string
              format: binary
      responses:
        '201':
          description: File uploaded
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FileResponse'
              example:
                data:
                  id: file_3xYz9
                  object: file
                  url: https://files.beatapi.io/u/6f1c2b9e4d0a4c589a572f0a8f3d7b11.mp3
                  key: u/6f1c2b9e4d0a4c589a572f0a8f3d7b11.mp3
                  mime_type: audio/mpeg
                  size_bytes: 1048576
                  purpose: input
                  created_at: 1782210000
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'
        '503':
          description: 'The file could not be stored: `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."). Retryable with backoff; a 503 carries no `Retry-After` header.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  code: processing_unavailable
                  message: File storage is temporarily unavailable. Retry later; nothing was stored.
                  retryable: true
                  request_id: req_xxx
components:
  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
    InternalError:
      description: Unexpected internal error (`internal_error`). Retryable; keep `request_id` for support if it persists.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: internal_error
              message: Internal error. Contact support with the request_id if the problem continues.
              retryable: true
              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
  schemas:
    File:
      type: object
      required:
      - id
      - object
      - url
      - key
      - mime_type
      - size_bytes
      - purpose
      - created_at
      properties:
        id:
          type: string
          description: Uploaded file ID, `file_<uuid>`.
          example: file_6f1c2b9e-4d0a-4c58-9a57-2f0a8f3d7b11
        object:
          type: string
          enum:
          - file
          description: Object discriminator; always `file`.
        url:
          type: string
          format: uri
          description: BeatAPI HTTPS URL to use in workflow or model requests.
          example: https://files.beatapi.io/u/6f1c2b9e4d0a4c589a572f0a8f3d7b11.mp3
        key:
          type: string
          description: BeatAPI storage key, `u/<random>.<ext>`, for support and diagnostics.
          example: u/6f1c2b9e4d0a4c589a572f0a8f3d7b11.mp3
        mime_type:
          type: string
          description: The canonical MIME type the file is stored and served under, not necessarily the one you sent. `image/jpg` is reported as `image/jpeg`, `audio/mp3` as `audio/mpeg`, and `text/plain` (a `.srt` file) as `application/x-subrip`.
          example: audio/mpeg
        size_bytes:
          type: integer
          description: Uploaded file size in bytes.
          example: 1048576
        purpose:
          type: string
          enum:
          - input
          description: File purpose; currently always `input`.
        created_at:
          type: integer
          description: Unix timestamp when the file was stored.
          example: 1782210000
    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.
    FileResponse:
      type: object
      required:
      - data
      properties:
        data:
          $ref: '#/components/schemas/File'
          description: Uploaded file metadata and the public HTTPS URL to use in later requests.
  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