How to Use the Kling 4.0 API on fal: Text, Image, Reference and Edit Endpoints, Pricing and Errors
If you generate video in an app or pipeline, Kling 4.0 is now callable through fal’s API by any fal customer, and the defaults will cost you more than you expect: every endpoint renders 1080p unless you say otherwise. fal announced on October 23, 2026 that “Kling 4.0 is now publicly available on fal, with API access open to all customers.” There are four endpoints: text-to-video, image-to-video, reference-to-video and video editing. All four produce 3 to 30 second clips at 720p or 1080p and are billed per second of video.
This guide walks through getting a key, making a first request in Python, JavaScript and curl, and using each endpoint’s real parameters. It also covers multi-shot prompts, the @Image1 / @Video1 / @Element1 reference syntax, working out the cost before you submit, and the queue, webhook and error behavior you need for production.
Every parameter name, limit and price below comes from fal’s own published material for these endpoints: the Kling 4.0 Text to Video API page, the per-endpoint OpenAPI schemas fal serves for kling/v4/text-to-video, kling/v4/image-to-video, kling/v4/reference-to-video and kling/v4/video-to-video/edit, and fal’s Quick Start, queue API and error reference docs. We did not render videos for this article, so there are no quality judgments here, only the mechanics.
What you get: the four Kling 4.0 endpoints
fal’s announcement lists the headline features as “up to 30 seconds of native video generation with audio”, “up to 15 image, video, and element references”, “precise control with up to 10 keyframes”, and improved motion, character consistency and cinematic storytelling.
The API splits that into four endpoint IDs:
| Endpoint ID | What it does | Required input |
|---|---|---|
kling/v4/text-to-video | Video from a text prompt | prompt or multi_prompt |
kling/v4/image-to-video | Animates a start image, with an optional end image | start_image_url, plus prompt or multi_prompt |
kling/v4/reference-to-video | Video from a prompt plus image, video and character references | prompt or multi_prompt |
kling/v4/video-to-video/edit | Edits an existing clip with a text instruction | video_url and prompt |
Shared across all four, per the schemas:
durationis an integer from 3 to 30 seconds. It defaults to 5 on the three generation endpoints. On the edit endpoint it defaults to the source video’s length.resolutionis"720p"or"1080p", and the default is"1080p".- The output is a single
videoobject withurl,content_type,file_nameandfile_size.
Two things the marketing copy mentions are not exposed as separate parameters in the published schemas. There is no audio on/off switch and no keyframes array. What the schemas do give you is a start frame and an end frame on image-to-video, a start frame on reference-to-video, per-shot prompts through multi_prompt, and a voice_id you can bind to a character element. If you were planning around “10 keyframes” as a field, check the API page for your endpoint before you design around it.
Step 1: Get a fal key and install a client
Create a key in the fal dashboard and export it. Both official clients read FAL_KEY from the environment automatically:
export FAL_KEY="your-api-key-here"
Install the client for your language, as given in fal’s Quick Start:
pip install fal-client # Python
npm install @fal-ai/client # JavaScript / TypeScript
Do not put FAL_KEY in browser code. fal’s client setup docs are explicit that browser source is visible to anyone. For a web front end, route calls through @fal-ai/server-proxy on your server, which attaches the key before forwarding to fal.
Step 2: Your first Kling 4.0 request
Start small: 5 seconds at 720p. That is the cheapest useful test (see the pricing section below).
Python, using subscribe, which submits to the queue and waits for the result:
import fal_client
result = fal_client.subscribe(
"kling/v4/text-to-video",
arguments={
"prompt": "A detective in a black trench coat stands on a rooftop in the rain, "
"looking through a telescope at the street below.",
"duration": 5,
"resolution": "720p",
"aspect_ratio": "16:9",
},
)
print(result["video"]["url"])
JavaScript:
import { fal } from "@fal-ai/client";
const result = await fal.subscribe("kling/v4/text-to-video", {
input: {
prompt: "A detective in a black trench coat stands on a rooftop in the rain, looking through a telescope at the street below.",
duration: 5,
resolution: "720p",
aspect_ratio: "16:9",
},
});
console.log(result.data.video.url);
Note the different result shapes. Python returns the model output directly (result["video"]), and JavaScript wraps it in data (result.data.video). That matches fal’s own examples in the Quick Start.
curl, which submits to the queue and returns immediately:
curl -X POST "https://queue.fal.run/kling/v4/text-to-video" \
-H "Authorization: Key $FAL_KEY" \
-H "Content-Type: application/json" \
-d '{"prompt": "A detective in a black trench coat on a rainy rooftop", "duration": 5, "resolution": "720p"}'
The response contains a request_id plus status_url, response_url and cancel_url. Use those returned URLs rather than building your own. fal’s queue docs note that status and result URLs use only the owner and app, not the full endpoint path, and that a URL containing the endpoint path returns 405. For Kling 4.0 the app behind kling/v4/... is not obvious from the ID. An unauthenticated request to queue.fal.run/kling/v4/text-to-video returns an error naming the application fal-ai/kling-video. Copying the URLs from the submit response avoids guessing.
The prompt field accepts up to 26,000 characters, and aspect_ratio on text-to-video is one of 16:9 (default), 9:16, 1:1 or 21:9.
Step 3: Animate an image with start and end frames
kling/v4/image-to-video takes a required start_image_url and an optional end_image_url. Both are limited to 30 MB, at least 300×300 px, and an aspect ratio between 0.40 and 2.50. fal also applies a 20-second timeout when it downloads each one. This endpoint has no aspect_ratio parameter; your start image sets the frame.
If the image is on your disk, upload it to fal storage first. The Python client has upload_file, documented in the Python client reference:
import fal_client
start_url = fal_client.upload_file("shot_start.png")
end_url = fal_client.upload_file("shot_end.png")
result = fal_client.subscribe(
"kling/v4/image-to-video",
arguments={
"start_image_url": start_url,
"end_image_url": end_url,
"prompt": "The camera slowly pushes in as the lights of the city switch on.",
"duration": 8,
"resolution": "720p",
},
)
print(result["video"]["url"])
In JavaScript the equivalent is fal.storage.upload(file), which takes a Blob and resolves to the uploaded file’s URL, per the storage reference.
Use the end frame when you need a clip to land on an exact composition, for example to cut cleanly into the next shot or to loop back to the first frame. Leave it out when you want the model to choose where the motion goes.
Step 4: Multi-shot videos with multi_prompt
The three generation endpoints accept multi_prompt instead of a single prompt. It is an array of shots. Each shot has a prompt of 1 to 512 characters and a duration from 1 to 30 seconds (default 5). The schema says: “The video duration is the sum of the shot durations.”
result = fal_client.subscribe(
"kling/v4/text-to-video",
arguments={
"multi_prompt": [
{"prompt": "Wide shot: a lighthouse on a cliff at dusk, waves crashing below.", "duration": 4},
{"prompt": "Medium shot: the keeper climbs the spiral staircase holding a lantern.", "duration": 4},
{"prompt": "Close-up: the lamp ignites and the beam sweeps across the sea.", "duration": 4},
],
"resolution": "720p",
"aspect_ratio": "16:9",
},
)
Practical rules:
- Send either
promptormulti_prompt. The schema says “Either prompt or multi_prompt must be provided.” - Per-shot prompts are short. 512 characters per shot, against 26,000 for a single
prompt. Put the scene description in each shot, not one long paragraph split three ways. - Plan the total length. The overall clip is the sum of the shots, and the endpoints only produce 3 to 30 seconds. Keep your shot durations inside that range, and remember you pay for the total.
Step 5: Reference-to-video with images, videos and characters
kling/v4/reference-to-video is the endpoint behind the “up to 15 references” claim. You pass references as lists and then name them inside the prompt:
| Field | What it is | Limit | Prompt name |
|---|---|---|---|
image_urls | Reference images (scenes, styles, objects) | Up to 10 | @Image1, @Image2, … |
video_urls | Reference videos | Up to 5; each 3–30 s, 30 s combined with element videos | @Video1, @Video2, … |
elements | Characters or objects | Up to 7 | @Element1, @Element2, … |
start_image_url | Optional first frame | Counts toward the image limit | — |
Each element can have a frontal_image_url (the main view) plus 1 to 3 reference_image_urls from other angles. Alternatively it can be a video_url of the subject (3–30 s). The schema allows “up to 3 elements” to carry a voice_id and “up to 3” to be video elements. Voices are created with fal’s separate Kling create-voice endpoint.
result = fal_client.subscribe(
"kling/v4/reference-to-video",
arguments={
"prompt": "@Element1 and @Element2 are having dinner at the table in @Image1",
"image_urls": ["https://example.com/restaurant.jpg"],
"elements": [
{
"frontal_image_url": "https://example.com/alice-front.jpg",
"reference_image_urls": ["https://example.com/alice-side.jpg"],
},
{
"frontal_image_url": "https://example.com/bob-front.jpg",
"reference_image_urls": ["https://example.com/bob-side.jpg"],
},
],
"duration": 10,
"resolution": "720p",
"aspect_ratio": "auto",
},
)
The example prompt is the one fal uses in its schema. Replace the example.com URLs with your own uploads. Three details matter here:
aspect_ratiogains an"auto"option on this endpoint, which “adapts it to the references”. The default is still16:9, so setautoyourself if your references are portrait.- Reference videos have stricter specs than images. Each must be at most 300 MB, between 700 and 4553 px on each side, 23.9 to 60.05 fps, and 3 to 30.05 seconds long. Phone screen recordings and low-resolution GIF conversions often fail the 700 px minimum.
- Video references change the price, as the next section shows.
Step 6: Edit an existing video
kling/v4/video-to-video/edit takes the source clip as video_url, referred to as @Video1, plus a text instruction in prompt. You can add image_urls (referred to as @Image1 and so on, up to 10) and up to 7 image-based elements. Elements here require a frontal_image_url and 1 to 3 reference_image_urls; video elements are not accepted on this endpoint.
result = fal_client.subscribe(
"kling/v4/video-to-video/edit",
arguments={
"video_url": fal_client.upload_file("product_demo.mp4"),
"prompt": "Change the background of @Video1 to a tropical island at sunset.",
"resolution": "720p",
},
)
The source video has the same constraints as a reference video: 3 to 30.05 seconds, at least 700 px on each side, 23.9 to 60.05 fps, and at most 300 MB. If you leave out duration, the output matches the source length.
Pricing: work out the cost before you submit
fal lists these prices on the Kling 4.0 model entries:
| Endpoint | 720p | 1080p | Billed on |
|---|---|---|---|
| Text-to-video, image-to-video | $0.157 / s | $0.235 / s | Output seconds |
| Reference-to-video (images and image elements only) | $0.157 / s | $0.235 / s | Output seconds |
| Reference-to-video with video references or video elements | $0.094 / s | $0.141 / s | Input plus output seconds, minimum 2× output |
| Video editing | $0.094 / s | $0.141 / s | Input plus output seconds, minimum 2× output |
Worked examples, calculated from those rates:
- A default request (5 s, 1080p) costs 5 × $0.235 = $1.175. The same clip at 720p is $0.785.
- A maximum-length clip (30 s) is 30 × $0.157 = $4.71 at 720p and 30 × $0.235 = $7.05 at 1080p.
- Editing a 10-second clip at 1080p, with output also 10 s, bills 10 + 10 = 20 seconds: 20 × $0.141 = $2.82. At 720p it is 20 × $0.094 = $1.88.
- Reference-to-video with a 3-second reference video and a 10-second output: input plus output is 13 s, but the minimum is 2 × 10 = 20 s, so you are billed for 20 s, which is $2.82 at 1080p.
Here is a small Python helper that applies the same rules, so you can log or cap cost per request:
RATES = {
"standard": {"720p": 0.157, "1080p": 0.235},
"video_input": {"720p": 0.094, "1080p": 0.141},
}
def kling4_cost(output_s, resolution="1080p", input_video_s=0, uses_video_input=False):
if uses_video_input:
billed = max(input_video_s + output_s, 2 * output_s)
return round(billed * RATES["video_input"][resolution], 3)
return round(output_s * RATES["standard"][resolution], 3)
print(kling4_cost(5)) # 1.175
print(kling4_cost(10, "1080p", 10, uses_video_input=True)) # 2.82
The biggest saving is to iterate at 720p and short durations, then do the final render at 1080p. Because the default is 1080p, forgetting resolution on a test loop costs about 50% more per second ($0.235 against $0.157).
Production patterns: queue, webhooks and timeouts
Video renders take longer than an image call, so for anything beyond a script, use the queue directly instead of a blocking subscribe. Everything here is from fal’s queue API docs.
Submit and come back later:
handler = fal_client.submit(
"kling/v4/text-to-video",
arguments={"prompt": "A paper boat drifting down a rainy street gutter", "resolution": "720p"},
)
print(handler.request_id) # store this
for event in handler.iter_events(with_logs=True):
if isinstance(event, fal_client.InProgress):
for log in event.logs:
print(log["message"])
result = handler.get()
A request moves through IN_QUEUE, IN_PROGRESS and COMPLETED. fal says queue requests “are never dropped”. There is no queue size limit, and a request that fails on a runner with 503, 504 or a connection error is re-queued and retried up to 10 times. A failed request still reaches COMPLETED, with error and error_type fields in the status response, so check for those rather than treating COMPLETED as success.
Use a webhook instead of polling:
handler = fal_client.submit(
"kling/v4/text-to-video",
arguments={"prompt": "...", "resolution": "720p"},
webhook_url="https://your-server.com/api/fal/webhook",
)
With curl, add ?fal_webhook=https://your-server.com/api/fal/webhook to the submit URL. The webhook body has request_id, status ("OK" or "ERROR", which is not the same as the queue states) and payload with the model output. fal says it may retry deliveries, so de-duplicate on request_id and return 200 quickly.
Know which timeout does what. start_timeout is a server-side deadline that only applies before processing starts; if it passes, you get a 504 and no retries. client_timeout in Python (timeout in milliseconds in JavaScript) only stops your client from waiting, and the render may still finish and be billed. For long Kling clips, prefer a webhook to a short client timeout.
Download your outputs. Result URLs on fal.media are public and subject to your media expiration settings, per fal’s data retention docs. Copy finished videos into your own storage. You can also set retention per request with the X-Fal-Object-Lifecycle-Preference header, and disable request-history storage of prompts and outputs with X-Fal-Store-IO: 0.
Concurrency. The synchronous API returns 429 with "type": "concurrent_requests_limit" when you hit your account’s concurrent request limit. The queue API does not return that error; it holds the request until capacity frees up. That is another reason to batch Kling jobs through submit.
Troubleshooting common errors
Model input errors come back as HTTP 422 with a detail array. Each entry has loc (which field), msg, and a machine-readable type; fal says to branch on type, not to parse msg. The ones you are most likely to hit with Kling 4.0:
| Symptom | Likely cause | Fix |
|---|---|---|
| 401 “Authentication is required” | FAL_KEY missing, or header not in Authorization: Key <key> form | Export FAL_KEY, or send the header exactly as shown |
| 405 on a status or result URL | You built the URL with the full endpoint path | Use status_url / response_url from the submit response |
422 missing or value_error on prompt | Neither prompt nor multi_prompt sent (or a shot prompt over 512 characters) | Send exactly one of them; shorten shot prompts |
422 on duration | Value outside 3–30, or a non-integer | Use a whole number from 3 to 30 |
422 image_too_small / image_too_large | Image under 300 px, over 30 MB, or aspect ratio outside 0.40–2.50 | Resize or crop before upload |
422 file_download_error | fal could not fetch your URL in time (20 s for images, 30 s for videos) or the URL is private | Upload with upload_file / fal.storage.upload and pass the fal URL |
| 422 on a reference or source video | Under 700 px, under 23.9 fps, or outside 3–30.05 s | Re-encode, e.g. scale up to at least 700 px and 24 fps |
422 content_policy_violation | Prompt or input blocked by moderation | Rephrase; check the categories field if present |
@Element3 ignored or rejected | You referenced more elements than you passed | Number references to match list positions, starting at 1 |
| Bill higher than expected | Default resolution is 1080p; video inputs are billed at a 2× output minimum | Set resolution: "720p" while testing; use the cost helper above |
For infrastructure failures (request_timeout, runner_scheduling_failure, runner_disconnected and so on), fal’s request error reference says runner and timeout errors are usually transient and worth retrying, while bad_request and client_disconnected are not. The queue already retries most of these automatically.
One more thing to know on launch day: the short descriptions on fal’s Kling 4.0 model listings still said “API access is coming soon” when we checked on October 23, while fal’s announcement post says API access is open to all customers. If your first call fails with something other than the errors above, check the model’s API page and fal’s status page before you debug your code.
How Kling 4.0 fits next to other video models
On price alone, Kling 4.0’s $0.157 to $0.235 per second sits below fal’s listed price for the Kling 3.0 4K text-to-video endpoint, $0.42 per second. That is a 4K tier, though, so it is not a like-for-like comparison. The practical differences in Kling 4.0 are the 30-second ceiling, multi-shot prompts in one request, and up to 7 character elements with optional bound voices. If you are evaluating Google’s model as well, our Gemini Omni Flash guide covers its any-to-video approach and clip limits.
For a quick sanity check on whether a generated clip matches its brief, a fast multimodal model works well as a reviewer step; see how to use Gemini 3.6 Flash for setting one up. More tutorials are on the 7minai homepage.
FAQ
Is Kling 4.0 on fal available to everyone? fal’s October 23, 2026 announcement says “API access open to all customers.” You need a fal account and API key.
What is the maximum video length? 30 seconds per request on every endpoint. The minimum is 3 seconds.
Can I get 4K from Kling 4.0?
Not from these endpoints. The resolution field only accepts 720p and 1080p.
Does the output have audio?
fal’s announcement says Kling 4.0 generates “native video generation with audio.” The published v4 schemas have no audio toggle, and you can bind a voice_id to up to 3 elements on reference-to-video.
Which endpoint should I use for a consistent character across shots?
kling/v4/reference-to-video with an elements entry (a frontal image plus 1–3 angle shots), combined with multi_prompt for the shots.
How do I keep my API key out of the browser?
Run @fal-ai/server-proxy on your server so the browser calls your proxy and the key stays server-side, as fal’s client setup docs describe.