Model features

Image generation and editing

Generate images, send reference pictures, track progress, and retrieve private output.

Endpoint and credentials

Call POST https://api.kendr.org/api/v1/images/generations with a key scoped to models:invoke or an app/session credential. Use the kendr-image alias. This dedicated Kendr route differs from the upstream SDK’s /v1/images/generations path.

Generation returns private metadata, not base64 output or a public URL. Downloading /api/me/generated-images/{image_id} requires the same owner’s app session, browser cookie on its origin, or OAuth token with app scope. A kndr_live_... key alone cannot download the image.

Generate one image

curl https://api.kendr.org/api/v1/images/generations \
  -H "Authorization: Bearer $KENDR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: product-428-hero-v1" \
  -d '{
    "model": "kendr-image",
    "prompt": "A ceramic travel mug on a warm neutral studio background, soft side lighting",
    "size": "1536x1024",
    "quality": "medium"
  }'
FieldAccepted valuesBehavior
promptNon-empty string, up to 32,000 charactersA selected provider may impose a smaller limit.
size1024x1024, 1536x1024, 1024x1536Default 1536x1024; provider dimensions can use a closest supported size.
qualitylow, medium, highDefault medium.
input_imagesUp to 4 PNG, JPEG, or WebP images8 MiB per image, 12 MiB combined; base64 without a data-URI prefix.
conversation_idOptional valid chat-memory IDDeleting the associated stored conversation also deletes its images.
streamBoolean, default falseProgress SSE when supported; accept JSON replays too.

One request generates one image. Batch n, seeds, masks, transparent-background controls, and output-format selectors are not in the supported contract.

Read the result

Illustrative response excerpt; IDs and charges vary:

{
  "ok": true,
  "request_id": "product-428-hero-v1",
  "model": "kendr-image",
  "image": {
    "id": "img_0123456789abcdef01234567",
    "url": "/api/me/generated-images/img_0123456789abcdef01234567",
    "mimeType": "image/png",
    "size": "1536x1024",
    "quality": "medium"
  }
}

Persist request_id, image.id, and the settled credit_micros_charged. Use the exact charge returned by Kendr; token counts alone do not represent image cost.

Edit with a reference image

Prepare this JSON body in Python, then send it to the same endpoint with a new request ID:

import base64
from pathlib import Path

payload = {
    "model": "kendr-image",
    "prompt": "Keep the mug shape and logo; change the background to pale blue.",
    "input_images": [{
        "name": "mug.png",
        "media_type": "image/png",
        "data": base64.b64encode(Path("mug.png").read_bytes()).decode("ascii"),
    }],
}

The media type must match the actual bytes. Base64 expands data by about a third; the HTTP body limit is 24 MiB. If no enabled route supports reference images, the request fails instead of ignoring them. The image studio project includes runnable generation and editing commands.

Retrieve the private image

Use an app session for the same account that generated it. Replace the image ID and choose the extension from image.mimeType.

curl --fail-with-body \
  https://api.kendr.org/api/me/generated-images/img_0123456789abcdef01234567 \
  -H "X-Kendr-Session: $KENDR_SESSION_TOKEN" \
  -o generated-image.png

An image URL is not a bearer credential. Keep session tokens on the server and check user authorization before serving bytes through your own application.

Observe image progress

Add stream: true and Accept: text/event-stream. Parse complete SSE events, then JSON-decode each event’s data.

EventMeaning
startValidated request and reserved credits.
statusGenerating or finalizing.
partial_imageOptional frame with b64 and mime_type; not the final deliverable.
doneFinal generation result with image metadata and settled usage.
errorTerminal failure; inspect status and request_id.

Admission errors and completed replays can return JSON. Partial frames are route-dependent and may never arrive. After a disconnect, the request can still finish server-side. Retry the exact image request with the same key to retrieve its result.

Troubleshoot and retry

Use a new key for a new image or edit and preserve it for recovery. In-progress duplicates can return HTTP 400; back off with the same key. A completed replay sets idempotent_replay: true and does not charge again. Never reuse a key for a different prompt.

FailureNext step
Invalid image or optionsCheck decoded size, media type, size, and quality.
402Fund the account before creating another operation.
502Use bounded backoff with the same body and key.
Download unauthorizedUse the owner’s app/session credential; an API key is insufficient.