Generate
Use POST /v1/generate whenever you want an image, a video clip or audio. The call does not block on the generation itself: it hands back a task with status 202 straight away. There are three ways to collect the result:
- add
?wait=Nand let the server hold the connection for up to N seconds, - poll the task,
- pass a webhook URL and get called when it is done.
Request format
POST https://kadraris.com/v1/generate
Authorization: Bearer sk-kd-...
Content-Type: application/json| Field | Type | Required | Purpose |
|---|---|---|---|
model | string | yes | Id of a media model, e.g. seedance-2.5, gpt-image-2.5, mureka-v9 |
input | object | yes | Parameters for that model, checked against its input_schema |
webhook_url | string | no | Address that gets a POST once the task succeeds or fails |
| Query parameter | Type | Purpose |
|---|---|---|
wait | integer, 1-120 | How many seconds the server may wait for completion before it replies |
What comes back
You get 202 Accepted if you did not send wait, or if the task was still running when the wait ran out:
{
"id": "task_8f2k...",
"object": "task",
"status": "queued",
"model": "seedance-2.5",
"estimated_cost": { "amount": "2.9351", "currency": "USD" },
"poll_url": "https://kadraris.com/v1/tasks/task_8f2k..."
}That figure belongs to the request shown under Video with a webhook (Seedance 2.5, 5 s at 720p) and was taken from the October 2, 2026 price list. Live responses always carry today's amount in estimated_cost. If you want to compute it on your own:
- for video charged by the second, multiply the per-second rate for your resolution by
duration; - the rate for each resolution is listed in
pricing.variantsofGET /v1/models/{id}; - in this example, that is the 720p rate times 5.
When you do pass ?wait=N and the task completes in time, the answer is 200 OK and contains the full task, identical to what GET /v1/tasks/{id} returns. A completed task can be succeeded or failed, so read status before using output.
Reservation and charge
- The
estimated_costamount is reserved before any work starts. With too littleavailablebalance the call returns402 insufficient_balanceand no task is created. - A
succeededtask is charged its finalcost, and the reservation is closed. - A
failedtask gets the whole reservation back. The charge is 0.
Each amount is a string paired with a currency, USD on global accounts and PLN on Polish ones. More in Billing.
Model parameters
There is no single parameter set for all models. Fetch the schema of the model you plan to use from GET /v1/models/{id} (the input_schema field). Anything the schema does not allow, such as an unknown field, a wrong type or a value out of range, is rejected with 422 invalid_request, and the message points at the offending field.
Fields you will often see, grouped by category (each model supports only some of them):
| Category | Fields |
|---|---|
| Image | prompt, negative_prompt, aspect_ratio (1:1, 16:9, 9:16, 4:3, 3:4), num_images (1-4, only where GET /v1/models/{id} lists it), image_urls (for edits or references), seed |
| Video | prompt, duration (seconds), resolution (480p, 720p, 1080p, model dependent), aspect_ratio, image_url (first frame), generate_audio |
| Audio / music | prompt, duration, lyrics, instrumental |
Leave a field out and the schema default is used.
Image with wait
Image models typically need under a minute, so a single call with ?wait=60 is usually enough.
curl "https://kadraris.com/v1/generate?wait=60" \
-H "Authorization: Bearer $KADRARIS_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "flux-2-pro",
"input": {
"prompt": "Product shot of a leather wallet on slate, soft daylight",
"aspect_ratio": "4:3"
}
}'import os, requests
API = "https://kadraris.com/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['KADRARIS_API_KEY']}"}
r = requests.post(
f"{API}/generate",
params={"wait": 60},
headers=HEADERS,
json={
"model": "flux-2-pro",
"input": {
"prompt": "Product shot of a leather wallet on slate, soft daylight",
"aspect_ratio": "4:3",
},
},
timeout=130, # keep this above wait
)
r.raise_for_status()
task = r.json()
if task["status"] == "succeeded":
for item in task["output"]:
print(item["url"], item.get("width"), item.get("height"))
elif task["status"] == "failed":
print("failed:", task["error"])
else:
print("not done yet, poll:", task["poll_url"])const res = await fetch("https://kadraris.com/v1/generate?wait=60", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.KADRARIS_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
model: "flux-2-pro",
input: {
prompt: "Product shot of a leather wallet on slate, soft daylight",
aspect_ratio: "4:3",
},
}),
});
const task = await res.json();
if (task.status === "succeeded") task.output.forEach((o) => console.log(o.url));
else console.log(task.status, task.poll_url ?? task.error);Give your HTTP client a longer timeout than wait. Otherwise it may hang up before the server has replied.
Editing an existing image
Models that accept source images take them in image_urls (confirm in input_schema):
curl "https://kadraris.com/v1/generate?wait=60" \
-H "Authorization: Bearer $KADRARIS_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "nano-banana-pro",
"input": {
"prompt": "Swap the background for a quiet beach at sunset",
"image_urls": ["https://example.com/photo.jpg"]
}
}'Video with a webhook
A video takes minutes rather than seconds. Start it without waiting and have Kadraris call your server when the clip is ready.
curl https://kadraris.com/v1/generate \
-H "Authorization: Bearer $KADRARIS_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "seedance-2.5",
"input": {
"prompt": "Slow tracking shot along a rainy tram stop at night",
"duration": 5,
"resolution": "720p",
"aspect_ratio": "16:9"
},
"webhook_url": "https://your-server.example.com/kadraris-hook"
}'r = requests.post(
f"{API}/generate",
headers=HEADERS,
json={
"model": "seedance-2.5",
"input": {
"prompt": "Slow tracking shot along a rainy tram stop at night",
"duration": 5,
"resolution": "720p",
"aspect_ratio": "16:9",
},
"webhook_url": "https://your-server.example.com/kadraris-hook",
},
timeout=30,
)
task = r.json()
print(task["id"], task["estimated_cost"])const res = await fetch("https://kadraris.com/v1/generate", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.KADRARIS_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
model: "seedance-2.5",
input: {
prompt: "Slow tracking shot along a rainy tram stop at night",
duration: 5,
resolution: "720p",
aspect_ratio: "16:9",
},
webhook_url: "https://your-server.example.com/kadraris-hook",
}),
});
const task = await res.json();
console.log(task.id, task.estimated_cost);Most video models charge by the second of output, for instance Seedance 2.5 at from $0.261 per second and Kling 3.0 at from $0.0963 per second. Veo 3.1 (Quality) is the exception, with a per-clip price of from $2.53 per video (see billing units). If the schema has an image_url field, putting a still image there makes it the first frame of the clip.
Music
curl https://kadraris.com/v1/generate \
-H "Authorization: Bearer $KADRARIS_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "mureka-v9",
"input": {
"prompt": "Lo-fi hip hop, warm vinyl crackle, mellow piano",
"lyrics": "[Verse]\nStreetlights hum below my door\n[Chorus]\nOne more song before the morning"
}
}'For this model lyrics cannot be empty. Tag sections with [Verse] and [Chorus] and encode line breaks as \n inside the JSON string. The style comes from prompt. Length limits are in the model's input_schema. Price: $0.15 per song.
Possible errors
| Status | error.type | Situation |
|---|---|---|
| 401 | authentication_error | Key missing or invalid |
| 402 | insufficient_balance | available lower than estimated_cost |
| 403 | permission_error | The key reached its spend cap |
| 404 | not_found | Unknown model id |
| 422 | invalid_request | input fails schema validation |
| 429 | rate_limit | More than 60 requests a minute on one key (default limit) |
| 429 | rate_limit_error | 25 failed generations on the account within 24 hours; Retry-After tells you how long to wait |
Once a task has started, a failure is reported in the task (status: "failed" with an error object), not as an HTTP error. See Tasks and the full Errors list.























