HTTP API
POST /v1/render
An answer you already have, drawn again with no model.
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:
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 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.