Skip to main content

Image API solution

Generate images with the controls the model really exposes.

Every image endpoint declares its own fields. Some take a negative prompt, some take a seed, some return four candidates per call. A generic form hides exactly the controls that make output repeatable.

The challenge

Generic image forms lose the controls that matter

Prompt in, image out holds for about ten seconds. Then you need the same character twice, a 3:2 crop instead of a square, four candidates per call, and a seed you can write down.

01

A seed helps compare runs, not guarantee identical pixels

Where seed exists, keep it with the prompt, model version, size and references. Some endpoints remain nondeterministic; the same seed can still produce a different image.

02

Size is a field, not a preset

Some endpoints take resolution or aspect_ratio, others take width and height in pixels. Sending the wrong one is a 400, and on endpoints priced by megapixel the size you pick is also the price you pay.

03

One call can return several images

Where num_outputs exists, the charge follows the number of images rather than the number of requests. A default of 4 costs four times a default of 1, and the estimate is the only place that gap is visible before submission.

The approach

Read the schema, keep the fields, log the seed

Build inputs from the endpoint schema. Save the exact request, ordered references and model version with the result so you can compare later variations. Keep accepted originals; regenerating them is not guaranteed.

Image tasks use the same create-and-track contract as video. The whole difference lives inside input.

POST /api/v1/jobs/createTask

POST /api/v1/jobs/createTask
Authorization: Bearer $SPICY_API_KEY
Idempotency-Key: 7b1f0c2e-9a4d-4f31-8c67-2b5e0d9a1c44
Content-Type: application/json
{
  "model": "<publisher>/<model>/text-to-image",
  "input": {
    "prompt": "A ceramic teapot on linen, soft window light, muted palette",
    "aspect_ratio": "3:2",
    "num_outputs": 2,
    "seed": 1337
  }
}

GET /api/v1/jobs/recordInfo?taskId=…

{
  "code": 200,
  "msg": "success",
  "request_id": "req_example_record",
  "data": {
    "taskId": "job_01k3m8x9q2z4v7n5p6r8s0t1w3",
    "state": "succeeded",
    "output": {
      "assets": [
        {
          "mime": "image/png",
          "url": "https://…/result.png?X-Amz-Signature=…",
          "expiresAt": "2026-09-12T12:20:08Z"
        }
      ]
    },
    "cost": "0.040000",
    "settled": true
  }
}

Contract

The parts worth pinning down

Image generation API: one call, many models — The parts worth pinning down
Field or headerValue or limit
inputadditionalProperties: false
seed · num_outputs · aspect_ratiodeclared per endpoint
cost + settled: falsehold · final charge never exceeds it
errorCode9 stable values, content_rejected included

Swipe horizontally to see all columns.

Integration

From first call to production

  1. 01Open the endpoint's model page and read which of seed, negative_prompt, num_outputs and the size fields it declares.
  2. 02Build the body from input_schema; additionalProperties is closed, so an undeclared key is a 400 rather than a silent no-op.
  3. 03Quote, submit with an Idempotency-Key, and store taskId, seed and the resolved model value next to the result.
  4. 04Collect output.assets from the callback or recordInfo and copy the files into your own bucket.

Fit

When this path is the right one

Choose this when

  • You generate from text and want several publishers behind one request shape, one balance and one bill.
  • You need to compare controlled variations with a recorded request and model version.

Look elsewhere when

  • Your users start from a picture they already have. Editing is a separate task with its own reference contract.
  • You want one fixed house style across every model. Style lives in the model, not in this layer.

Evidence

What you can verify yourself

The playground request is the production request

The body you assemble on the model page is the body you send from your server: same fields, same validation, same estimate. There is no simplified preview mode that diverges later.

Undeclared fields fail loudly

Input is validated against the endpoint's schema with additionalProperties closed. A parameter the model does not declare returns 400 with a stable errorCode instead of being quietly ignored.

Output is served from platform storage

Results come back as output.assets with a key, a MIME type, a signed url and expiresAt. Nothing hot-links to wherever the model ran.

Before launch

Platform behaviour to confirm

  • Decide where seeds are stored before launch; they are only useful if you kept them.
  • Set the per-key daily cap, which every new key requires, plus monthly and lifetime caps where they apply.
  • Handle the closed errorCode set, content_rejected included, as ordinary product states.
  • Mirror assets into your own storage inside the 14-day retention window.

FAQ

Questions this page gets asked

Reuse the original input, version and seed if available. This narrows the comparison but does not guarantee identical pixels. Download and keep the original output when you need that exact image.