Create a render
Render an exterior, interior, masterplan, landscape, plan or product from an image, or from a prompt alone.
POST/v2/rendersReturns 202 straight away with the job and what it charged. Poll GET /v2/jobs/{id} for the result; a job that fails is refunded. The price is the engine’s: see Pricing.
Anything accepted but not applied, such as a setting that does not fit the engine, comes back in notes rather than being dropped silently. A field the API does not know is refused before anything is charged.
Sending the image
The image goes in the same call, with no upload step. Every create call takes it the same three ways, and so does each reference, an edit’s mask and a video’s end_frame:
- A file on disk: send the call as multipart form data, with the file as the
imagepart and every other field as a text part. Repeatreferencesfor several references. - A link:
"image": "https://…"in JSON. mnml fetches it. - Bytes in your code:
"image": "data:image/jpeg;base64,…"in JSON, or bare base64.
curl -X POST https://api.mnml.ai/v2/renders \ -H "Authorization: Bearer $MNML_API_KEY" \ -F [email protected] \ -F prompt="Timber facade, late afternoon, olive trees" \ -F [email protected]In a form, numbers and true / false are written as text, and settings or a region as JSON. Images are JPEG, PNG or WebP, up to 15 MB each. To work on an image mnml already made for you, pass its job_id instead: nothing is downloaded or sent again.
Getting the result in the same call
Add ?wait=90 and the answer waits up to that many seconds (90 at most) while the render runs. If it finishes in time, the answer is a 200 and jobs holds every job with its outputs. If it is still running, the answer is the usual 202 with jobs as they stand. Then follow the job as a stream: one connection that stays open until the render is done, however long it takes. How long a render takes depends on the engine: compare the engines on the models page.
curl -X POST "https://api.mnml.ai/v2/renders?wait=90" \ -H "Authorization: Bearer $MNML_API_KEY" \ -F [email protected] \ -F prompt="Timber facade, late afternoon, olive trees" # 200 → data.jobs[0].outputs[0].url is the renderFor a slower engine, a video, or a script that should simply block until the result is ready, skip wait: start the job, then open its stream. It sends the job each time it changes and ends with done and the finished job.
JOB_ID=$(curl -s -X POST "https://api.mnml.ai/v2/renders" \ -H "Authorization: Bearer $MNML_API_KEY" \ -F [email protected] \ -F prompt="Timber facade, late afternoon, olive trees" | jq -r .data.id) curl -N "https://api.mnml.ai/v2/jobs/$JOB_ID/events" -H "Authorization: Bearer $MNML_API_KEY" # event: done → data.outputs[0].url is the renderHeaders
AuthorizationstringRequiredBearer mk_live_…: your API key. See Authentication.Content-TypestringRequiredapplication/json, ormultipart/form-datato send a file.Idempotency-Keystring- Your own key, 1 to 255 visible ASCII characters. A retry with the same key and request within 24 hours returns the first answer instead of running again.
Query parameters
waitinteger- Hold the answer up to this many seconds (1 to 90) while the render runs, and answer with the finished jobs in
jobs. Still running when the time is up: a 202; read the job with GET /v2/jobs/{id}?wait=90 until it settles.
Body
enginestringDefaultv4.6-ultra- An engine id or name from GET /v2/engines.
modestringDefaultexterior- What the image shows. Without an image it defaults to
text-to-render, which renders from the prompt alone.exteriorinteriormasterplanplanlandscapeproducttext-to-render promptstringRequired- What to render: materials, light, season, context.
imagestring- The JPEG, PNG or WebP to work on, up to 15 MB: a public
https://link we fetch, adata:image/…;base64,URI, or bare base64. With multipart form data, attach the file itself (-F [email protected]). Send one ofimageorjob_id. job_idstring- A finished job of yours: work on its output without downloading it first.
referencesstring | object[]- Images whose style, materials, mood or geometry to follow, up to 15. Each is just the image (a link or base64, or with multipart a
referencesfile part, repeated), or an object,{ image | job_id, mode }, that also sets itsmode. How many an engine takes iscapabilities.max_referencesin GET /v2/engines.Fields of each item (3)
imagestring- The reference image: a public
https://link we fetch, adata:image/…;base64,URI, or bare base64. With multipart form data, attach the file itself. Send one ofimageorjob_id. job_idstring- The reference image, as a finished job of yours.
modestringDefaultstyle- What to take from it: its
style, amaterial, theatmosphere, thecoloror thegeometry.autolets the engine decide.autostylematerialatmospherecolorgeometry
settingsobject- Studio’s settings for this engine and mode, as name → value. A setting left out takes the value Studio opens on. A setting that does not apply is listed in
notes, not applied. aspect_ratiostringDefaultauto- The frame.
autokeeps the source image’s shape.auto1:13:24:35:416:921:92:33:44:59:16 countintegerDefault1- Variations of this brief, 1 to 4. Each is its own job and charge;
idslists them. A given seed is stepped for each. seedinteger- Reuse a seed to stay close to an earlier result. Engines that take no seed say so in
notes. webhook_urlstring- A public
https://URL to send this job’s settle event to, signed like every webhook, on top of your account’s endpoints.
Response
On success (202): Started. Poll GET /v2/jobs/{id} for the result. The JSON is { "success": true, "data": … }, and inside data:
idstringRequired- The job. Read it at GET /v2/jobs/{id}. With
count, the first ofids. idsstring[]Required- Every job this call started, one per variation, in order.
statusstringRequired- The job’s status when it was accepted, usually
queued.queuedprocessingsucceededfailedcanceled charged_usdnumberRequired- What this call charged, every variation together, in US dollars.
replayedbooleanRequired- True when this is the stored answer to an earlier identical request with the same
Idempotency-Key: nothing ran or was charged again. See Idempotency. notesstring[]Required- What was accepted but not applied, in plain words: a setting that does not fit the engine, a seed it does not take. Empty when everything applied. When fewer variations started than
countasked for, it says so here. jobsobject[]- Only with
?wait: every job this call started, as GET /v2/jobs/{id} reads it, outputs included. A200means all of them finished in time; a202means some are still running: read each with GET /v2/jobs/{id}?wait=90 until it settles.Fields of each item (10)
idstringRequired- The job’s id, as the create call answered it.
statusstringRequired- Where the job is.
succeeded,failedandcanceledare final: stop polling.queuedprocessingsucceededfailedcanceled kindstringRequired- What the job makes:
render,edit,erase,upscale,enhance,bg-remove,extend(anoutpaint) orvideo. enginestring | nullRequired- The engine’s mnml name for a render or an edit;
nullfor an enhancement, an erase or a video. outputsobject[]Required- The results, once the job has
succeeded; empty before that, and on failure.Fields of each item (3)
urlstringRequired- A signed link to the file at GET /v2/files/{id}. It needs no key.
mediastringRequired- Whether the file is an image or a video.
imagevideo expires_atstringRequired- When the link stops working, as an ISO 8601 time. Poll again for a fresh one, and download what you keep.
charged_usdnumberRequired- What the job charged when it started, in US dollars.
refunded_usdnumberRequired- What came back when the job failed or was cancelled, in US dollars; 0 otherwise.
errorobject | nullRequired- Why the job failed or stopped;
nullotherwise.Fields (2)
codestringRequired- A stable code to branch on. See When a job fails.
UNSAFE_CONTENTNO_CHANGECANCELEDRENDER_FAILED messagestringRequired- The same in plain words, for a person.
created_atstringRequired- When the job was accepted, as an ISO 8601 time.
completed_atstring | nullRequired- When it reached a final status, as an ISO 8601 time;
nullwhile it runs.
Response headers (5)
X-Request-Idstring- This request, for support and the console log.
RateLimit-Limitinteger- Requests this key may make per minute.
RateLimit-Remaininginteger- Requests left in the current minute.
RateLimit-Resetinteger- Seconds until the current minute resets.
Idempotent-Replayedstring- Present, as
true, when this is the stored answer to an earlier request.
Status codes
- 200
- Finished, within ?wait: every job, with its outputs, is in jobs.
- 202
- Started. Poll GET /v2/jobs/{id} for the result.
- 401
- The API key is missing, malformed, unknown or revoked.
- 402
- The balance does not cover this call.
- 409
- The Idempotency-Key was reused for a different request, or is still in progress.
- 429
- A limit was reached: requests per minute, or a daily or concurrency limit.
- Other
- Any other error, in the same envelope.
Every error answers { "success": false, "error": { "code", "message" } }. What each code means, and what to do, is on Errors.