HTTP API

POST /v1/render

An answer you already have, drawn again with no model.

View as Markdown

Keys

Your MorphScreen key in X-MorphScreen-Key: the call counts against your plan.

Example

Draw an answer you already have as HTML, with no model called:

Terminal
curl https://api.morphscreen.com/v1/render \
  -H "X-MorphScreen-Key: $MORPHSCREEN_KEY" \
  -H "Content-Type: application/json" \
  -d '{"text": "## Budget\n\n<Stat label=\"Per day\" value=\"$165\" />\n"}'

The HTML needs no JavaScript and no style attributes, so it passes a strict content security policy. Load morphscreen.css from the web SDK on the page that shows it (HTML without JavaScript).

Request

RenderRequest

An answer you already have, in our format, with the options. output: html (the default), ops or tree. Free, counted, within a fair-use limit.

Field Type Required What it is
text string yes
packs list of string
components list of object
image_hosts list of string
images list of object At most 200.
photos one of the shapes below The app's own photo key, for one provider: with it the model may ask for photos, searched there on the app's quota, each loading from the provider's own address with its credit. Without one (or false) the model isn't asked for photos.
output html, ops, tree

AppImage

One of your own pictures. The model shows it as alt and the API puts its URL and credit in; its host is allowed with it.

Field Type Required What it is
id string yes Letters, digits, '-', '_' or '.'.
url string yes Where it loads from, http(s).
alt string What it shows, told to the model.
credit string Shown under it, as written (Markdown links allowed).

Responses

Status What comes back
200 The answer as HTML, ops or the tree, with the core's verdict.
400 The request can't be run as written; model_needs_your_key: a model other than the included one, asked for without your own OpenRouter key.
401 No key, or one turned down: your MorphScreen key (morphscreen_key_required, morphscreen_key_invalid) or your OpenRouter key (openrouter_key_required, openrouter_key_invalid).
403 The account is suspended (account_suspended), or the model's moderation refused the request (model_refused).
413 The body is over 1 MB (payload_too_large), or a call with the model included has more than about 8,000 tokens of conversation (conversation_too_long).
429 A limit reached, with Retry-After saying how long to wait: requests a minute (rate_limited), answers at once (too_many_streams), the free tier's day (daily_limit_reached), renders this month (render_limit_reached), or OpenRouter's own (openrouter_rate_limited).
503 Accounts can't be read just now; try again.

Errors come back as {"error": {"code", "message", "type", "metadata": {"error_type", "reason"}}}: type is the reason to act on (rate_limited, plan_quota_reached...). Limits and errors says what to do about each.