> ## Documentation Index
> Fetch the complete documentation index at: https://developer.beeble.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> This site documents two API families. Choose the family before generating integration code and keep its request fields, billing, statuses, responses, and webhooks together.
> SwitchX API: POST /v1/switchx/generations; use /quickstart and /authentication. Completed generation files are under output.
> Enterprise API: POST /v1/products/{product}/jobs and GET /v1/product-jobs/{job_id}; use /enterprise/quickstart and /products. Check /enterprise for current access requirements. Completed product files are under outputs.
> For product jobs, fetch model-specific input_schema from GET /v1/products/{product}/models. OpenAPI defines the common job response; product guides show illustrative completed outputs. Do not treat output examples as exhaustive schemas.
> SwitchX 2.0 Finish uses the separate switchx_finish product and model_id switchx-2.0. Follow /products/switchx-finish: pass inputs.parent_job_id (a completed Standard switchx product generation's public dap_ ID owned by the same key owner, organization, and team) and inputs.target_resolution (1080 or 2160), without uploading media. Fast results, Finish results, and legacy SwitchX API generations cannot be parents. Estimate the transition, then submit and poll the new child ID; result files are under outputs.
> For product APIs, authenticate with an Organization API Key in x-api-key and keep the same organization and X-Beeble-Team-Id context for uploads, estimates, submissions, and reads. Use Beeble Cloud credits; product routes do not support USD.
> Follow /enterprise/llms-txt for the product API workflow: discover products and models, upload media, estimate credits, submit with an idempotency_key, and poll or receive webhooks. On an uncertain submission, retry the same body and key; do not create a replacement job.
> Product-job success is status=success; stop polling on failed, cancelled, or credit_required. Use the chosen product guide for completed response examples and download fields. Refer to /enterprise/errors, /enterprise/rate-limits, /guides/billing, and /guides/jobs for failures, limits, and refunds.

# Uploads

> Use uploaded files, HTTPS URLs, or base64 data URIs as media inputs.

## Choose a media input

Each single-file media field accepts one of these forms:

| Input           | Example                                                    | Requirement                                                                      |
| --------------- | ---------------------------------------------------------- | -------------------------------------------------------------------------------- |
| Beeble URI      | `beeble://uploads/your-upload-id/source.png`               | Finish the upload in the same organization before use.                           |
| Beeble CDN URL  | `https://cdn.beeble.ai/public/developer-api/reference.png` | Use an owned file, an original signed URL granting access, or a public sample.   |
| HTTPS URL       | `https://storage.example.com/source.png?signature=...`     | Publicly readable or presigned; custom authentication headers are not supported. |
| Base64 data URI | `data:image/png;base64,...`                                | At most 50 MiB of decoded media. Use the file's MIME type.                       |

Pass the value directly in the model's media field, such as `inputs.source`,
`inputs.reference_image`, or a supported audio reference. No separate upload is
required for HTTPS or `data:` inputs. For private Beeble CDN files, use a URL
you own or preserve the complete signed URL that grants access. The URL alone
does not grant access to another user's private file. Public CDN samples can
be used directly without a signature.

For inline files, create the complete URI before submitting the request:

<CodeGroup>
  ```bash Shell theme={null}
  # Encode a local PNG. Remove base64 line breaks before putting it in JSON.
  SOURCE_URI="data:image/png;base64,$(base64 < source.png | tr -d '\r\n')"
  ```

  ```python Python theme={null}
  import base64

  with open("source.png", "rb") as source:
      source_uri = "data:image/png;base64," + base64.b64encode(source.read()).decode("ascii")
  ```

  ```javascript JavaScript theme={null}
  // Run in Node.js. Use the MIME type of the actual file.
  import { readFile } from "node:fs/promises"

  const sourceUri =
    "data:image/png;base64," + (await readFile("source.png")).toString("base64")
  ```
</CodeGroup>

Use the complete value as the media field in the JSON request body. For audio,
use `data:audio/mpeg;base64,...` for MP3 or `data:audio/wav;base64,...` for WAV;
the selected model must support that audio input.

External HTTPS imports have a 5 GiB file limit and a 120-second download
budget; large files or slow origins should use an upload URL instead.
Private network destinations and redirects to them are refused.
The selected model's file type, size, dimensions, and duration limits also
apply. Requests with multiple external references may share a shorter download
budget, so upload large reference sets first. Keep presigned URLs readable and
their contents unchanged through estimation and submission. Separate estimate
and job requests can fetch the same URL again. Estimates can import and store
media, but do not create jobs or charge credits.
Image-sequence directory inputs still require a Beeble cache URI.

## Create an upload URL

[Request parameters, body, and response schema](/docs/enterprise/api-reference/create-upload-url)

Set `BEEBLE_API_KEY` and, for internal teams, `BEEBLE_TEAM_ID`. Use the same
organization and team when submitting the job. Python requires `requests`;
JavaScript examples run in Node.js.

<CodeGroup>
  ```bash cURL theme={null}
  curl --fail-with-body https://api.beeble.ai/v1/uploads \
    -H "x-api-key: $BEEBLE_API_KEY" \
    -H "X-Beeble-Team-Id: ${BEEBLE_TEAM_ID:-}" \
    -H "Content-Type: application/json" \
    --data '{"filename": "source.png"}'
  ```

  ```python Python theme={null}
  import os
  import requests

  headers = {"x-api-key": os.environ["BEEBLE_API_KEY"]}
  if team_id := os.environ.get("BEEBLE_TEAM_ID"):
      headers["X-Beeble-Team-Id"] = team_id

  response = requests.post(
      "https://api.beeble.ai/v1/uploads",
      headers=headers,
      json={"filename": "source.png"},
      timeout=30,
  )
  response.raise_for_status()
  upload = response.json()
  print(upload["beeble_uri"])
  ```

  ```javascript JavaScript theme={null}
  import { readFile } from "node:fs/promises"

  const headers = {
    "x-api-key": process.env.BEEBLE_API_KEY,
    "Content-Type": "application/json",
  }
  if (process.env.BEEBLE_TEAM_ID)
    headers["X-Beeble-Team-Id"] = process.env.BEEBLE_TEAM_ID
  const response = await fetch("https://api.beeble.ai/v1/uploads", {
    method: "POST",
    headers,
    body: JSON.stringify({ filename: "source.png" }),
    signal: AbortSignal.timeout(30_000),
  })
  if (!response.ok) throw new Error(await response.text())
  const upload = await response.json()
  console.log(upload.beeble_uri)
  ```
</CodeGroup>

**Response (200):**

```json theme={null}
{
  "id": "upload_example",
  "upload_url": "https://storage.example.com/source.png?signed-parameters",
  "beeble_uri": "beeble://uploads/upload_example/source.png"
}
```

## Upload the file

Send the file to the returned `upload_url`. This example uses a PNG image;
use the matching content type for other files. Do not send your API key to this URL.

For models with audio references, upload `.mp3` with `Content-Type: audio/mpeg`
or `.wav` with `Content-Type: audio/wav`, then pass the returned Beeble URI in
the model's audio field. Audio uploads do not change SwitchX's image/video inputs.

<CodeGroup>
  ```bash cURL theme={null}
  UPLOAD_URL="https://storage.example.com/source.png?signed-parameters" # Use your upload_url.
  curl --fail-with-body --request PUT "$UPLOAD_URL" \
    -H "Content-Type: image/png" \
    --data-binary @source.png
  ```

  ```python Python theme={null}
  with open("source.png", "rb") as source:
      uploaded = requests.put(
          upload["upload_url"],
          headers={"Content-Type": "image/png"},
          data=source,
          timeout=120,
      )
  uploaded.raise_for_status()
  ```

  ```javascript JavaScript theme={null}
  const uploaded = await fetch(upload.upload_url, {
    method: "PUT",
    headers: { "Content-Type": "image/png" },
    body: await readFile("source.png"),
    signal: AbortSignal.timeout(120_000),
  })
  if (!uploaded.ok) throw new Error(await uploaded.text())
  ```
</CodeGroup>

## Use the media in a job

After the upload succeeds, use `beeble_uri` in the model's media input, usually
`inputs.source`. Continue with the [Quickstart](/docs/enterprise/quickstart).

## Media requirements

* Match the model's supported media types, dimensions, and duration.
* SwitchX source and custom-alpha uploads must not exceed **5 GB**.
* Complete uploads before requesting an estimate or submitting a job.

### Source metadata

SwitchX, Background Remover, VFX Passes, SDR to HDR, and Reframe measure the
source automatically. You can omit `generation_type` and `frame_count`; if you
supply a media type, it must match the file. Other models follow their `input_schema`.

Reframe still requires all six canvas and source-placement fields. See [Reframe](/docs/products/reframe).

<Accordion title="Metadata returned by estimates">
  `source_metadata` includes media type, width, height, and frame count, plus
  frame rate and duration for video. `frame_count_exact: false` means the count
  was calculated from duration and frame rate. Products without source
  measurement return `source_metadata: null`.
</Accordion>

See the [Upload API Reference](/docs/enterprise/api-reference/create-upload-url) for the full schema.
