bithuman-ai Files API

Upload images, videos, audio, and documents.

Operations 1

POST /v1/files/upload Upload a file #

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/bithuman-ai:bithuman-ai-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

bithuman-ai-files-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: Bithuman Ai Files API
  version: '1.0'
  contact:
    name: bitHuman Support
    url: https://www.bithuman.ai/discord
  x-logo:
    url: https://docs.bithuman.ai/bithuman-mark.png
  description: 'Operations tagged Files across 2 of this provider''s published API definitions: openapi.yaml, bithuman-ai-openapi.yaml. Each path carries the servers of the definition it was published in.'
servers:
- url: https://api.bithuman.ai
  description: Production
security:
- apiSecret: []
tags:
- name: Files
  description: Upload images, videos, audio, and documents.
paths:
  /v1/files/upload:
    post:
      operationId: uploadFile
      x-codeSamples:
      - lang: shell
        label: cURL
        source: "curl -X POST https://api.bithuman.ai/v1/files/upload \\\n  -H \"api-secret: $BITHUMAN_API_SECRET\" \\\n  -H \"content-type: application/json\" \\\n  -d '{\"file_url\": \"https://example.com/avatar.jpg\", \"file_type\": \"image\"}'\n"
      summary: Upload a file
      description: 'Upload images, videos, audio, or documents — by public URL or as

        base64. Files are organized by type, and the type is read from the

        file''s own bytes: `file_type` and the filename extension are both

        cross-checked against them, never trusted over them. Files are stored

        privately. The response returns a signed `file_url` (valid 7 days) and

        a `file_id` to pass to other endpoints instead of the URL.'
      tags:
      - Files
      requestBody:
        required: true
        content:
          application/json:
            schema:
              oneOf:
              - type: object
                title: Upload by URL
                required:
                - file_url
                properties:
                  file_url:
                    type: string
                    description: Public URL to download the file from.
                    example: https://example.com/avatar.jpg
                  file_type:
                    type: string
                    enum:
                    - auto
                    - image
                    - video
                    - audio
                    - document
                    - pdf
                    default: auto
                    description: Optional cross-check, not an override — the stored category always comes from the file's own bytes. Give a value and the bytes must agree with it, or the upload is refused with `415`. `document` and `pdf` are the same category. Any other value is refused with `400 VALIDATION_ERROR`; omit it, or send `auto`, to let the bytes decide. The filename here comes from the URL's path, and its extension must be one of the supported ones.
              - type: object
                title: Upload by base64
                required:
                - file_data
                - file_name
                properties:
                  file_data:
                    type: string
                    description: Base64-encoded file data.
                  file_name:
                    type: string
                    description: Original filename. The extension is required and must be one of the supported ones (see `415`); a name without one is refused.
                    example: avatar.jpg
                  file_type:
                    type: string
                    enum:
                    - auto
                    - image
                    - video
                    - audio
                    - document
                    - pdf
                    default: auto
                    description: Optional cross-check, not an override — the stored category always comes from the file's own bytes. Give a value and the bytes must agree with it, or the upload is refused with `415`. `document` and `pdf` are the same category. Any other value is refused with `400 VALIDATION_ERROR`; omit it, or send `auto`, to let the bytes decide.
      responses:
        '200':
          description: File uploaded
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  message:
                    type: string
                    example: File uploaded successfully
                  data:
                    type: object
                    properties:
                      file_id:
                        type: string
                        description: Private reference to the uploaded file. Pass it instead of a URL to the endpoints that take an uploaded file; it works only for files your own account uploaded.
                        example: 3f2b9c14-8a7e-4d21-9f10-2c5b6e0a11dd
                      file_url:
                        type: string
                        description: Signed link to the private file, valid 7 days.
                      url_expires_in:
                        type: integer
                        description: Lifetime of `file_url` in seconds.
                        example: 604800
                      original_source:
                        type: string
                        description: Original URL or filename.
                      file_type:
                        type: string
                        description: Detected file type category.
                      file_size:
                        type: integer
                        description: File size in bytes.
                      mime_type:
                        type: string
                        description: MIME content type.
                      asset_category:
                        type: string
                        description: Storage category (images, videos, audio, docs).
                      uploaded_at:
                        type: string
                        format: date-time
        '400':
          description: "One of:\n\n- `DOWNLOAD_FAILED` — `file_url` could not be downloaded:\n  unreachable, not publicly readable, or not an ordinary public\n  `http(s)` address.\n- `VALIDATION_ERROR` — `file_data` was not valid base64, both\n  `file_url` and `file_data` were sent, or `file_type` was a value\n  this API does not define. The accepted values are `auto`,\n  `image`, `video`, `audio`, `document` and `pdf`; anything else is\n  refused rather than quietly treated as `auto`, so a typo cannot\n  silently change where your file lands.\n- `MISSING_PARAM` — neither `file_url` nor `file_data` was sent.\n"
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  code: VALIDATION_ERROR
                  message: 'Invalid file_type ''picture''; must be one of: auto, image, video, audio, document, pdf'
                  httpStatus: 400
                status: error
                status_code: 400
        '401':
          $ref: '#/components/responses/Unauthorized'
        '413':
          description: '`FILE_TOO_LARGE` — the file is over the limit for its category:

            **10 MB** images, **100 MB** video, **25 MB** audio and documents.

            The category is read from the file''s own bytes, so the limit that

            applies is the one for what the file actually is.

            '
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  code: FILE_TOO_LARGE
                  message: file is 31 MB; the limit for image is 10 MB
                  httpStatus: 413
                status: error
                status_code: 413
        '415':
          description: "`UNSUPPORTED_TYPE` — this API will not store the file. Four things\nraise it:\n\n- **The bytes are not a supported type.** Supported: JPEG, PNG,\n  GIF, WebP, BMP · MP4, MOV, WebM, AVI, WMV, FLV, Matroska ·\n  MP3, WAV, FLAC, AAC, OGG, M4A · PDF, Word, Excel, PowerPoint,\n  RTF and plain text.\n- **The bytes contradict `file_type`.** Sending\n  `file_type: \"image\"` with a text file is refused here rather than\n  stored under the wrong category.\n- **The filename extension is not one of the supported ones.** For\n  a base64 upload that is `file_name`; for a URL upload it is the\n  last path segment of `file_url`. A name with no extension, or\n  one like `.exe` or `.sh`, is refused.\n- **The file would run in a browser.** SVG, HTML and any text\n  carrying a script are refused outright: an uploaded file is\n  served from a public address, and a file that executes there\n  would run as if it came from us.\n"
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  code: UNSUPPORTED_TYPE
                  message: file_type was declared 'image' but the uploaded bytes are text/plain
                  httpStatus: 415
                status: error
                status_code: 415
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          description: '`INTERNAL_ERROR` — the file was accepted but could not be stored. Nothing is kept and nothing is charged; retrying is safe.'
    servers:
    - url: https://api.bithuman.ai
      description: Production
