> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.aegi.run/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.aegi.run/_mcp/server.

# Canvas

A canvas model is a PNG template you lay out visually: canvas size, background,
images, shapes, text, and fonts. The API does not create models. It renders one
that already exists in your project, optionally filling in parameters.

## Building a model

Models live in a project on [aegi.run](https://aegi.run). Open the project's
**Canvas** tab and save the document you want to render. When you open a saved
model, the address bar carries its id:

```
https://aegi.run/dash/p/<projectId>/canvas/editor?model=<modelId>
```

That `modelId` is what the render endpoint takes. Images and fonts you add in
the editor are uploaded to Aegis's file service and referenced by URL, so the
model itself stays small.

## Rendering

```
POST /v1/canvas/render/{modelId}
```

The body is optional. `values` fills the parameters the model declares:

```json
{
  "values": {
    "player": "Aegis",
    "avatar": "https://example.com/avatar.png"
  }
}
```

The SDK has no canvas resource yet, so post it directly and collect the job with
the client you already have:

```ts
const response = await fetch(
  `https://api.aegi.run/v1/canvas/render/${modelId}`,
  {
    method: 'POST',
    headers: {
      authorization: `Bearer ${process.env.AEGIS_API_KEY}`,
      'content-type': 'application/json',
    },
    body: JSON.stringify({
      values: { player: 'Aegis', avatar: 'https://example.com/avatar.png' },
    }),
  },
)

const { data } = await response.json()
const { result } = await aegis.jobs.wait(data.jobId, { timeout: 60 })
```

The response confirms the queue, not the render:

```json
{
  "success": true,
  "data": {
    "jobId": "3f8a1c8e-5b7d-2049-af31-c6e8d5b90742",
    "status": "pending",
    "modelId": "9a6c1c8e5b7d2049af31c6e8d5b90742"
  }
}
```

Canvas jobs have type `canvas`, and `result` is:

```json
{
  "fileId": "9c1e8a4b-2f6d-4a91-9b3c-0d5e7f1a2b4c",
  "fileUrl": "https://files.aegi.run/9c1e8a4b.png",
  "mime": "image/png"
}
```

The output is a still PNG at the model's canvas size.

## Parameters

A parameter has a key, a kind (`text` or `image`), and optionally a default
value, `required`, and a regular expression. Text parameters replace
`{{key}}` tokens in text elements. Image parameters fill the image elements
that point at them.

* Every value is a string. A text value is limited to 2,000 characters.
* An image value is an `http(s)` URL or a base64 data URL (`png`, `jpeg`, `gif`,
  `webp`, `avif`), up to 10 MB.
* Keys the model does not declare are ignored, not rejected.
* A missing value falls back to the parameter's default. If it is required and
  has no default, the request fails with `400`.
* A value that does not match the parameter's pattern also fails with `400`.
* A request carries at most 50 values, and at most 12 MB of them.

## Limits

| Limit                | Value               |
| -------------------- | ------------------- |
| Canvas size          | 16–4096 px per side |
| Elements             | 500                 |
| Fonts                | 50                  |
| Parameters           | 50                  |
| Remote image or font | 12 MB, 30 s         |

Remote sources are fetched by the worker, not by the browser. Loopback, private,
link-local and `.local`/`.internal` hosts are refused, so a render cannot reach
the network Aegis runs on.

## Errors

| Status | Cause                                                                 |
| ------ | --------------------------------------------------------------------- |
| `400`  | A required value is missing, malformed, or does not match its pattern |
| `404`  | No model with that id in the project                                  |
| `413`  | The request body is too large                                         |
| `422`  | The saved model is not a valid canvas document                        |
| `503`  | The render queue is unavailable                                       |

Models are project scoped: a key can only render models in its own project.

## Cost

Canvas renders are in the `canvas` class: 10 per minute on `free`, up to 1,000
on `scale`, and they also count against the aggregate budget. See
[rate limits](/rate-limits).