Documentation

Working with
the render route

One route handles every model and both output types. Rendering is asynchronous — you get a job id back before the file exists, then poll or wait for a webhook.

01 Quickstart

Connect a wallet on Robinhood Chain and you have an account. There is no signup, no email, and no API key to generate — requests are authenticated by a signature from your address.

// POST /api/render
{
  "prompt": "a kestrel mid-downstroke, backlit",
  "model": "standard",
  "ratio": "16:9"
}

// 202 Accepted
{ "id": "rnd_8f2c41", "state": "queued", "cost": 2, "balance": 10 }

Then poll GET /api/render/rnd_8f2c41 until state is terminal. On the fast models that is usually two or three polls.

02 Credits

A credit is the unit you spend on a render. Every address gets 2 free credits per calendar month, reset on the first. Unused credits do not carry over.

Cost is charged when the job is accepted, not when it completes, and refunded automatically if it fails. That ordering is deliberate: charging on completion would let one address queue unlimited concurrent jobs against a balance it does not have.

Worth knowing

Your balance drops the moment you send the request. If you cancel a job mid-render the credits come back, minus nothing — cancellation is free.

03 The render route

Every model goes through POST /api/render. Changing engines means changing one string, not rewriting your integration.

MethodPathDoes
POST/api/renderStart a job. Returns 202 with a job id.
GET/api/render/:idRead one job, including its file URL once ready.
DELETE/api/render/:idCancel a queued or rendering job. Credits refunded.
PATCH/api/render/:idSet visibility to public or private.
GET/api/rendersList your jobs. Paginated, newest first.
GET/api/exploreThe public feed. No wallet needed.

04 Parameters

Everything except prompt has a default. Send only what you want to change.

FieldAcceptsNotes
promptstring, 1–1200 charsRequired. Over the limit returns 400 — nothing is silently truncated.
modelturbo · standard · fidelityDefaults to standard.
ratio1:1 · 16:9 · 9:16 · 4:3 · 3:2Defaults to 1:1.
output_formatjpeg · pngDefaults to jpeg. PNG is lossless and costs the same — use it when the image contains text.
typeimage · videoDefaults to image. See the video flag below.
seedintegerReuse a seed with the same prompt and model for a near-identical render. Omit for random.
visibilityprivate · publicPublic renders appear at /r/:id and in Explore. Defaults to private.

05 Job states

A job only moves forward. It never returns to an earlier state, so you can stop polling the moment you see a terminal one.

queuedrenderingreadyfailedcancelledrefunded
StateTerminalMeaning
queuednoAccepted and paid for. Waiting on capacity.
renderingnoSent to the engine.
readyyesurl is populated and the file is stored against your address.
failedyeserror says what went wrong in plain language.
cancelledyesYou called DELETE before it finished.
refundedyesCredits returned. Follows every failed and cancelled job automatically.

06 Webhooks

Rendering is driven by a webhook from the engine, not by a background worker. The engine signs its callback with Ed25519 and the route verifies that signature before it reads a single field.

// the job object you poll
{
  "id": "rnd_8f2c41",
  "state": "ready",
  "url": "https://…supabase.co/storage/v1/object/public/renders/…",
  "model": "standard",
  "seed": 418207,
  "cost": 2
}
Why the URL looks like that

The engine's own file URLs expire. Every finished render is copied into our storage bucket and it is that copy you get back — a link you saved a month ago still works.

07 Models

ModelCostOutputUse it for
turbo11024px image, ~4sFastest route. Good for iterating on a prompt before committing.
standard21536px image, ~8sBalanced quality and cost. The default for most renders.
fidelity42048px image, ~18sHighest detail and prompt adherence. Slower, worth it for finals.
motion85s clip, 1080pLocked until launch.
motionpro168s clip, 1080pLocked until launch.

There is no separate model for images with text in them. Set output_format to png instead: the engine is the same, the cost is the same, and the lettering survives because nothing is thrown away in the encoding.

08 Video flag

Video generation is complete. The route accepts it, the queue handles it, the gallery displays it. A single flag keeps it shut until token launch.

While the flag is off, type: "video" returns 423 Locked — not 404. The capability exists; it is withheld. Your integration can send video requests today and start working the day the flag flips, without a deploy on your side.

If you are implementing this

The flag has to be read server-side on every request. Hiding the tab in the interface is not a lock — anyone with devtools can post type: "video" straight at the route.

Video also carries a daily cap while it is subsidised. Once the day's clips are used up the route answers daily_cap_reached and image renders carry on untouched. The day rolls over at midnight Jakarta time.

Credits held when the flag flips spend on video at the published rate. Nothing expires and nothing is reset at launch.

09 Errors

Errors are plain objects with a machine-readable code and a sentence you can show a person without rewriting it.

StatusCodeMeans
400prompt_too_longOver 1200 characters. Nothing was charged.
400unknown_modelThe model string does not match any route.
402insufficient_creditsBalance is below the job cost. Includes needed and balance.
423video_lockedVideo is built but switched off. Try again after launch.
429daily_cap_reachedThe day's video budget is spent. Image renders are unaffected.
429rate_limitedIncludes retry_after in seconds. Wait and resend.
500engine_failedThe engine returned nothing. Credits already refunded.
502upstream_failedThe engine would not accept the job. Credits already refunded.

10 Limits

Limits keep the free tier free. They are per address and enforced server-side.

LimitValue
concurrent2 jobs per address
rate20 requests per minute per address
prompt1200 characters
storageRenders kept 90 days on the free tier
new addressFirst render available immediately. No waiting period, no minimum balance.

A brand-new wallet is a first-class case, not an edge case. Most people arrive with one.