AI assistant
The AI assistant makes pictures, videos and fonts, and writes texts as JSON, with the AI services a workspace has connected. Through the API it is a forwarder: you send a request, Reelwire passes it on to OpenAI, Google, Black Forest Labs, BytePlus or Anthropic with the workspace's own key for that service, and hands back what came out. The service bills the workspace's own account; Reelwire adds nothing. See AI assistant in the Dashboard chapter for the models and where each service's key is made.
| Method | Path | Permission |
|---|---|---|
GET | /v1/ai/models | ai:read |
POST | /v1/ai/generate | ai:write |
POST | /v1/ai/chats | ai:write |
GET | /v1/ai/chats | ai:read |
GET | /v1/ai/chats/{id} | ai:read |
POST | /v1/ai/chats/{id}/messages | ai:write |
POST | /v1/ai/chats/{id}/stop | ai:write |
POST | /v1/ai/results/{id}/keep | ai:write |
The permission is Media - AI assistant on the API keys screen. Keeping a result writes it into the media library, and needs only this permission.
The keys for the services are not reachable by any API key. /v1/ai-keys belongs to a signed-in
owner or admin, on the API keys screen: a key that could set them could spend the workspace's money
at another company.
Which models can be used
curl https://app.reelwire.io/v1/ai/models -H "Authorization: Bearer $REELWIRE_KEY"
Every model is listed, whether or not the workspace has a key for its service. configured: true
means it can be used now: its service has a key in the model's own section (image, video, sound for
music, or text and font) on the API keys screen. A key saved for one section switches on no other, so a workspace
can have Google's pictures and not its videos. Each provider lists the sections it has a key in
(configuredSections). Each model says what it makes (kinds: image, video, sound, font, text),
a line on what it is for (about), the shapes (aspectRatios) and lengths (durations) it makes,
how many pictures one message may ask for (maxCount), whether it can change a picture
(references) or make a clear background (transparent), whether a video has sound (audio, and
audioAlways where it cannot be switched off), and whether it starts and ends on a picture you
choose (firstFrame, lastFrame, with frameNote where there is something to know), and
whether a piece of music can have singing (vocals).
The same, as a table per model, is under Settings per model in the Dashboard chapter.
There are no prices in the answer: they are each service's own and change often. Every provider in
it carries pricingUrl, the address of that service's price list.
Making something
A chat is one conversation with one model about one thing. POST /v1/ai/generate starts one and
sends its first message:
curl https://app.reelwire.io/v1/ai/generate \
-H "Authorization: Bearer $REELWIRE_KEY" -H "Content-Type: application/json" \
-d '{
"kind": "image",
"model": "google/gemini-3.1-flash-image",
"prompt": "A flat, minimal fox in orange, for a finance brand",
"options": { "aspectRatio": "1:1", "count": 2 },
"purpose": { "label": "Logo", "brief": "The logo of Northwind Markets" }
}'
It answers 202 at once, with the chat and a turn in state RUNNING. The work happens in the
background: ask GET /v1/ai/chats/{id} until the turn is DONE, FAILED or CANCELLED.
POST /v1/ai/chats/{id}/stop stops the message being answered and answers with the chat: the turn
becomes CANCELLED, nothing from it is kept, and the service is asked to cancel where it allows that
(a service that cannot be cancelled may still finish, and bill, the request on its side). It answers
409 when nothing is running. Pictures and texts take seconds to a minute; videos one to four
minutes, so poll every ten seconds or so.
| Field | For |
|---|---|
kind | image, video, sound (music, answered as an MP3), font or text. |
model | A model id from /v1/ai/models that makes this kind. |
prompt | What to make, up to 4000 characters. |
options.aspectRatio | The shape, "w:h". The nearest one the model makes is used. |
options.count | Pictures in one go, 1 to 4, each billed. |
options.durationSeconds | A video's or a piece of music's length, up to 190 seconds. The nearest the model makes is used. |
options.transparent | A clear background, where the model can. |
options.audio | Sound in a video, where the model can. Veo always has sound. |
options.vocals | Singing in a piece of music, where the model can (vocals: true). Instrumental otherwise. |
options.refine | A picture result of this chat to change, by its id. |
options.reference | A picture from the media library to change, on a model with references: a PNG, JPEG or WebP, media://<id>. Not together with refine. |
options.firstFrame | For a video on a model with firstFrame: a PNG, JPEG or WebP picture from the media library, media://<id>, that the video starts on. |
options.lastFrame | The picture it ends on, on a model with lastFrame, and only together with firstFrame. |
purpose | What the chat is for, sent with every message: label, brief, aspectRatio, transparent, language, and for a text format. place says where it was opened, and is only logged. |
POST /v1/ai/chats with kind, model and purpose starts a chat without a message (201), and
POST /v1/ai/chats/{id}/messages with prompt and options sends the next one: "make the
background blue". The model is given the earlier requests of the chat. A chat answers one message at
a time: sending another while one is running is a 409. Sending, on either route, is limited to 30
messages a minute, because every one costs money at the service.
GET /v1/ai/chats lists the 50 most recent chats of the last day, each with its label, how many
messages it has had and when it expiresAt.
What comes back
{
"chat": {
"id": "01M37DK0NAPXE2GV9APHS8GT71",
"kind": "image",
"model": "google/gemini-3.1-flash-image",
"expiresAt": "2026-09-24T15:19:16.403Z",
"turns": [
{
"id": "01M37DK0NG22D4...",
"prompt": "A flat, minimal fox in orange, for a finance brand",
"state": "DONE",
"error": null,
"results": [
{
"id": "01M37DK0P8...",
"name": "ai-7kq3mz9xfp.png",
"mimeType": "image/png",
"byteSize": 812345,
"width": 1024,
"height": 1024,
"url": "https://app.reelwire.io/v1/assets/01M37DK0P8.../download?exp=...&sig=...",
"kept": null
}
]
}
]
}
}
A picture, video or font has a signed preview url, good for an hour. A picture or video is named
ai- and ten random letters and digits; a font is named after its family, such as
Northwind-Sans-Regular.otf. A text has its answer in data instead. A FAILED turn says why in
error, in the service's own words where it gave some: a refused key, an account out of credit, a
prompt its safety check stopped.
Results are proposals, kept for a day after the chat was last used, outside the media library and its storage. Keep the ones you want:
curl -X POST https://app.reelwire.io/v1/ai/results/01M37DK0P8.../keep \
-H "Authorization: Bearer $REELWIRE_KEY" -H "Content-Type: application/json" -d '{"name": "fox-logo"}'
It answers 201 with the library file, whose ref (media://...) is what a brand slot or a
template's content takes, and the workspace's storage. name is optional; without it the result
keeps its own name. A kept file meets the library's own rules: the storage allowance, pictures up to
2048 by 2048 pixels, videos up to 5 MB. Keeping it again answers with the file already kept and
already: true, rather than a second copy. A text has no file to keep, and keeping one is a 409.
Texts: JSON that fits a schema
A text chat answers with JSON and nothing else, and needs purpose.format.schema: the JSON Schema
the answer must match. The model is told the schema, and its answer is checked against it before you
see it; an answer that does not fit is sent back once with the reasons, then the turn fails.
{
"kind": "text",
"model": "anthropic/claude-opus-5-5",
"prompt": "Announce the summer sale, friendly and short",
"purpose": {
"label": "Texts on the clip",
"language": "de",
"format": {
"schema": {
"type": "object",
"properties": {
"headline": { "type": "string", "maxLength": 60 },
"subline": { "type": "string", "maxLength": 120 }
},
"required": ["headline", "subline"],
"additionalProperties": false
},
"instructions": "headline: the first line on the clip. subline: the line under it.",
"current": { "headline": "Sommer", "subline": "" }
}
}
}
instructions says what each field is for, example gives an example of good content, and current
what is written now, so a message like "shorter" has something to shorten. The schema may be up to
20,000 characters.
Fonts
A font chat has a text model draw a new typeface: every capital, lowercase letter, digit and common
sign as an outline on a fixed grid. Reelwire builds an OpenType file (font/otf) from the drawing and
checks it by reading it back. One font per message, and it takes a few minutes. The result's data
holds family, description, glyphs (how many were drawn) and missing (characters the drawing
left out, which fall back to another font); the turn's reply names them too. A request to change it
("bolder") draws the whole font again.
Through an assistant
The MCP server offers the same as tools: reelwire_ai_models, reelwire_ai_generate,
reelwire_ai_reply, reelwire_ai_chat, reelwire_ai_stop and reelwire_ai_keep. See
MCP tools.