# Get Account Info
Source: https://developer.beeble.ai/docs/api-reference/account/get-account-info

https://api.beeble.ai/developer-api-docs/openapi.json get /v1/account/info
Get account metadata and current rate limit usage.



# Get Billing Info
Source: https://developer.beeble.ai/docs/api-reference/account/get-billing-info

https://api.beeble.ai/developer-api-docs/openapi.json get /v1/account/billing
Get billing period details and per-meter usage breakdown. This endpoint may be slower as it fetches external billing data.



# Get Job Status
Source: https://developer.beeble.ai/docs/api-reference/switchx/get-job-status

https://api.beeble.ai/developer-api-docs/openapi.json get /v1/switchx/generations/{job_id}
Poll the status of a SwitchX job.



# List Jobs
Source: https://developer.beeble.ai/docs/api-reference/switchx/list-jobs

https://api.beeble.ai/developer-api-docs/openapi.json get /v1/switchx/generations
List your SwitchX jobs with cursor-based pagination.



# Start Generation
Source: https://developer.beeble.ai/docs/api-reference/switchx/start-generation

https://api.beeble.ai/developer-api-docs/openapi.json post /v1/switchx/generations
Start a SwitchX compositing job.



# Create Upload URL
Source: https://developer.beeble.ai/docs/api-reference/uploads/create-upload-url

https://api.beeble.ai/developer-api-docs/openapi.json post /v1/uploads
Create a presigned upload URL for a media file.



# Authentication
Source: https://developer.beeble.ai/docs/authentication

How to obtain and use your Beeble API key

The Beeble API uses API keys for authentication. Each request must include your API key in the request headers.

## Getting Your API Key

