Skip to content
Radient LogoRadient Documentation

Image API Usage Guide

Generate an image from a prompt, or edit an existing image with one. Image generation is asynchronous: you submit a request, poll it until it settles, then fetch the generated file.

The same API covers video — see the Video API for the video-specific parameters and billing. Older clients may still call the legacy routes; they forward to the same engine and are documented at the bottom of this page.

Submit: POST https://api.radienthq.com/v1/tools/media/generate. Poll: GET /v1/tools/media/status?request_id=…. Fetch: GET /v1/tools/media/result?request_id=….

#Quickstart

Submit a request. The default image model is used when you do not name one:

bash
curl https://api.radienthq.com/v1/tools/media/generate \
  -H "Authorization: Bearer $RADIENT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"prompt": "A single red apple on a white table, studio photo", "image_size": "square"}'

The response is the queue handle and the quoted price — nothing is charged yet:

json
{"request_id":"01a1218e-4850-77e0-8370-ecd4926402ff","model":"…","provider":"…","status":"IN_QUEUE","queue_position":0,"cost_usd":0.03,"units":1,"unit":"megapixel"}

Poll the request id until it settles:

bash
curl "https://api.radienthq.com/v1/tools/media/status?request_id=01a1218e-4850-77e0-8370-ecd4926402ff" \
  -H "Authorization: Bearer $RADIENT_API_KEY"
json
{"request_id":"01a1218e-4850-77e0-8370-ecd4926402ff","model":"…","status":"COMPLETED","metrics":{"inference_time":7.422000169754028},"settled":true,"cost_usd":0.03,"units":1,"unit":"megapixel"}

Then fetch the result and download the file the output points at:

bash
curl "https://api.radienthq.com/v1/tools/media/result?request_id=01a1218e-4850-77e0-8370-ecd4926402ff" \
  -H "Authorization: Bearer $RADIENT_API_KEY"
json
{"request_id":"01a1218e-4850-77e0-8370-ecd4926402ff","model":"…","status":"COMPLETED","output":{"images":[{"content_type":"image/jpeg","file_name":"QWj1y0ZmH04O4QYZZEgHF_JngXHa9M.jpg","file_size":null,"height":512,"url":"https://…/QWj1y0ZmH04O4QYZZEgHF_JngXHa9M.jpg","width":512}],"seed":919543088}}

Example bodies on this page come from live calls; … marks a value trimmed here.

#Selecting a model

GET https://api.radienthq.com/v1/tools/media/models is public — no key required. It returns every model you can pass as model, with its display name, type (image or video), billing unit, unit price and a pricing note:

json
{"models":[{"id":"…","display_name":"…","type":"image","unit":"megapixel","unit_price_usd":0.03,"pricing_note":"First output megapixel $0.03; each extra megapixel $0.015 (input and output), rounded to the nearest megapixel (minimum 1).","default":true,"legacy":false}]}

Read the list from the endpoint — model ids and prices change over time. Omit model to use the default ("default": true, an image model today); the response always echoes the model that served your request. legacy: true marks entries kept for older clients.

#Submitting a request

The request body is the selected model's own parameter object, with two reserved keys the platform reads:

FieldTypeRequiredNotes
modelstringNoA model id from /v1/tools/media/models. Empty → the default model. An unknown id is rejected with 400 media_rejected before any generation.
every other field––Forwarded as parameters to the model. Prompt, sizes, counts and seeds are per model; the platform validates and prices the ones that affect cost (below).

Cost-relevant parameters the platform understands on every image model:

FieldTypeNotes
promptstringWhat to generate.
image_sizestring | objectA preset — square_hd (1024×1024), square (512×512), portrait_4_3 (768×1024), portrait_16_9 (576×1024), landscape_4_3 (1024×768, the default), landscape_16_9 (1024×576) — or {"width":…,"height":…} with each edge at most 8192.
num_imagesintegerHow many images to generate, within the model's own limit (a model that produces one output per request rejects anything but 1).
seedintegerReproducibility, where the model supports it.

Anything the platform cannot price is refused up front with 400 media_rejected — you are never charged for a request that could not be quoted. The submission body is capped at 1 MiB (413 past it).

#Editing an image

