API reference
Every route lives at the root, unversioned, so placeholder URLs stay as short as possible. Synth-at-edge GETs are public; AI writes need an API key.
Conventions
{w}x{h}matches a strict[0-9]+x[0-9]+shape, e.g.400x300. Dimensions are clamped toMAX_DIM(2048).- Hex values are
rgborrrggbbwith no leading#in the path; query params may include or omit it. - Synth responses are
Content-Type: image/svg+xmland cachedpublic, max-age=31536000, immutable. - Identical URLs return byte-identical output. AI prompts are never placed in URLs (that's why submit is a
POST) and full prompts are not logged.
Synth-at-edge (public, SVG)
Pure functions of the URL. No auth, instant, free.
| Method | Route | Query params | Access |
|---|---|---|---|
| GET | /{w}x{h}Boring dimension-labelled placeholder. | text, bg, fg | public |
| GET | /color/{hex}/{w}x{h}Solid color fill. | — | public |
| GET | /gradient/{w}x{h}Linear (with angle) or radial gradient. | from, to, angle, type=linear|radial | public |
| GET | /seed/{seed}/{w}x{h}Deterministic, stable variation derived from the seed string. | — | public |
| GET | /glyph/{w}x{h}Wireframe icon placeholder. | as=avatar|photo|video|product|map|document | public |
Examples
GET /400x300 GET /600x240?text=hero+banner&bg=111827&fg=9aa0b4 GET /color/7c9cff/400x300 GET /gradient/600x400?from=7c9cff&to=59e3c5&angle=120 GET /gradient/600x400?from=7c9cff&to=59e3c5&type=radial GET /seed/precious-tide/400x300 GET /glyph/300x300?as=avatar
Async AI
A job pipeline. Submitting a prompt returns a stable URL immediately; the image fills in later via a provider webhook. The URL never changes.
| Method | Route | Notes | Access |
|---|---|---|---|
| POST | /aiSubmit a prompt. Returns {id, url, status_url}. | — | API key |
| GET | /ai/{w}x{h}/{id}.pngPlaceholder while pending, final PNG once ready. Stable across the job's lifetime. | — | public |
| GET | /ai/{id}/statusJob state JSON: pending | generating | ready | failed. | — | public |
| POST | /ai/replicate-webhookProvider → service. Signature-verified. Not called by clients. | — | API key |
Submit a job
POST /ai
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json
{
"prompt": "a red fox in snow, cinematic lighting",
"w": 512,
"h": 512,
"seed": 42, // optional
"model": "..." // optional, defaults to flux-schnell
}
→ 200 OK
{
"id": "a1b2c3d4e5f6g7h8",
"url": "/ai/512x512/a1b2c3d4e5f6g7h8.png",
"status_url": "/ai/a1b2c3d4e5f6g7h8/status"
}Poll for completion
GET /ai/a1b2c3d4e5f6g7h8/status
→ { "state": "pending" } // queued
→ { "state": "generating" } // prediction running
→ { "state": "ready", "url": "/ai/512x512/{id}.png" } // done
→ { "state": "failed", "error": "..." } // gave upRe-submitting the same prompt + dimensions + model + seed returns the same id and does not start a second generation. A blocked prompt returns 422 with a "blocked" glyph rather than a broken image.
Drop-in <ai-img> component
A framework-agnostic custom element. It renders a placeholder immediately, polls status_url with exponential backoff (500ms → cap 5s), and swaps in the final image on ready — no manual refresh. The raw URL stays usable without it.
<script type="module">
import { registerAiImg } from '/components/ai-img.js'
registerAiImg()
</script>
<!-- Prompt mode: POSTs to /ai, then polls -->
<ai-img prompt="a red fox in snow" w="512" h="512" api-key="YOUR_KEY"></ai-img>
<!-- URL mode: you already have a stable URL + status URL -->
<ai-img
src="/ai/512x512/{id}.png"
status="/ai/{id}/status">
</ai-img>| Attribute | Description |
|---|---|
prompt | Prompt text. Triggers POST /ai unless src is set. |
w, h | Dimensions (default 400×300). |
src | Explicit image URL; skips POST. |
status | Explicit status_url to poll (used with src). |
endpoint | Service base URL (default: same origin). |
api-key | Bearer token for POST /ai (prompt mode only). |
seed, model | Optional overrides forwarded to POST /ai. |
alt | Alt text for the rendered image. |
Events: ai-img:ready and ai-img:failed bubble from the element. The current state is also reflected on the data-state attribute.
Health
| Method | Route | Response |
|---|---|---|
| GET | /healthz | { "ok": true } |