Build with the API

Media generation

Generate images synchronously and video, music, code builds, walkable 3D rooms from a few photos or a video, and research as jobs.

Images (sync)

Image generation is synchronous: the response carries the finished image. Pick an engine or omit it — the default is theo-ultra on paid plans (Free-plan calls fall back to theo-creative and the response says so):

Request body
promptrequired
string
engine
auto | theo-creative | theo-imagine | theo-photo | theo-rapid | theo-design | theo-studio | theo-type | theo-ultra | grok-theo
Default: theo-ultra on paid plans (theo-creative on Free). grok-theo is the Grok + Theo co-brand engine, available on workspaces that enable it.
aspectRatio
1:1 | 16:9 | 9:16 | 4:3 | 3:4
style
string
referenceImageUrls
array<uri> (max 5)
Anchor the render on reference images.
includeBase64
boolean
Also return the bytes inline.
curl
curl https://www.opencharts.com/api/v1/images \
  -H "Authorization: Bearer $OPENCHARTS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "prompt": "Isometric pixel-art data center, neon accents", "aspectRatio": "16:9" }'

Theo Moonlight (our own model)

POST /images/moonlight renders on Theo Moonlight, the first-party image model OpenCharts serves on its own hardware. It is the endpoint to point a benchmark or an arena at: synchronous, seedable, and with only a prompt it renders at the model's published defaults (1024x1024, 8 steps, guidance 1). The response carries the PNG bytes and the seed that was used; nothing is stored for you.

Request body
promptrequired
string
negativePrompt
string
Not used by this model. Leave it out or send an empty string; a non-empty value is refused with a 400.
aspectRatio
1:1 | 3:4 | 4:3 | 2:3 | 3:2 | 9:16 | 16:9
Default 1:1. Every shape renders at about one megapixel.
seed
integer
Fix it to reproduce a render; omit for a random one. The response echoes the seed used.

Safe-for-work only

This endpoint renders safe-for-work images. A prompt describing adult content is refused with a 400 before anything renders, and a finished render the safety check scores as adult is refused with a 403. Neither is charged.

curl
curl https://www.opencharts.com/api/v1/images/moonlight \
  -H "Authorization: Bearer $OPENCHARTS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "prompt": "A lighthouse keeper reading by lamplight, rain on the window, oil painting", "seed": 42 }'

Videos

Video renders return a 202 job envelope immediately:

Request body
promptrequired
string
aspectRatio
16:9 | 9:16
modelTier
fast | max
referenceImageUrl
uri
Anchor the first frame on an image.

Songs

Request body
stylerequired
string
The sound you want, in plain words.
title
string
lyrics
string
Bring your own lyrics.
autoLyrics
boolean
Let the songwriter write them.
instrumental
boolean
tier
auto | premium | fast

Completed jobs return two versions, each with audio, cover art, and a Theo-branded engine label.

Code builds

Build a full Code Canvas project (site or app) from a prompt; the finished project opens in the OpenCharts editor:

Request body
promptrequired
string
name
string
framework
html | react | auto
planFirst
boolean
Draft an architecture plan before building.

Real World spaces (photos or a video of a room, a walkable 3D space)

POST /real-world/spaces turns photos of ONE room into an imagined, walkable 3D room on Theo Real World. Send up to eight photos taken from one spot, turning between shots so each overlaps the last (imageUrls), or one short video of the room (videoUrl), and Theo works out where each photo was taken, builds the room, and imagines every wall, floor and corner the photos did not show. The job answers in two tiers on the same space_ job: a walkable quick room lands on the poll while the job is still processing (about a minute and a half), and the full room at real scale (with metricScale, a 360 panorama and a collider mesh) completes it a few minutes later. One photo alone (imageUrl) builds a room too; on a deployment without the room engine it becomes a measured, imagined, walkable space instead, with the 360 preview and the room's dimensions first.

Request body (exactly one input)
imageUrls
uri[] (1 to 8)
Photos of ONE room (JPEG, PNG or WebP) as http(s) URLs the server can fetch, in the order they were taken. Another room is another request.
videoUrl
uri
One video of the room (MP4, MOV or WebM; 30 seconds and 100 MB or less). The whole input; send no photos beside it.
imageUrl
uri
ONE photo. Wide and level, with the floor and a wall in view; a corner gives the truest measurements on the one-photo space engine.
quality
preview | full
preview stops at the first tier (the quick room, or the 360 panorama plus the dimensions); full (default) continues to the final tier and costs more.
title
string
Optional label for the job; a room also reads it as a short description.

Honest about what is imagined

The photos are the only real part. Every result carries imagined: true. A room is truest where the photos looked; a one-photo space's dimensions are estimates with a confidence each (monocular scale is typically within 5 to 15 percent), and a wall the photo did not show makes a value a floor, flagged lowerBound: true. Say so to your users too. A photo of an object or a person is not a space; captures are not on this API.

curl
curl https://www.opencharts.com/api/v1/real-world/spaces \
  -H "Authorization: Bearer $OPENCHARTS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "imageUrls": ["https://example.com/photos/living-room-1.jpg", "https://example.com/photos/living-room-2.jpg", "https://example.com/photos/living-room-3.jpg"], "quality": "full" }'
poll result (GET /jobs/space_...), once complete (stage preview while processing)
{
  "stage": "space",
  "imagined": true,
  "source": "photos",
  "photoCount": 3,
  "panoramaUrl": "https://www.opencharts.com/api/canvas-video/...",
  "spaceUrl": "https://www.opencharts.com/api/canvas-video/...",
  "spaceFullUrl": "https://www.opencharts.com/api/canvas-video/...",
  "format": "spz",
  "metricScale": 1.38,
  "floorOffsetM": 1.351,
  "colliderUrl": "https://www.opencharts.com/api/canvas-video/...",
  "depthUrl": null,
  "posterUrl": "https://...",
  "gaussians": null,
  "dimensions": null,
  "engine": "Theo Real World 1.1"
}

Register a webhook for space.completed / space.failed to be told when the job ends instead of polling. A completed job may stay at stage: preview when only the preview was asked for, or when the walkable tier did not finish; the result's notes say so. The full walkthrough, from the key to rendering the splat, is the Real World spaces guide.

Deep research

Multi-step web research with citations, returned as a markdown report plus sources:

Poll research like every other job at GET /jobs/{id} using the returned res_… id. The legacy GET /research/{jobId} path stays for older integrations: it accepts both id forms and returns its original (pre-jobs) response shape.

curl
curl https://www.opencharts.com/api/v1/research \
  -H "Authorization: Bearer $OPENCHARTS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "query": "State of AI-native documentation tooling in 2026" }'

Idempotent retries

Every generation POST accepts Idempotency-Key

Retries with the same key replay the original response: the async job creators return the same job (billed once), and the synchronous /images + /extract-flowchart replay the original finished result. Pair with webhooks for a fully event-driven pipeline. See Idempotency.