PL Log inOpen Studio
Preview version. Model catalog, prices, calculator and docs are live. Generation goes live at launch.

Generate

Docs: every page

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=N and 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

http
POST https://kadraris.com/v1/generate
Authorization: Bearer sk-kd-...
Content-Type: application/json
FieldTypeRequiredPurpose
modelstringyesId of a media model, e.g. seedance-2.5, gpt-image-2.5, mureka-v9
inputobjectyesParameters for that model, checked against its input_schema
webhook_urlstringnoAddress that gets a POST once the task succeeds or fails
Query parameterTypePurpose
waitinteger, 1-120How 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:

json
{
  "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.variants of GET /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

  1. The estimated_cost amount is reserved before any work starts. With too little available balance the call returns 402 insufficient_balance and no task is created.
  2. A succeeded task is charged its final cost, and the reservation is closed.
  3. A failed task 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):

CategoryFields
Imageprompt, 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
Videoprompt, duration (seconds), resolution (480p, 720p, 1080p, model dependent), aspect_ratio, image_url (first frame), generate_audio
Audio / musicprompt, 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.

bash
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"
    }
  }'
python
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"])
javascript
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):

bash
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.

bash
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"
  }'
python
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"])
javascript
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

bash
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

Statuserror.typeSituation
401authentication_errorKey missing or invalid
402insufficient_balanceavailable lower than estimated_cost
403permission_errorThe key reached its spend cap
404not_foundUnknown model id
422invalid_requestinput fails schema validation
429rate_limitMore than 60 requests a minute on one key (default limit)
429rate_limit_error25 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.