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.
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
Start building
Create a key and connect your account in minutes.
Run the quickstartGo from your first request to a video with copyable examples.
Two endpoints. The complete workflow.
Generate with Kling V3, Ultra image preparation, and 720p output.
POST/api/v1/kling-v3-ultra/generations
/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.
read -rs "BLUMA_API_KEY?Paste your API key: "
2. Create a generation
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.
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
/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
/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. |