---
title: "Record Canvas Interaction"
method: POST
path: "/v2/conversations/{conversation_id}/canvas/interactions"
tags: ["Conversations"]
---

# Record Canvas Interaction

`POST /v2/conversations/{conversation_id}/canvas/interactions`

Record a Magic Canvas interaction (submit, skip, dismiss, clear, error, or heartbeat) while a conversation is **active**.

The Tavus-hosted embed and `@tavus/cvi-ui` post interactions for you. Call this endpoint directly only if you build your own renderer.

**Authentication:** No API key is required while the conversation is active. Never put your Tavus API key in a browser. Once the conversation ends, every POST is rejected.

**Idempotency:** Retries with the same `(conversation_id, interaction_id)` and identical `tool_call_id`, `component`, `component_version`, `type`, and `value` return `200` without firing a second webhook. `metadata` is excluded from the match.

**Rate limiting:** 120 POSTs per 60-second window per `(client IP, conversation_id)`. Exceeding the limit returns `429` with `{ "error": "Too many requests" }` and a `Retry-After` header (seconds until the window resets). Custom renderers posting `heartbeat` interactions count toward this limit.

See [Canvas interactions](/sections/conversational-video-interface/magic-canvas/api/interactions) for per-component `value` rules, webhook delivery, and the full error catalog.

## Request body

- CanvasInteractionRequest — Body for [Record Canvas Interaction](/api-reference/canvas-interactions/record-canvas-interaction). `value` validation depends on `component` and `type` - see [Canvas interactions](/sections/conversational-video-interface/magic-canvas/api/interactions#value-rules-per-component).
  - `interaction_id` string, required — Idempotency key. Unique per logical interaction; reuse verbatim on retries. Tavus clients use `ci_{tool_call_id}_{type}_{uuid}`.
  - `tool_call_id` string, required — The id of the Canvas invocation that showed the card. Ties the interaction to a specific card instance.
  - `component` 'canvas.question' | 'canvas.input' | 'canvas.calendar' | 'canvas.scheduling_embed' | 'canvas.text' | 'canvas.image' | 'canvas.video' | 'canvas.chart' | 'canvas.alert', required — Component id.
  - `component_version` string, required — Component contract version. `v1` for all current components.
  - `type` 'submit' | 'skip' | 'dismiss' | 'clear' | 'error' | 'heartbeat', required — Interaction type. Submit-capable components also allow `submit` and `skip`.
  - `value` object, required — Interaction payload. At most 16 KB serialized. Shape depends on `component` and `type`.
  - `metadata` object — Optional client annotations, at most 4 KB serialized. Not part of idempotency matching.

## Response `200`

Interaction recorded (or idempotent replay)

- object
  - `success` boolean

## Other responses

- `400` — Bad Request - invalid payload, unknown conversation, or conversation not active
- `409` — Conflict - interaction does not match the issued canvas instance, or interaction_id reused with a different payload
- `429` — Too Many Requests - rate limit exceeded (120 POSTs per 60-second window per client IP and conversation)

---

[API](https://skmtc.dev/tavus/apis/tavus-developer-api-collection.md) · [All operations](https://skmtc.dev/tavus/apis/tavus-developer-api-collection/llms.txt) · [OpenAPI document](https://skmtc-service-production.skmtc.workers.dev/v1/apis/tavus/tavus-developer-api-collection/revisions/c878e2f6508d/schema)
