> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tavus.io/llms.txt
> Use this file to discover all available pages before exploring further.

# PAL Canvas configuration

> Full reference for the magic_canvas skill on PALs: attaching it, the component overlay, the skills API, and every validation error.

To configure **Magic Canvas**, attach the `magic_canvas` skill to the PAL. The skill controls which Canvas components the PAL may use; the PAL decides at runtime when to show one.

Attaching the skill enables every component with defaults; there is no per-component opt-in. Audio-only, chat, and external-meeting conversations never get Canvas actions; see [how the configuration reaches a conversation](#how-the-configuration-reaches-a-conversation).

## Attaching the Skill

Attach with a single `PUT`:

```bash theme={null}
curl -X PUT https://tavusapi.com/v2/pals/{pal_id}/skills/magic_canvas \
  -H "x-api-key: <your-api-key>" \
  -H "Content-Type: application/json" \
  -d '{ "config": {} }'
```

```json theme={null}
{
  "skill_id": "magic_canvas",
  "config": {},
  "attached_at": "2026-06-10T17:04:52.183947+00:00",
  "updated_at": "2026-06-10T17:04:52.183947+00:00"
}
```

Common configurations, shown as the PAL's `skills` value:

```json theme={null}
// Everything on, defaults (scheduling_embed inactive: needs config)
"skills": { "magic_canvas": { "config": {} } }
```

```json theme={null}
// Everything on + the scheduling embed configured
"skills": { "magic_canvas": { "config": {
  "components": { "scheduling_embed": { "provider": "calendly", "scheduling_url": "https://calendly.com/x/30min" } }
} } }
```

```json theme={null}
// Everything except chart
"skills": { "magic_canvas": { "config": {
  "components": { "chart": { "enabled": false } }
} } }
```

```json theme={null}
// Everything on + guidance on when to show cards
"skills": { "magic_canvas": { "config": {
  "usage_guidance": "Show a chart whenever you compare numbers; ask with a question card before booking."
} } }
```

## Component Overlay

`config.components` is a sparse overlay, not an allowlist. Components you don't mention stay enabled with defaults. Add an entry to:

* **Configure a component**: for example, set `scheduling_url` on `scheduling_embed`.
* **Disable a component**: set `{ "enabled": false }`.

New components Tavus adds later are enabled automatically on PALs with the skill attached. Disable them per component to opt out.

<Note>
  `scheduling_embed` only activates once `scheduling_url` is set. Attaching the
  skill without that config doesn't error; the component stays inactive.
</Note>

`config` is strictly validated: an unknown component name or stray field returns `400`. A misspelled skill id in the URL returns `404`: `Unknown skill '...'` on `PUT` and `PATCH`, the not-attached `404` on `GET` and `DELETE`.

## When cards appear

There is no API to show a specific card. The PAL chooses when to call a Canvas action during the conversation. You influence that in three places:

| Lever                  | Where                                                                                                       | Best for                                                                                                                |
| ---------------------- | ----------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
| `usage_guidance`       | `config.usage_guidance` on the `magic_canvas` skill (the **When to use Magic Canvas** field in the builder) | Canvas-specific rules, for example "show a chart when you compare numbers" or "ask with a question card before booking" |
| System prompt          | The PAL's main prompt                                                                                       | Persona, conversation flow, and broader guidance on when UI helps                                                       |
| Conversational context | `conversational_context` at conversation create                                                             | Session-specific facts (availability, user details) the PAL can use when picking a card                                 |

Tavus appends `usage_guidance` to the Canvas system prompt. It is ignored when blank or when no component is active.

Start by disabling components the PAL should not use (`config.components.<name>.enabled: false`). An enabled component can still appear even if your prompts never mention it.

```json theme={null}
{
  "config": {
    "usage_guidance": "Show a chart whenever you compare numbers; ask with a question card before booking."
  }
}
```

## Components

Each active component gives the PAL one action named `canvas_show_<component>` (for example, `canvas_show_question`). When at least one component is active, the PAL also gets `canvas_clear`. See the [components overview](/sections/conversational-video-interface/magic-canvas/components) for descriptions and per-component reference.

Every card renders inline in the `safe-area-right` side rail next to the PAL video. Placement is client-side; the PAL does not choose the side. Only one card is on screen at a time: showing a card replaces whatever is currently displayed.

### Component Fields

| Field            | Type    | Required | Description                                                                                                                      |
| ---------------- | ------- | -------- | -------------------------------------------------------------------------------------------------------------------------------- |
| `enabled`        | boolean | ❌        | Accepted by every component. Defaults to `true`. Set `false` to disable the component.                                           |
| `provider`       | string  | ❌        | `scheduling_embed` only. Defaults to `"calendly"`, the only supported provider.                                                  |
| `scheduling_url` | string  | ❌        | `scheduling_embed` only. Your booking link, delivered to the embed exactly as configured. Defaults to `""` (component inactive). |

### `scheduling_url` Rules

A non-empty `scheduling_url` must be a public HTTPS URL:

* Must start with `https://` and include a hostname.
* At most 2048 characters.
* `localhost` and cloud metadata hostnames (such as `metadata.google.internal`) are rejected.
* IP-based hosts (including hex and other numeric encodings) in private, loopback, link-local, or otherwise internal address space are rejected.
* An empty string is allowed and means "not configured yet."

## Skills API

Skill attachments live under `/v2/pals/{pal_id}/skills`. Full HTTP reference:

* [List PAL skills](/api-reference/pal-skills/list-pal-skills)
* [Get PAL skill](/api-reference/pal-skills/get-pal-skill)
* [Attach skill to PAL](/api-reference/pal-skills/attach-skill-to-pal)
* [Update PAL skill](/api-reference/pal-skills/update-pal-skill)
* [Detach skill from PAL](/api-reference/pal-skills/detach-skill-from-pal)
* [Replace PAL skills](/api-reference/pal-skills/replace-pal-skills)

Endpoints:

| Method & path                                | What it does                                                 |
| -------------------------------------------- | ------------------------------------------------------------ |
| `GET /v2/pals/{pal_id}/skills`               | List every skill attached to the PAL.                        |
| `PUT /v2/pals/{pal_id}/skills`               | Replace the PAL's **entire** skill set in one request.       |
| `GET /v2/pals/{pal_id}/skills/{skill_id}`    | Read one attachment.                                         |
| `PUT /v2/pals/{pal_id}/skills/{skill_id}`    | Attach a skill, or overwrite its config if already attached. |
| `PATCH /v2/pals/{pal_id}/skills/{skill_id}`  | Merge changes into an existing attachment's config.          |
| `DELETE /v2/pals/{pal_id}/skills/{skill_id}` | Detach a skill.                                              |

You can read skills on stock PALs, but you can only modify skills on PALs you own.

### Reading Configuration

The single-skill `GET` returns the attachment as stored:

```json theme={null}
{
  "skill_id": "magic_canvas",
  "config": {
    "components": { "chart": { "enabled": false } }
  },
  "attached_at": "2026-06-10T17:04:52.183947+00:00",
  "updated_at": "2026-06-11T09:31:08.412605+00:00"
}
```

The per-skill `PUT`, `PATCH`, and `GET` return the attachment object directly. The list `GET` and the bulk `PUT` wrap attachments in a `data` map keyed by skill id:

```json theme={null}
{
  "data": {
    "magic_canvas": {
      "skill_id": "magic_canvas",
      "config": {},
      "attached_at": "2026-06-10T17:04:52.183947+00:00",
      "updated_at": "2026-06-10T17:04:52.183947+00:00"
    }
  }
}
```

### Updating with PATCH

`PATCH` requires a `{ "config": ... }` body (unlike `PUT`, where it defaults to `{}`), merges it into the existing config, and returns `404` if the skill isn't attached:

```bash theme={null}
curl -X PATCH https://tavusapi.com/v2/pals/{pal_id}/skills/magic_canvas \
  -H "x-api-key: <your-api-key>" \
  -H "Content-Type: application/json" \
  -d '{ "config": { "components": { "chart": { "enabled": false } } } }'
```

Merge rules:

* The merge is **shallow, at the top level of `config`**: a PATCH that includes `components` replaces the whole overlay map rather than deep-merging per component. Send the complete set of overrides you want to end up with.
* Setting a top-level config key to `null` removes it: `{ "config": { "components": null } }` clears every override and returns the skill to defaults.

The merged result is re-validated in full.

### Replacing All Skills

`PUT /v2/pals/{pal_id}/skills` takes `{ "skills": { ... } }` and replaces the PAL's **entire** skill set:

```bash theme={null}
curl -X PUT https://tavusapi.com/v2/pals/{pal_id}/skills \
  -H "x-api-key: <your-api-key>" \
  -H "Content-Type: application/json" \
  -d '{ "skills": { "magic_canvas": { "config": {} } } }'
```

<Warning>
  The bulk PUT is a full replace: any skill missing from the payload is detached.
  To change only Canvas, use the per-skill `PUT` or `PATCH` instead.
</Warning>

Skills that were already attached keep their original `attached_at`.

### Detaching

```bash theme={null}
curl -X DELETE https://tavusapi.com/v2/pals/{pal_id}/skills/magic_canvas \
  -H "x-api-key: <your-api-key>"
```

Returns `204` with no body. Detaching removes Canvas actions from all future conversations and deletes the attachment's config; re-attaching starts from the config you send next.

## Validation Errors

Errors return `{ "error": "..." }`:

| Status | When                                                                               | Error message contains                                               |
| ------ | ---------------------------------------------------------------------------------- | -------------------------------------------------------------------- |
| `404`  | `PUT` or `PATCH` with a skill id that isn't registered (misspelled `magic_canvas`) | `Unknown skill '<skill_id>'`                                         |
| `404`  | `GET`, `PATCH`, or `DELETE` on a skill that isn't attached to the PAL              | `Skill '<skill_id>' is not attached to this PAL`                     |
| `400`  | Unknown key anywhere inside `config` (misspelled component, stray field)           | the offending key and `Unknown field.`                               |
| `400`  | `scheduling_url` doesn't start with `https://`                                     | `scheduling_url must use HTTPS`                                      |
| `400`  | `scheduling_url` is longer than 2048 characters                                    | `scheduling_url must be at most 2048 characters`                     |
| `400`  | `scheduling_url` has no hostname                                                   | `scheduling_url must include a hostname`                             |
| `400`  | `scheduling_url` host is `localhost` or a cloud metadata hostname                  | `scheduling_url host '<host>' is not allowed`                        |
| `400`  | `scheduling_url` host is an internal IP address                                    | `scheduling_url IP '<host>' is not allowed (internal address space)` |
| `400`  | The `pal_id` in the URL doesn't exist                                              | `Bad Request. PAL not found`                                         |

## How the configuration reaches a conversation

At conversation create, Tavus resolves the PAL's Canvas action list once:

* Audio-only (`audio_only: true`), chat, and external-meeting (`meeting_url`: Zoom, Teams, Meet) conversations never get Canvas actions.
* Every other conversation with the skill attached gets one `canvas_show_<component>` action per active component.
* `canvas_clear` is added once at least one component is active.
* Canvas actions never overwrite a [tool](/sections/conversational-video-interface/pal/tools) you defined with the same name; your tool wins.