components:
  responses:
    Unauthorized:
      description: 'Authentication failed. `UNAUTHORIZED` when the `api-secret` header is

        present but invalid; `MISSING_AUTH` when it is absent. The HTTP status

        equals `status_code` (401).

        '
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: UNAUTHORIZED
              message: Invalid API secret
              httpStatus: 401
            status: error
            status_code: 401
    RateLimited:
      description: 'Too many requests. The limiter is **per account** — every API secret on

        the account draws from one bucket — and **per cost tier**, so a burst of

        reads never uses up your generate budget. Your plan sets the number for

        each tier; the matrix, the tier each route belongs to and a retry

        recipe are on

        [Rate limits](https://docs.bithuman.ai/api/rate-limits).


        Wait `Retry-After` seconds and retry. The `X-RateLimit-*` headers let a

        client slow down *before* it gets here, but header coverage is uneven

        across routes — read them defensively and fall back to exponential

        backoff when they are absent.


        On a route that can also be called without an API secret, an anonymous

        call is metered per network address instead: same body, same

        `Retry-After`, no `X-RateLimit-*`.

        '
      headers:
        Retry-After:
          schema:
            type: integer
          description: Seconds to wait before retrying.
          example: 1
        X-RateLimit-Limit:
          schema:
            type: integer
          description: Requests per minute your plan allows on this request's cost tier.
          example: 30
        X-RateLimit-Remaining:
          schema:
            type: integer
          description: Whole requests left in the bucket right now.
          example: 0
        X-RateLimit-Reset:
          schema:
            type: integer
          description: Unix time at which the bucket is fully refilled.
          example: 1758380460
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: RATE_LIMITED
              message: Too many generate requests for this api-secret. Retry in ~1s.
              httpStatus: 429
            status: error
            status_code: 429
  schemas:
    Error:
      type: object
      properties:
        error:
          type: object
          properties:
            code:
              type: string
              example: UNAUTHORIZED
            message:
              type: string
              example: Invalid API secret
            httpStatus:
              type: integer
              example: 401
            upgrade_url:
              type: string
              description: 'On `PLAN_REQUIRED`, `AGENT_LIMIT_REACHED` and `CONCURRENCY_LIMIT_REACHED` (403): where to choose a plan. Send the user there instead of retrying. See [Plan and credit refusals](https://docs.bithuman.ai/api/errors#plan-and-credit-refusals).'
              example: https://www.bithuman.ai/pricing
            topup_url:
              type: string
              description: 'On `INSUFFICIENT_BALANCE` (402): where to top up credits.'
              example: https://www.bithuman.ai/billing#credits
            details:
              type: object
              description: Code-specific fields. `CONCURRENCY_LIMIT_REACHED` sends `tier`, `cap`, `active` and `upgrade_url`.
              additionalProperties: true
        status:
          type: string
          example: error
        status_code:
          type: integer
          example: 401
  securitySchemes:
    apiSecret:
      type: apiKey
      name: api-secret
      in: header
      description: 'Your bitHuman API secret. Get one at

        [www.bithuman.ai/developer/api-keys](https://www.bithuman.ai/developer/api-keys).

        '
    bearerApiSecret:
      type: http
      scheme: bearer
      description: 'The same API secret, sent as `Authorization: Bearer <api-secret>`. Self-

        hosted runtimes send it this way; the classic `api-secret` header works

        on the same routes.

        '
x-refined-from:
- openapi.yaml
- bithuman-ai-openapi.yaml
x-tagGroups:
- name: Get started
  tags:
  - overview
  - quickstart
  - auth-guide
  - models
  - pricing
- name: Core concepts
  tags:
  - avatars-imx
  - audio-streaming
  - agent-lifecycle
- name: SDKs
  tags:
  - sdk-python
  - sdk-swift
  - cli
- name: Guides
  tags:
  - local-mode
  - building-avatars
- name: Deployment
  tags:
  - deploy-livekit
  - deploy-self-hosted
  - deploy-embed
- name: API reference
  tags:
  - Authentication
  - Agent Generation
  - Agent Management
  - Agent Context
  - Files
  - Dynamics
  - Embedding
  - Video
  - Billing
  - Account
  - Self-hosting
  - API secrets
  - Providers
  - Runtime sessions
  - Knowledge
  - Realtime
  - Status
  - Webhooks
- name: Resources
  tags:
  - community
  - changelog
  - support