<Steps>
  <Step title="Go to Developer Page">
    Go to [developer.beeble.ai/api-keys](https://developer.beeble.ai/api-keys).
  </Step>

  <Step title="Sign Up">
    Sign up and accept the terms if you don't have an account.
  </Step>

  <Step title="Create Key">
    Click **Create Key** to generate a new
    key.
  </Step>

  <Step title="Save Your Key">
    Copy and securely store your API key immediately. For security reasons,
    you won't be able to view it again.
  </Step>
</Steps>

<Warning>
  Your API key will only be displayed once upon creation. Make sure to
  copy and store it in a secure location before closing the dialog.
</Warning>

## Using Your API Key

Include your API key in the `x-api-key` header with every request:

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.beeble.ai/v1/uploads \
    -H "x-api-key: YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{"filename": "source.mp4"}'
  ```

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

  response = requests.post(
      "https://api.beeble.ai/v1/uploads",
      headers={
          "x-api-key": "YOUR_API_KEY",
          "Content-Type": "application/json"
      },
      json={"filename": "source.mp4"}
  )
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch("https://api.beeble.ai/v1/uploads", {
      method: "POST",
      headers: {
          "x-api-key": "YOUR_API_KEY",
          "Content-Type": "application/json",
      },
      body: JSON.stringify({ filename: "source.mp4" }),
  });
  ```
</CodeGroup>

## Revoking Your API Key

If you need to revoke your API key:

1. Go to the [Developer Page](https://developer.beeble.ai/api-keys)
2. Click the **Revoke** button next to your API key
3. Confirm the revocation

<Note>
  After revoking your API key, all requests using that key will be rejected.
  You can issue a new key at any time.
</Note>


# Errors
Source: https://developer.beeble.ai/docs/errors

Error codes and error response format

The Beeble API uses conventional HTTP status codes and returns structured error responses with machine-readable error codes.

## Error Response Format

All errors follow this format:

```json theme={null}
{
    "error": {
        "message": "Human-readable error description",
        "code": "ERROR_CODE"
    }
}
```

| Field     | Type   | Description                             |
| --------- | ------ | --------------------------------------- |
| `message` | string | Human-readable description of the error |
| `code`    | string | Machine-readable error code             |

***

## Error Codes

### Validation Errors (400)

Returned when request parameters are invalid or missing.

| Code                      | Description                                                                            |
| ------------------------- | -------------------------------------------------------------------------------------- |
| `INVALID_GENERATION_TYPE` | `generation_type` must be `"image"` or `"video"`                                       |
| `INVALID_ALPHA_MODE`      | `alpha_mode` must be `"auto"`, `"fill"`, `"custom"`, or `"select"`                     |
| `INVALID_MAX_RESOLUTION`  | `max_resolution` must be `720` or `1080`                                               |
| `MISSING_STYLE_INPUT`     | Neither `reference_image_uri` nor `prompt` was provided                                |
| `MISSING_SOURCE`          | `source_uri` is required                                                               |
| `MISSING_ALPHA`           | `alpha_uri` required when `alpha_mode` is `"custom"` or `"select"`                     |
| `INVALID_FILE_FORMAT`     | Source format doesn't match `generation_type` (e.g. video source for image generation) |
| `ALPHA_TYPE_MISMATCH`     | Alpha type doesn't match source (image vs video) when `alpha_mode` is `"custom"`       |
| `ALPHA_MUST_BE_IMAGE`     | Alpha must be an image (PNG/JPG) when `alpha_mode` is `"select"`                       |
| `SOURCE_TOO_LARGE`        | Source resolution exceeds 2,770,000 total pixels (width × height)                      |
| `VIDEO_TOO_MANY_FRAMES`   | Video exceeds the maximum of 240 frames                                                |
| `INVALID_URI`             | URI format invalid or file type could not be determined                                |
| `SOURCE_UNREACHABLE`      | Source, alpha, or reference URI is not reachable                                       |
| `INVALID_FILENAME`        | Filename invalid or unsupported extension                                              |
| `INVALID_CALLBACK_URL`    | Callback URL is not valid HTTPS or is unreachable                                      |

### Authentication Errors (401)

Returned when API key authentication fails.

| Code              | Description                   |
| ----------------- | ----------------------------- |
| `INVALID_API_KEY` | API key is missing or invalid |

### Billing Errors (402)

Returned when there is a billing or payment issue with your account.

| Code                      | Description                                                                                                                                       |
| ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| `BILLING_NOT_CONFIGURED`  | No billing account or no active API subscription. Set up billing at [developer.beeble.ai](https://developer.beeble.ai)                            |
| `INSUFFICIENT_BALANCE`    | Prepaid account balance is too low for this job. Top up your balance to continue                                                                  |
| `HARD_LIMIT_EXCEEDED`     | This job would push your current period usage over your spending limit. Wait for the next billing cycle or contact support to increase your limit |
| `CREDIT_DEDUCTION_FAILED` | Failed to process credit deduction (server-side issue)                                                                                            |

### Not Found Errors (404)

Returned when the requested resource doesn't exist.

| Code            | Description                              |
| --------------- | ---------------------------------------- |
| `JOB_NOT_FOUND` | Job doesn't exist or is not owned by you |

### Rate Limiting (429)

Returned when you exceed a rate or concurrency limit. See [Rate Limits](/rate-limits) for details.

| Code                        | Description                                                                                      |
| --------------------------- | ------------------------------------------------------------------------------------------------ |
| `RATE_LIMIT_EXCEEDED`       | Too many requests per minute. Back off and retry after a short delay                             |
| `CONCURRENT_LIMIT_EXCEEDED` | Too many in-flight generation jobs. Wait for running jobs to complete before submitting new ones |

<Warning>
  `RATE_LIMIT_EXCEEDED` and `CONCURRENT_LIMIT_EXCEEDED` require **different retry strategies**.
  For RPM limits, use exponential backoff. For concurrency limits, poll your active jobs and wait for one to finish.
</Warning>

### Server Errors (500)

Returned when an internal error occurs. These are not caused by your request.

| Code                      | Description                        |
| ------------------------- | ---------------------------------- |
| `INTERNAL_ERROR`          | Unexpected server error            |
| `CREDIT_DEDUCTION_FAILED` | Failed to process credit deduction |
| `UPLOAD_URL_FAILED`       | Failed to generate upload URL      |
| `JOB_QUEUE_FAILED`        | Failed to queue job for processing |


# Overview
Source: https://developer.beeble.ai/docs/index

Beeble API for AI-powered visual effects

## SwitchX

SwitchX is our flagship video-to-video model that lets you switch anything in a scene while perfectly keeping what matters. Unlike standard video generators, SwitchX uses the original pixels to drive the final output.

By providing a Source Video, defining an Alpha Mask (to tell the AI what to keep), and providing a Reference Image (to dictate the new look), SwitchX seamlessly generates new elements and relights your original subject to match perfectly.

### How It Works

<Steps>
  <Step title="Upload Assets">
    Use the [Uploads API](/api-reference/uploads/create-upload-url) to securely upload your starting materials:

    <ParamField type="file">
      The original video you want to transform.
    </ParamField>

    <ParamField type="file">
      Your visual target. While not strictly required, we **always strongly recommend** providing one to achieve the highest quality and most accurate results.
    </ParamField>

    <ParamField type="file">
      A custom mask file. Whether you need to upload this depends entirely on which **alpha\_mode** you choose in the next step.
    </ParamField>
  </Step>

  <Step title="Start Generation">
    Call the [Generate endpoint](/api-reference/switchx/start-generation) to define your compositing job. Link your uploaded assets and configure the following parameters:

    <ParamField type="string">
      Choose how SwitchX handles the scene:

      | Mode       | Description                                                                                               |
      | :--------- | :-------------------------------------------------------------------------------------------------------- |
      | **Auto**   | The AI automatically detects and masks the foreground subject.                                            |
      | **Select** | Provide an alpha mask for the **first frame only**, and our AI will propagate it across the entire video. |
      | **Fill**   | Keeps everything in the original scene exactly as it is (no masking applied).                             |
      | **Custom** | Provide a full custom video mask for exact **frame-by-frame** control.                                    |
    </ParamField>

    <ParamField type="string">
      *(Recommended)* A text description of the desired output video to further guide the AI on the specific style, lighting, or background details you want to generate.
    </ParamField>
  </Step>

  <Step title="Poll or Webhook">
    Video generation takes a little time. Check your job's progress by [polling our status endpoint](/api-reference/switchx/get-generation-status), or set up a [webhook callback](/webhooks) to get notified the second it finishes.
  </Step>

  <Step title="Download">
    Retrieve the URL from the completed job and download your seamlessly composited, fully relighted final video!
  </Step>
</Steps>

***

## Get Started

<CardGroup>
  <Card title="Quickstart" icon="rocket" href="/quickstart">
    Make your first API call in minutes
  </Card>

  <Card title="SwitchX API" icon="wand-magic-sparkles" href="/api-reference/switchx/start-generation">
    Full SwitchX endpoint reference
  </Card>
</CardGroup>

<CardGroup>
  <Card title="Uploads" icon="upload" href="/api-reference/uploads/create-upload-url">
    Upload files for SwitchX
  </Card>

  <Card title="Authentication" icon="key" href="/authentication">
    Get your API key
  </Card>
</CardGroup>

<CardGroup>
  <Card title="Account" icon="user" href="/api-reference/account/get-account-info">
    Check your rate limits, spending limit, and billing info
  </Card>
</CardGroup>

***

## LLM-Friendly Docs

Build AI-powered integrations using our machine-readable documentation.

<CardGroup>
  <Card title="llms.txt" icon="robot" href="https://developer.beeble.ai/docs/llms.txt">
    Concise doc index for LLMs
  </Card>

  <Card title="llms-full.txt" icon="file-lines" href="https://developer.beeble.ai/docs/llms-full.txt">
    Full documentation content for LLMs
  </Card>
</CardGroup>


# llms.txt
Source: https://developer.beeble.ai/docs/llms-txt

Machine-readable documentation for LLMs and AI-powered tools

We provide [llms.txt](https://llmstxt.org/) files so AI tools and LLMs can easily consume our documentation.

## Available Files

<CardGroup>
  <Card title="llms.txt" icon="robot" href="https://developer.beeble.ai/docs/llms.txt">
    Concise index of all documentation pages with summaries. Use this for quick context and discovery.
  </Card>

  <Card title="llms-full.txt" icon="file-lines" href="https://developer.beeble.ai/docs/llms-full.txt">
    Full documentation content in a single file. Use this when you need complete API details.
  </Card>
</CardGroup>

## OpenAPI Specification

For programmatic API client generation or tool integrations (MCP, Cursor, etc.), the OpenAPI spec is available at:

```
https://api.beeble.ai/developer-api-docs/openapi.json
```


# Quickstart
Source: https://developer.beeble.ai/docs/quickstart

Generate a composited video with SwitchX in minutes

## Prerequisites

To use the Beeble API, you need an API key.

1. Go to [Developer Page](https://developer.beeble.ai/api-keys)
2. Sign up and accept the terms if you don't have an account
3. Click **Create Key**

<Note>
  See [Authentication](/authentication) for details on obtaining and using
  your API key.
</Note>

***

## Try It — One Command

Run this single command to generate a video using our sample assets. Replace `YOUR_API_KEY` with your key.

Here's what you'll be working with:

<CardGroup>
  <Card title="Source Video">
    <video />
  </Card>

  <Card title="Alpha Video">
    <video />
  </Card>

  <Card title="Reference Image">
    <img alt="Reference image" />
  </Card>

  <Card title="Output">
    <video />
  </Card>
</CardGroup>

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.beeble.ai/v1/switchx/generations \
    -H "x-api-key: YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "generation_type": "video",
      "source_uri": "https://cdn.beeble.ai/public/developer-api/source.mp4",
      "reference_image_uri": "https://cdn.beeble.ai/public/developer-api/reference.png",
      "alpha_uri": "https://cdn.beeble.ai/public/developer-api/alpha.mp4",
      "alpha_mode": "custom",
      "max_resolution": 720,
      "prompt": "Video depicts a young woman with long red hair and freckles, smiling and gently looking to her right, as she walks through the sun-dappled courtyard of a traditional Korean palace."
    }'
  ```

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

  API_KEY = "YOUR_API_KEY"
  HEADERS = {
      "x-api-key": API_KEY,
      "Content-Type": "application/json"
  }

  response = requests.post(
      "https://api.beeble.ai/v1/switchx/generations",
      headers=HEADERS,
      json={
          "generation_type": "video",
          "source_uri": "https://cdn.beeble.ai/public/developer-api/source.mp4",
          "reference_image_uri": "https://cdn.beeble.ai/public/developer-api/reference.png",
          "alpha_uri": "https://cdn.beeble.ai/public/developer-api/alpha.mp4",
          "alpha_mode": "custom",
          "max_resolution": 720,
          "prompt": "Video depicts a young woman with long red hair and freckles, smiling and gently looking to her right, as she walks through the sun-dappled courtyard of a traditional Korean palace.",
      }
  )

  job_id = response.json()["id"]
  ```

  ```javascript JavaScript theme={null}
  const API_KEY = "YOUR_API_KEY";
  const headers = {
    "x-api-key": API_KEY,
    "Content-Type": "application/json",
  };

  const res = await fetch(
    "https://api.beeble.ai/v1/switchx/generations",
    {
      method: "POST",
      headers,
      body: JSON.stringify({
        generation_type: "video",
        source_uri: "https://cdn.beeble.ai/public/developer-api/source.mp4",
        reference_image_uri: "https://cdn.beeble.ai/public/developer-api/reference.png",
        alpha_uri: "https://cdn.beeble.ai/public/developer-api/alpha.mp4",
        alpha_mode: "custom",
        max_resolution: 720,
        prompt: "Video depicts a young woman with long red hair and freckles, smiling and gently looking to her right, as she walks through the sun-dappled courtyard of a traditional Korean palace.",
      }),
    }
  );

  const { id: jobId } = await res.json();
  ```
</CodeGroup>

**Response (201):**

```json theme={null}
{
  "id": "YOUR_GENERATION_ID...",
  "status": "in_queue",
  "progress": 0,
  "generation_type": "video",
  "alpha_mode": "custom",
  "output": null,
  "error": null,
  "created_at": "2026-02-23T10:00:00Z",
  "modified_at": "2026-02-23T10:00:00Z",
  "completed_at": null
}
```

***

## Check Status & Download

Poll the job status until it completes, then download the result.

<CodeGroup>
  ```bash cURL theme={null}
  # Check status (repeat until "completed")
  # Replace YOUR_GENERATION_ID with the "id" from the response above
  curl https://api.beeble.ai/v1/switchx/generations/YOUR_GENERATION_ID \
    -H "x-api-key: YOUR_API_KEY"

  # Download the result
  # Replace with the "render" URL from the completed response
  curl -o output.mp4 "RENDER_URL_FROM_OUTPUT"
  ```

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

  while True:
      result = requests.get(
          f"https://api.beeble.ai/v1/switchx/generations/{job_id}",
          headers={"x-api-key": API_KEY}
      ).json()

      if result["status"] == "completed":
          output = result["output"]
          break
      if result["status"] == "failed":
          raise Exception(result.get("error"))

      time.sleep(5)

  # Download the result
  with open("output.mp4", "wb") as f:
      f.write(requests.get(output["render"]).content)
  ```

  ```javascript JavaScript theme={null}
  const sleep = (ms) => new Promise(r => setTimeout(r, ms));

  let output;
  while (true) {
    const res = await fetch(
      `https://api.beeble.ai/v1/switchx/generations/${jobId}`,
      { headers: { "x-api-key": API_KEY } }
    );
    const status = await res.json();

    if (status.status === "completed") {
      output = status.output;
      break;
    }
    if (status.status === "failed") throw new Error(status.error);

    await sleep(5000);
  }

  // Download the result
  const fs = require("fs");
  const renderRes = await fetch(output.render);
  fs.writeFileSync("output.mp4", Buffer.from(await renderRes.arrayBuffer()));
  ```
</CodeGroup>

**Response (completed):**

```json theme={null}
{
  "id": "YOUR_GENERATION_ID",
  "status": "completed",
  "progress": 100,
  "generation_type": "video",
  "alpha_mode": "custom",
  "output": {
    "render": "https://cdn.beeble.ai/.../output.mp4",
    "source": "https://cdn.beeble.ai/.../source.mp4",
    "alpha": "https://cdn.beeble.ai/.../alpha.mp4"
  },
  "created_at": "2026-02-23T10:00:00Z",
  "modified_at": "2026-02-23T10:05:00Z",
  "completed_at": "2026-02-23T10:05:00Z"
}
```

<Note>
  Output URLs expire after **72 hours**. You can always re-fetch fresh URLs by calling the status endpoint again.
</Note>

***

## Complete Script

A single copy-paste script that creates a generation, polls until complete, and downloads the result.

<CodeGroup>
  ```python Python theme={null}
  """
  Beeble SwitchX API — Complete Example
  Install: pip install requests
  Usage:   python beeble_quickstart.py
  """
  import time
  import requests

  API_KEY = "YOUR_API_KEY"
  BASE_URL = "https://api.beeble.ai/v1"
  HEADERS = {"x-api-key": API_KEY, "Content-Type": "application/json"}

  # 1. Start generation using sample assets
  print("Starting generation...")
  response = requests.post(
      f"{BASE_URL}/switchx/generations",
      headers=HEADERS,
      json={
          "generation_type": "video",
          "source_uri": "https://cdn.beeble.ai/public/developer-api/source.mp4",
          "reference_image_uri": "https://cdn.beeble.ai/public/developer-api/reference.png",
          "alpha_uri": "https://cdn.beeble.ai/public/developer-api/alpha.mp4",
          "alpha_mode": "custom",
          "max_resolution": 720,
          "prompt": "Video depicts a young woman with long red hair and freckles, "
                    "smiling and gently looking to her right, as she walks through "
                    "the sun-dappled courtyard of a traditional Korean palace.",
      },
  )
  response.raise_for_status()
  job = response.json()
  job_id = job["id"]
  print(f"Job created: {job_id} (status: {job['status']})")

  # 2. Poll until complete
  while True:
      result = requests.get(
          f"{BASE_URL}/switchx/generations/{job_id}",
          headers={"x-api-key": API_KEY},
      ).json()

      status = result["status"]
      progress = result.get("progress", 0)
      print(f"  Status: {status} ({progress}%)")

      if status == "completed":
          break
      if status == "failed":
          raise Exception(f"Job failed: {result.get('error')}")

      time.sleep(5)

  # 3. Download result
  render_url = result["output"]["render"]
  print(f"Downloading result...")
  with open("output.mp4", "wb") as f:
      f.write(requests.get(render_url).content)
  print("Saved to output.mp4")
  ```

  ```javascript JavaScript theme={null}
  /**
   * Beeble SwitchX API — Complete Example
   * Usage: node beeble_quickstart.mjs
   */
  import fs from "fs";

  const API_KEY = "YOUR_API_KEY";
  const BASE_URL = "https://api.beeble.ai/v1";
  const headers = { "x-api-key": API_KEY, "Content-Type": "application/json" };

  // 1. Start generation
  console.log("Starting generation...");
  const createRes = await fetch(`${BASE_URL}/switchx/generations`, {
    method: "POST",
    headers,
    body: JSON.stringify({
      generation_type: "video",
      source_uri: "https://cdn.beeble.ai/public/developer-api/source.mp4",
      reference_image_uri: "https://cdn.beeble.ai/public/developer-api/reference.png",
      alpha_uri: "https://cdn.beeble.ai/public/developer-api/alpha.mp4",
      alpha_mode: "custom",
      max_resolution: 720,
      prompt:
        "Video depicts a young woman with long red hair and freckles, " +
        "smiling and gently looking to her right, as she walks through " +
        "the sun-dappled courtyard of a traditional Korean palace.",
    }),
  });
  const job = await createRes.json();
  console.log(`Job created: ${job.id} (status: ${job.status})`);

  // 2. Poll until complete
  const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
  let result;
  while (true) {
    const res = await fetch(`${BASE_URL}/switchx/generations/${job.id}`, {
      headers: { "x-api-key": API_KEY },
    });
    result = await res.json();
    console.log(`  Status: ${result.status} (${result.progress ?? 0}%)`);

    if (result.status === "completed") break;
    if (result.status === "failed") throw new Error(result.error);
    await sleep(5000);
  }

  // 3. Download result
  console.log("Downloading result...");
  const renderRes = await fetch(result.output.render);
  fs.writeFileSync("output.mp4", Buffer.from(await renderRes.arrayBuffer()));
  console.log("Saved to output.mp4");
  ```
</CodeGroup>

***

## Using Your Own Videos

To use your own source video, alpha mask, or reference image, upload them first to get a `beeble_uri`.

<Steps>
  <Step title="Get Upload URLs">
    Create upload URLs for your files.

    <CodeGroup>
      ```bash cURL theme={null}
      # Upload source video
      curl -X POST https://api.beeble.ai/v1/uploads \
        -H "x-api-key: YOUR_API_KEY" \
        -H "Content-Type: application/json" \
        -d '{"filename": "source.mp4"}'

      # Upload reference image
      curl -X POST https://api.beeble.ai/v1/uploads \
        -H "x-api-key: YOUR_API_KEY" \
        -H "Content-Type: application/json" \
        -d '{"filename": "reference.png"}'
      ```

      ```python Python theme={null}
      source_upload = requests.post(
          "https://api.beeble.ai/v1/uploads",
          headers=HEADERS,
          json={"filename": "source.mp4"}
      ).json()

      reference_upload = requests.post(
          "https://api.beeble.ai/v1/uploads",
          headers=HEADERS,
          json={"filename": "reference.png"}
      ).json()
      ```

      ```javascript JavaScript theme={null}
      const [sourceUpload, referenceUpload] = await Promise.all([
        fetch("https://api.beeble.ai/v1/uploads", {
          method: "POST",
          headers,
          body: JSON.stringify({ filename: "source.mp4" }),
        }).then((r) => r.json()),

        fetch("https://api.beeble.ai/v1/uploads", {
          method: "POST",
          headers,
          body: JSON.stringify({ filename: "reference.png" }),
        }).then((r) => r.json()),
      ]);
      ```
    </CodeGroup>
  </Step>

  <Step title="Upload Files">
    Upload each file to its upload URL.

    <CodeGroup>
      ```bash cURL theme={null}
      curl -X PUT "YOUR_SOURCE_UPLOAD_URL" \
        -H "Content-Type: video/mp4" \
        --data-binary @source.mp4

      curl -X PUT "YOUR_REFERENCE_UPLOAD_URL" \
        -H "Content-Type: image/png" \
        --data-binary @reference.png
      ```

      ```python Python theme={null}
      with open("source.mp4", "rb") as f:
          requests.put(
              source_upload["upload_url"],
              headers={"Content-Type": "video/mp4"},
              data=f
          )

      with open("reference.png", "rb") as f:
          requests.put(
              reference_upload["upload_url"],
              headers={"Content-Type": "image/png"},
              data=f
          )
      ```

      ```javascript JavaScript theme={null}
      const fs = require("fs");

      await Promise.all([
        fetch(sourceUpload.upload_url, {
          method: "PUT",
          headers: { "Content-Type": "video/mp4" },
          body: fs.readFileSync("source.mp4"),
        }),
        fetch(referenceUpload.upload_url, {
          method: "PUT",
          headers: { "Content-Type": "image/png" },
          body: fs.readFileSync("reference.png"),
        }),
      ]);
      ```
    </CodeGroup>
  </Step>

  <Step title="Start Generation">
    Use the `beeble_uri` from the upload responses to start a generation.

    <CodeGroup>
      ```bash cURL theme={null}
      curl -X POST https://api.beeble.ai/v1/switchx/generations \
        -H "x-api-key: YOUR_API_KEY" \
        -H "Content-Type: application/json" \
        -d '{
          "generation_type": "video",
          "source_uri": "YOUR_SOURCE_BEEBLE_URI",
          "reference_image_uri": "YOUR_REFERENCE_BEEBLE_URI",
          "alpha_mode": "auto",
          "prompt": "Your prompt describing the desired output."
        }'
      ```

      ```python Python theme={null}
      response = requests.post(
          "https://api.beeble.ai/v1/switchx/generations",
          headers=HEADERS,
          json={
              "generation_type": "video",
              "source_uri": source_upload["beeble_uri"],
              "reference_image_uri": reference_upload["beeble_uri"],
              "alpha_mode": "auto",
              "prompt": "Your prompt describing the desired output.",
          }
      )

      job_id = response.json()["id"]
      ```

      ```javascript JavaScript theme={null}
      const res = await fetch(
        "https://api.beeble.ai/v1/switchx/generations",
        {
          method: "POST",
          headers,
          body: JSON.stringify({
            generation_type: "video",
            source_uri: sourceUpload.beeble_uri,
            reference_image_uri: referenceUpload.beeble_uri,
            alpha_mode: "auto",
            prompt: "Your prompt describing the desired output.",
          }),
        }
      );

      const { id: jobId } = await res.json();
      ```
    </CodeGroup>

    Then poll for status and download the result as shown above.
  </Step>
</Steps>

### Alpha Modes

Whether you need to upload an alpha mask depends on the `alpha_mode` you choose:

| Mode       | Alpha Mask Required                                            |
| :--------- | :------------------------------------------------------------- |
| **auto**   | Not needed — the AI detects the foreground automatically       |
| **fill**   | Not needed — keeps everything as-is                            |
| **select** | First-frame alpha only — the AI propagates it across the video |
| **custom** | Full video mask required for frame-by-frame control            |

See the [`alpha_mode` field in Start Generation](/api-reference/switchx/start-generation#body-alpha-mode) for details.

***

## Next Steps

<CardGroup>
  <Card title="SwitchX API" icon="wand-magic-sparkles" href="/api-reference/switchx/start-generation">
    Full endpoint reference
  </Card>

  <Card title="Uploads" icon="upload" href="/api-reference/uploads/create-upload-url">
    Upload endpoint reference
  </Card>
</CardGroup>


# Rate Limits
Source: https://developer.beeble.ai/docs/rate-limits

Request rate and concurrency limits for the Beeble API

The Beeble API enforces per-user rate limits to ensure fair usage and service stability. Limits apply per user account, not per API key.

## Limits

| Limit                         | Default | Description                                          |
| :---------------------------- | :------ | :--------------------------------------------------- |
| **Requests per minute (RPM)** | 5       | Maximum API calls to generation endpoints per minute |
| **Concurrent generations**    | 10      | Maximum in-flight generation jobs at any time        |
| **Spending limit**            | \$5,000 | Maximum spending per billing period (in dollars)     |

<Note>
  Rate limits apply only to write endpoints (`POST /v1/switchx/generations`).
  Read endpoints (status polling, listing jobs) have a separate limit of **5
  requests per minute** per account.
</Note>

***

## Spending Limit

Each account has a `spending_limit` (in dollars) that caps total spending per billing period. If a new job would push your current period usage over this limit, the API returns `402` with error code `HARD_LIMIT_EXCEEDED`.

The error message includes your current usage and the job cost so you can decide whether to wait for the next billing cycle or request a limit increase.

***

## Checking Your Limits

Use the [Account Info](/api-reference/account/get-account-info) endpoint to see your current rate limits and usage:

```bash theme={null}
curl https://api.beeble.ai/v1/account/info \
  -H "x-api-key: YOUR_API_KEY"
```

The response includes your configured limits:

```json theme={null}
{
  "spending_limit": 5000,
  "rate_limits": {
    "rpm": { "usage": 3, "limit": 5 },
    "concurrency": { "usage": 1, "limit": 10 }
  }
}
```

For detailed billing usage breakdown (per-meter totals, billing period dates), use the [Billing Info](/api-reference/account/get-billing-info) endpoint. Note that this endpoint fetches live data from external billing services and is rate-limited to **5 requests per minute** — avoid calling it in tight loops.


# Webhooks
Source: https://developer.beeble.ai/docs/webhooks

Receive notifications when jobs complete or fail

Instead of polling for job status, provide a `callback_url` when starting a generation to receive a webhook notification when the job completes or fails.

## Using Webhooks

Include the `callback_url` parameter in your generation request:

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.beeble.ai/v1/switchx/generations \
    -H "x-api-key: YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "generation_type": "video",
      "source_uri": "beeble://uploads/upload_xxx/source.mp4",
      "reference_image_uri": "https://example.com/ref.png",
      "alpha_mode": "auto",
      "callback_url": "https://your-server.com/webhook"
    }'
  ```

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

  response = requests.post(
      "https://api.beeble.ai/v1/switchx/generations",
      headers={
          "x-api-key": "YOUR_API_KEY",
          "Content-Type": "application/json"
      },
      json={
          "generation_type": "video",
          "source_uri": "beeble://uploads/upload_xxx/source.mp4",
          "reference_image_uri": "https://example.com/ref.png",
          "alpha_mode": "auto",
          "callback_url": "https://your-server.com/webhook",
      }
  )
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch("https://api.beeble.ai/v1/switchx/generations", {
      method: "POST",
      headers: {
          "x-api-key": "YOUR_API_KEY",
          "Content-Type": "application/json",
      },
      body: JSON.stringify({
          generation_type: "video",
          source_uri: "beeble://uploads/upload_xxx/source.mp4",
          reference_image_uri: "https://example.com/ref.png",
          alpha_mode: "auto",
          callback_url: "https://your-server.com/webhook",
      }),
  });
  ```
</CodeGroup>

## Webhook Payload

When the job completes or fails, a `POST` request will be sent to your `callback_url`.

**Success:**

```json theme={null}
{
    "id": "swx_abc123",
    "status": "completed",
    "output": {
        "render": "https://cdn.beeble.ai/.../render.mp4",
        "source": "https://cdn.beeble.ai/.../source.mp4",
        "alpha": "https://cdn.beeble.ai/.../alpha.mp4"
    },
    "completed_at": "2026-02-23T10:05:00Z"
}
```

**Failure:**

```json theme={null}
{
    "id": "swx_abc123",
    "status": "failed",
    "completed_at": "2026-02-23T10:05:00Z",
    "error": "Processing failed"
}
```

## Retry Behavior

If your endpoint does not return a `2xx` status code, the webhook will be retried with exponential backoff:

| Attempt | Delay after previous |
| :------ | :------------------- |
| 1       | Immediate            |
| 2       | \~1 second           |
| 3       | \~5 seconds          |
| 4       | \~30 seconds         |
| 5       | \~2 minutes          |

After 5 failed attempts, the webhook is marked as failed. You can check delivery status via the [Get Generation Status](/api-reference/switchx/get-generation-status) endpoint:

```json theme={null}
{
  "id": "swx_abc123",
  "status": "completed",
  "webhook": {
    "status": "failed",
    "attempts": 5,
    "last_error": "HTTP 502 Bad Gateway"
  }
}
```

The `webhook` field is only present when a `callback_url` was provided. Possible statuses: `pending`, `delivered`, `failed`.

<Note>
  Your webhook endpoint should return a `2xx` status code within **10 seconds** to acknowledge
  receipt. Process the payload asynchronously if your handler needs more time.
</Note>


