API reference

POST /ai/imagine

Generate an image from a prompt.

The imagine endpoint turns a text prompt into an image and returns the finished image URL in a single request. It is synchronous: the connection is held open while the job runs, up to a bounded timeout, and the response carries the result directly. Any request that fails or does not finish in time is cancelled and refunded, so you are never charged for an image you did not receive. Fire-and-forget async submission is intentionally not exposed in v1 — every call blocks until the job settles or the wait window elapses.

Endpoint

POST/api/v1/ai/imagine

The request body is JSON. Only prompt is required. The mode is fixed to text-to-image; there is no image-input, mask, or edit parameter on this endpoint in v1.

Like the OpenAI-compatible Chat completions endpoint — and unlike the native REST resources — this endpoint returns a bare JSON object with no { "data": …, "meta": … } envelope. Errors raised by the endpoint itself (400, 405, 502, 504) use the shape { "error": { "message": …, "type": … } }; the shared authentication, scope, and credit refusals (401, 403, 402) use the native { "error": { "code": …, "message": … }, "meta": … } envelope.

Authorization and scope

Send a krallo_live_… bearer key in the Authorization header. The key must hold the ai:imagine scope (or the * wildcard). See Authentication for how keys are issued and sent.

RequirementValue
MethodPOST
Scopeai:imagine
AuthBearer krallo_live_… key
Content typeapplication/json
MeteringFlat per-image credit cost, pre-charged and refunded on non-delivery

Request parameters

All parameters live in the JSON request body.

NameTypeRequiredDescription
prompt string required The text description of the image to generate. Must be present and non-blank, or the call returns 400 invalid_request_error.
negative_prompt string optional Concepts to steer away from. Support depends on the underlying provider.
seed integer optional Seed for reproducible sampling. Omit for a random seed on each call.
steps integer optional Sampler step count. Omit to use the provider default. Passed through as-is and not range-validated by the API.
guidance number optional Prompt-adherence (guidance) strength. Omit to use the provider default. Passed through as-is.
width integer optional Requested output width in pixels. Omit to use the provider default.
height integer optional Requested output height in pixels. Omit to use the provider default.
output_count integer optional Number of images the job should render. The synchronous response surfaces a single output_url (the primary image) regardless of count.
strength number optional Denoising/transform strength for the sampler. Omit to use the provider default. Passed through as-is.
project_id string optional Your own grouping/reference id, attached to the job for organization. It does not affect generation.
wait_timeout_ms integer optional How long the request will wait for the job to finish, in milliseconds. Default 90000; clamped to the range 15000–180000. Values outside the range are pulled to the nearest bound.

The generation mode is always text-to-image. steps, guidance, and strength are forwarded to the image pipeline without range validation, so unsupported values fall back to provider behavior rather than being rejected.

Synchronous wait behavior

When you POST, the request submits the job and blocks until one of the following happens.

Cancelling a timed-out job before refunding is deliberate: it prevents a background job from finishing and delivering an image after you have already been refunded. Choose wait_timeout_ms to fit your client’s own read timeout — a larger value tolerates slow provider queues, a smaller value returns a retryable 504 sooner. Keep your HTTP read timeout at least as large as the wait you request.

Example request

cURL
curl https://exe.krallo.com/api/v1/ai/imagine \
  -H "Authorization: Bearer krallo_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "a lighthouse on a cliff at dawn, cinematic, volumetric light",
    "negative_prompt": "text, watermark, low quality",
    "width": 1024,
    "height": 1024,
    "seed": 42,
    "wait_timeout_ms": 120000
  }'
Node.js
const res = await fetch("https://exe.krallo.com/api/v1/ai/imagine", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${process.env.KRALLO_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    prompt: "a lighthouse on a cliff at dawn, cinematic, volumetric light",
    width: 1024,
    height: 1024,
    wait_timeout_ms: 120000,
  }),
});

