Get started

Bluma API

Video generation, built into your workflow.

Bring characters to life from an image and a motion reference. Create a generation, check its status, and get a finished video — all through a simple REST API.

A few lines. A new video.REST API · v1
curl -X POST https://api.getbluma.com/api/v1/\
kling-v3-ultra/generations \
  -H "Authorization: Bearer $BLUMA_API_KEY" \
  -H "Idempotency-Key: your-unique-request-id" \
  -H "Content-Type: application/json" \
  --data @request.json
202 Acceptedqueued processing completed

Start building

Two endpoints. The complete workflow.

Generate with Kling V3, Ultra image preparation, and 720p output.

POST
Create a generation/api/v1/kling-v3-ultra/generations
GET
Retrieve a generation/api/v1/generations/{id}

Choose your environment

Environment Base URL
Production https://api.getbluma.com
Staging https://api-staging.getbluma.com

Use an API key from the same environment as your request. Keys created in production won’t authenticate staging requests.

FROM TERMINAL TO VIDEO

Run your first generation

This example uses real public sample media: a character image and a 3-second motion video. Submitting it uses your account's credits. Use the same terminal for all three steps.

1. Load your key

On macOS with zsh, run this command, paste your key at the prompt, then press Enter. Your key stays hidden.

zsh
read -rs "BLUMA_API_KEY?Paste your API key: "

2. Create a generation

POST · cURL
GENERATION_RESPONSE=$(curl -sS \
  'https://api.getbluma.com/api/v1/kling-v3-ultra/generations' \
  -H "Authorization: Bearer $BLUMA_API_KEY" \
  -H 'Idempotency-Key: bluma-docs-production-test-001' \
  -H 'Content-Type: application/json' \
  --data '{
    "prompt": "Preserve the character appearance and follow the reference motion.",
    "inputs": {
      "image_url": "https://v3b.fal.media/files/b/0a90ffa7/TNErq9yD7ZxGRATjfAqnh_EIgJSN67.png",
      "motion_video_url": "https://v3b.fal.media/files/b/0a90ff92/hklvF__w53diz6Rve7f5__JuDW2xl0mr6sJ_Kjz3Vxe_vidoeook%20(1)_1.mp4"
    },
    "options": {
      "reference": "video",
      "duration_seconds": 3,
      "keep_original_sound": true
    }
  }')

printf '%s\n' "$GENERATION_RESPONSE"

A successful submission returns HTTP 202, a generation id, and status: "queued". If you receive an error, resolve it before continuing.

3. Retrieve the result

This command reads the ID from the POST response using Python 3. Repeat it every 5–10 seconds until the status is completed or failed.

GET · cURL
GENERATION_ID=$(printf '%s' "$GENERATION_RESPONSE" \
  | python3 -c 'import json, sys; print(json.load(sys.stdin)["id"])') && \
curl -sS \
  "https://api.getbluma.com/api/v1/generations/$GENERATION_ID" \
  -H "Authorization: Bearer $BLUMA_API_KEY"

When complete, open the returned video_url. Checking status does not create a new generation or charge additional credits.

Retry the same POST with the same idempotency key and inputs. To intentionally create another video, change the key's suffix from 001 to 002.

GET CONNECTED

Authentication

For enabled accounts, open Settings → API, name your key, and select Create. Copy the secret when it appears; it is shown once. Staging keys are created in staging Settings → API.

Store your key on your server. Send it on every request:

Authorization: Bearer YOUR_API_KEY

A key accesses only its owner's generations. Any active key owned by that user can retrieve their public API generations. To rotate a key, create its replacement before revoking the old key. Revocation blocks new requests; already accepted jobs continue.

API REFERENCE

Create a generation

POST/api/v1/kling-v3-ultra/generations

Requires Authorization, Content-Type: application/json, and an Idempotency-Key header. The body accepts only the following fields.

Field Type Behavior
inputs.image_urlRequired string Public HTTP(S) image, up to 10 MiB and 40 million decoded pixels.
inputs.motion_video_urlRequired string Public HTTP(S) MP4, MOV, or WebM; up to 100 MiB and 180 seconds of source footage.
prompt string Optional instructions, up to 2,500 characters. Defaults to an empty string.
inputs.voice_id string Optional accessible library or owned voice ID, or its ElevenLabs provider voice ID. Requires source audio and keep_original_sound: true.
options.reference string "video" (default) supports up to 30 seconds; "image" supports up to 10 seconds.
options.duration_seconds number Optional trim from the start. Minimum 0.5 seconds; cannot exceed the source duration or reference-mode maximum.
options.keep_original_sound boolean Defaults to true. Set false to omit the original sound.

Without a trim, the full source video must fit the selected reference-mode limit. Model, Ultra preparation, and output resolution are fixed by this endpoint. Unknown fields are rejected.

202 · Accepted

{
  "id": "36bef404-d2ca-42c2-bb84-842d528f1305",
  "status": "queued",
  "status_url": "/api/v1/generations/36bef404-d2ca-42c2-bb84-842d528f1305",
  "model": "kling-v3",
  "ultra": true,
  "resolution": "720p",
  "created_at": "2026-09-29T12:00:00.000Z",
  "updated_at": "2026-09-29T12:00:00.000Z"
}

Acceptance includes fetching, validating, and storing the input media. Video processing happens afterward. The response also includes a relative Location header.

API REFERENCE

Retrieve a generation

GET/api/v1/generations/{id}

Use the returned generation ID or append status_url to the same API base URL. Requires the owner's active API key.

Status What to do
queued Accepted and waiting to run. Check again in a few seconds.
processing Generation is running. Continue polling.
completed Retrieve the output from video_url. The response also includes video_id.
failed Read error.code and error.message. Stop polling.

If an optional voice replacement cannot be applied, the video may complete with the original audio and a voice_not_applied warning. The voice-step charge is refunded.

RELIABLE INTEGRATIONS

Retries & idempotency

Choose a unique Idempotency-Key for each intended generation: 8–128 printable ASCII characters, with no spaces. Save it before submitting.

  • Same key and same inputs: returns the original generation without a duplicate charge.
  • Same key with different inputs: returns 409.
  • Network timeout or 503: retry the same inputs with the same key.
  • Completed or failed generation: the key still refers to the original request. Use a new key for an intentional new generation.

Keys are scoped to the owner and operation, so retries also work after rotating an API credential.

PLAN YOUR USAGE

Credits & limits

Generations use the API key owner's account balance and the same billing calculation as the app for matching settings. There is no extra API surcharge. The complete generation cost must be available before acceptance.

Ultra image preparation is included in the charge plan. Optional voice replacement can add a charge. Short clips are retimed to the provider's minimum processing duration, then restored to their requested duration; billing uses the processing duration.

Invalid requests and insufficient-credit responses do not charge your balance. Failed jobs refund their outstanding charges; a temporary dependency outage may delay the refund.

These two endpoints have no Bluma request-rate or active-job quota. Available credits, media constraints, worker concurrency, and provider capacity still apply. Queuing is possible.

TROUBLESHOOTING

Errors

{ "error": { "code": "insufficient_credits", "message": "Insufficient credits for this generation." } }
HTTP status Meaning
400 Invalid body, unsupported media or options, or missing/invalid idempotency key.
401 Missing, invalid, or revoked API key. Check that the key and API hostname use the same environment.
402 Insufficient account credits for the complete generation.
403 The key owner's account is inactive or deleted.
404 Unknown endpoint, missing generation, or generation owned by another user.
409 The idempotency key was already used with different inputs.
503 Temporary dependency failure. Retry using the same idempotency key and inputs.