Choosing the edit model (from GET /v1/tools/media/models; the editing entry's id and display name say so) and passing source image URLs performs image-to-image; image_size must be explicit because the output size cannot be inferred from a URL the platform does not fetch:

json
{
  "model": "YOUR_EDIT_MODEL_ID",
  "prompt": "Make the apple green",
  "image_urls": ["https://…/QWj1y0ZmH04O4QYZZEgHF_JngXHa9M.jpg"],
  "image_size": "square"
}
  • image_urls — one or more source images; the edit model reads this field. A request to an edit model without an explicit image_size is rejected (this fails closed rather than guessing the output price).
  • To animate an image instead of editing it, see Image-to-video.
  • Only output-side megapixels are billed on edits today (see Pricing).

#Job and progress model

A submission returns a request_id, which is the handle for everything else. Poll GET /v1/tools/media/status?request_id=… until the response carries "settled": true; then fetch the output from GET /v1/tools/media/result?request_id=….

Status values are IN_QUEUE, IN_PROGRESS, COMPLETED and CANCELLED. While a request is waiting, queue_position tells you where it is; the status response may also include logs and metrics from the generation service. There is no webhook support — poll at your own cadence (one to a few seconds apart is plenty for images; video takes longer).

The status response fields:

FieldNotes
request_id, modelThe handle and the model serving it.
statusIN_QUEUE, IN_PROGRESS, COMPLETED or CANCELLED.
queue_positionPresent while queued.
settledtrue once a terminal outcome has been recorded; the settled cost_usd / units / unit appear at the same time.
costThe versioned cost object: the quote while unsettled, billed with the settled figure once settled. See Cost reporting.
error, error_typePresent on a failure — see Failures.
metrics, logsGeneration telemetry from the service (latency, and any log lines it publishes).

GET /v1/tools/media/result returns the same header fields plus output — the generated object. Image models return output.images (array of url, width, height, content_type, file_name); the top level carries the seed. The generated object appears once the status is COMPLETED.

Download the file, do not store the URL as your copy. The url points at the generated file on the generation service's storage; fetch it and save the bytes somewhere you control, and treat the link as temporary.

#Pricing

Every submission is quoted before it runs: the submit response's cost_usd / units / unit are the price, and GET /v1/tools/media/models publishes each model's unit_price_usd and a pricing_note describing the arithmetic. Nothing is charged at submit — the quote is only reserved against your balance until the request settles. The same figures travel in the response's cost object: basis quote at submission and while the request is unsettled, billed with the settled figure once settled — see Cost reporting.

How settlement works:

  • The charge is written when the platform observes the terminal state and successfully fetches the result — i.e. on your first poll that sees it done. Poll your requests.
  • Failures cost $0. A generation that fails settles at cost_usd: 0 with error_type: "media_failed".
  • A cancelled request is not automatically free. Cancellation is best-effort: if the job completed anyway, fetching its result settles the full quote.
  • The quote does not change once issued — the number on the submit response is what a completed request charges.

By the megapixel (most image models including the default): the first output megapixel is $0.03 and each extra megapixel $0.015, rounded to the nearest megapixel with a minimum of 1 — so a 512×512 or 1024×1024 image costs $0.03, and a 1920×1080 image $0.045. Per-image models publish a flat unit_price_usd per image (for example $0.08 or $0.15), with per-resolution and add-on multipliers described in the model's pricing_note. Edit models bill the output side only; the input image's megapixels are not charged today.

#Failures and cancellation

A generation that fails is a normal terminal state, not an HTTP error: the status settles with "status": "COMPLETED", an error string, error_type: "media_failed" and cost_usd: 0. Treat any settled failure as retryable.

Cancel with:

bash
curl https://api.radienthq.com/v1/tools/media/cancel \
  -H "Authorization: Bearer $RADIENT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"request_id": "01a12193-1b1f-7ec0-a0cf-52e3e7b31a0d"}'
json
{"request_id":"01a12193-1b1f-7ec0-a0cf-52e3e7b31a0d","model":"…","status":"CANCELLED"}
  • Cancelling is idempotent — repeating it returns the same response.
  • Cancelling an already completed request is a 409 media_already_completed.
  • Cancellation asks the generation service to stop; it is not a guarantee. Measured in practice: jobs cancel while queued and, when the service completes one anyway, the result fetch charges the quote.
  • The cancel answer reports where settlement stands: while a charge can still settle, cost carries the quote and a top-level note carries “If the upstream job completes, the quoted charge will settle; poll /status.”; once settled, cost reports the billed figure and note is absent.
  • There is no restart or resume endpoint. To retry, submit a new request — a new request_id, a new quote.

#Errors

StatusCodeMeaning
400media_rejectedThe request could not be priced or accepted: unknown model, unknown image_size, a count or duration outside the model's range, or an unpriced parameter. Nothing ran, nothing was charged.
400–Malformed JSON or a missing request_id on status/result.
401–Missing or invalid credentials.
402–Insufficient credits — see Radient Pass.
404media_not_foundUnknown request id, or a request that belongs to another account. The two answer identically by design.
409media_already_completedCancel of a completed request.
413payload_too_largeSubmission body over 1 MiB; details.limit_bytes carries the limit.
429media_rate_limitedThe generation service is busy; retry shortly.
503media_unavailableThe generation service is temporarily unavailable — also returned when a submission cannot be reserved, refused before any generation runs.

Real bodies (… marks text trimmed in this page):

json
{"code":"media_rejected","error":"This generation request could not be priced or accepted."}
json
{"code":"media_not_found","error":"This generation request does not exist."}
json
{"code":"media_already_completed","error":"This generation request has already completed."}
json
{"code":"payload_too_large","details":{"limit_bytes":1048576},"error":"…"}
json
{"code":"media_unavailable","error":"Media generation is temporarily unavailable."}
json
{"error":"missing Authorization header"}
json
{"error":"insufficient credits"}

#Legacy image routes

Three routes predate the media API. They forward to the same engine and keep their old response shape, so existing integrations keep working — new work should use /v1/tools/media/*, which has cleaner error semantics and the same prices.

Legacy routeWhat it does
POST /v1/tools/images/generateSubmit; body fields prompt (required, 1–1000 chars), num_images (1–10), image_size, source_url (image-to-image), strength, seed, num_inference_steps, guidance_scale. sync_mode is accepted and ignored — the response has always been a queue handle, never an image.
GET /v1/tools/images/status?request_id=…Status, with cost_usd / units / unit and queue_position added where known.
GET /v1/tools/images/providersLists the available image service ids.

Differences from the media routes worth knowing: the legacy status response returns the images array directly once complete; the additive cost_usd / units / unit fields are absent until the request settles (0 is a settled zero, absent means not yet settled); and the legacy routes surface a rejected request and an unknown request id as HTTP 500 (with media_rejected / media_not_found in the body) rather than 400 / 404.

For the full endpoint list, see the API Reference.