if (!res.ok) {
  const err = await res.json();
  throw new Error(`${res.status} ${err.error?.type}: ${err.error?.message}`);
}

const { output_url } = await res.json();
console.log("image:", output_url);

Success response

A completed job returns 200 OK with a bare object. output_url is an absolute, publicly fetchable URL for the finished image; relative pipeline paths are resolved to an absolute URL before they are returned.

{
  "job_id": "9f2c1b7a-4e6d-40b1-a0c3-f5e8d2b1a6c4",
  "status": "SUCCEEDED",
  "output_url": "https://exe.krallo.com/img/ai/c8b1f0d2-7a3e-4f19-9d5c-2e6b8a4c0d17.png",
  "provider_used": "..."
}
FieldTypeDescription
job_idstringUnique id for this generation job. Also the natural idempotency key on the imagine.completed webhook, if you subscribe to one.
statusstringAlways SUCCEEDED on a 200 response.
output_urlstringAbsolute URL of the generated image.
provider_usedstringOptional. A label for the backend that rendered the image. Present when known; the field is omitted when the provider label is unavailable.

Billing and refunds

Image generation is billed at a flat per-image cost (default 10 credit units), not by tokens — the price is known up front, so the cost is pre-charged before the job runs and refunded on any non-delivery. Each app has a free daily allowance (default 10000 units) that resets at UTC midnight; charges hit the owner’s prepaid wallet only after that allowance is exhausted and only while billing is enabled. See Billing for the credit model, free quota, and how the wallet is debited.

A successful image is charged once, on the wallet of the developer who owns the app’s key. Retrying a 502/504 is safe from a billing standpoint — the failed attempt was already refunded.

Webhook: imagine.completed

If you have a verified webhook endpoint subscribed to imagine.completed, a successful generation also fires that event. The synchronous response is authoritative for a single call; the webhook is useful for auditing or for reconciling generations across your fleet. Because job_id is a unique per-job id, use it as an idempotency key to deduplicate a retried delivery.

{
  "job_id": "9f2c1b7a-4e6d-40b1-a0c3-f5e8d2b1a6c4",
  "status": "SUCCEEDED",
  "output_url": "https://exe.krallo.com/img/ai/c8b1f0d2-7a3e-4f19-9d5c-2e6b8a4c0d17.png",
  "provider_used": "...",
  "mode": "text_to_image",
  "width": 1024,
  "height": 1024
}

Errors

Errors raised by the endpoint itself (400, 405, 502, 504) use the shape { "error": { "message": …, "type": … } }; authentication, scope, and credit refusals (401, 403, 402) use the native envelope, with the identifier in error.code. See Errors for the shared model and correlation ids.

StatusTypeWhen
400invalid_request_errorBody is not valid JSON, or prompt is missing/blank.
401unauthorized / invalid_token / token_expired / token_revokedMissing, malformed, expired, or revoked bearer key. See Authentication.
402insufficient_creditsOver the free allowance and the wallet cannot cover the flat image cost. Body includes required_units and balance.
403insufficient_scope / app_disabled / owner_suspendedKey lacks the ai:imagine scope (body includes required_scope), or the app/account is disabled.
405method_not_allowedAny method other than POST (pre-flight OPTIONS returns 204).
429rate_limitedPer-key rate limit exceeded. Honor the Retry-After header. See Rate limits.
502upstream_errorThe job reached a terminal failed/cancelled state, or the orchestrator threw. Refunded; retryable. The message echoes the job’s error detail when one is available.
504timeoutThe job did not finish within wait_timeout_ms; it was cancelled. Refunded; retryable.

Rate limits

Imagine calls count against your key’s per-minute rate limit, which is driven by the app’s tier. Every response past the authentication and scope checks carries advisory X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset headers; a 429 additionally sets Retry-After. Because a request holds the connection for the full generation, keep your client’s read timeout at least as large as your chosen wait_timeout_ms. See Rate limits for tiers and header semantics.

Related