diff --git a/ai-agents/ag-ui-card-messages.mdx b/ai-agents/ag-ui-card-messages.mdx
new file mode 100644
index 000000000..ffc3a5a46
--- /dev/null
+++ b/ai-agents/ag-ui-card-messages.mdx
@@ -0,0 +1,9 @@
+---
+title: "Card Messages"
+sidebarTitle: "Card Messages"
+description: "Let your AG-UI BYOA agent reply with rich, interactive cards designed in Card Builder."
+---
+
+import CardMessages from '/snippets/ai-agents/card-messages.mdx';
+
+
diff --git a/ai-agents/ag2-card-messages.mdx b/ai-agents/ag2-card-messages.mdx
new file mode 100644
index 000000000..39c4d0aa0
--- /dev/null
+++ b/ai-agents/ag2-card-messages.mdx
@@ -0,0 +1,9 @@
+---
+title: "Card Messages"
+sidebarTitle: "Card Messages"
+description: "Let your AG2 BYOA agent reply with rich, interactive cards designed in Card Builder."
+---
+
+import CardMessages from '/snippets/ai-agents/card-messages.mdx';
+
+
diff --git a/ai-agents/agent-builder/card-messages.mdx b/ai-agents/agent-builder/card-messages.mdx
new file mode 100644
index 000000000..3bc7e8ed2
--- /dev/null
+++ b/ai-agents/agent-builder/card-messages.mdx
@@ -0,0 +1,59 @@
+---
+title: "Card Messages"
+sidebarTitle: "Card Messages"
+description: "Let your agent reply with rich, interactive cards — designed in Card Builder — instead of plain text."
+---
+
+The **Card Messages** tool lets your agent reply with flexible, interactive cards — buttons, images, progress bars, layouts — instead of plain text. You design each card once in [Card Builder](/card-builder/overview) so it always renders uniformly, then tell the agent when to send it.
+
+## Enable the Card Messages tool
+
+1. Open your agent and go to **Tools**.
+2. Find **Card Messages** (a built-in system tool) and toggle it **on**.
+3. A **Design interactive cards with Card Builder** prompt appears — click **Open Card Builder** to start designing.
+
+## How it works
+
+Card Messages is a built-in **system tool**. When you enable it, the agent can call the tool to fetch a **card reference — working examples plus a field reference** (describing the structure documented in the [Card JSON Schema](/card-builder/schema)) — and then generate a conforming card in its reply.
+
+That means the agent *can* compose cards freely — but free-form generation drifts in layout and styling from one reply to the next. To keep every card consistent, **design it once in Card Builder and give the agent the exported JSON** to reuse, as shown below.
+
+
+You supply **what** card to send — the **how** is automatic. Enabling the tool also teaches the agent the format CometChat uses to recognize a card in its reply, so cards render with no extra work. This holds even when you paste a predefined card into the Instructions: keep the tool **on** — that's what supplies the format. With the tool off, pasted card JSON won't render as a card.
+
+
+
+A reply is delivered as an ordered sequence of **elements** — plain-text segments and at most **one card**. So an agent can send a card on its own, or with text before and/or after it, in a single reply. To present multiple sections *inside* the card, use layout elements (`row`, `column`, `grid`, `tabs`, `accordion`) rather than sending a second card.
+
+
+## Design a card and add it to your agent
+
+Once the tool is on, the workflow is:
+
+1. **Design your card** visually in [Card Builder](/card-builder/overview) — see [Building an Order Status Card](/card-builder/example-order-status) for a full walkthrough.
+2. Use **Export → Copy Card JSON** to copy the finished card.
+3. Add the JSON to the agent's **[Instructions](/ai-agents/agent-builder/instructions)** and specify **when** to send it.
+
+
+A fixed card renders exactly as designed. If it includes `{{placeholder}}` variables, instruct the agent to fill them in before sending.
+
+
+
+With several card types, you can return the card JSON from a **[Custom API Tool](/ai-agents/agent-builder/tools/overview)** instead of pasting it into the instructions — keeping the agent's instructions concise and focused.
+
+
+## Design cards in Card Builder
+
+Card Builder is the visual editor where you compose and save your cards.
+
+
+
+ Learn the editor — palette, canvas, elements, actions, and variables.
+
+
+ Build an interactive Order Status card from scratch, step by step.
+
+
+ The complete schema a card's JSON must conform to.
+
+
diff --git a/ai-agents/agno-card-messages.mdx b/ai-agents/agno-card-messages.mdx
new file mode 100644
index 000000000..174a4e8ab
--- /dev/null
+++ b/ai-agents/agno-card-messages.mdx
@@ -0,0 +1,9 @@
+---
+title: "Card Messages"
+sidebarTitle: "Card Messages"
+description: "Let your Agno BYOA agent reply with rich, interactive cards designed in Card Builder."
+---
+
+import CardMessages from '/snippets/ai-agents/card-messages.mdx';
+
+
diff --git a/ai-agents/crew-ai-card-messages.mdx b/ai-agents/crew-ai-card-messages.mdx
new file mode 100644
index 000000000..bfa319ba6
--- /dev/null
+++ b/ai-agents/crew-ai-card-messages.mdx
@@ -0,0 +1,9 @@
+---
+title: "Card Messages"
+sidebarTitle: "Card Messages"
+description: "Let your CrewAI BYOA agent reply with rich, interactive cards designed in Card Builder."
+---
+
+import CardMessages from '/snippets/ai-agents/card-messages.mdx';
+
+
diff --git a/ai-agents/langgraph-card-messages.mdx b/ai-agents/langgraph-card-messages.mdx
new file mode 100644
index 000000000..58df16be1
--- /dev/null
+++ b/ai-agents/langgraph-card-messages.mdx
@@ -0,0 +1,9 @@
+---
+title: "Card Messages"
+sidebarTitle: "Card Messages"
+description: "Let your LangGraph BYOA agent reply with rich, interactive cards designed in Card Builder."
+---
+
+import CardMessages from '/snippets/ai-agents/card-messages.mdx';
+
+
diff --git a/ai-agents/mastra-card-messages.mdx b/ai-agents/mastra-card-messages.mdx
new file mode 100644
index 000000000..56122286e
--- /dev/null
+++ b/ai-agents/mastra-card-messages.mdx
@@ -0,0 +1,9 @@
+---
+title: "Card Messages"
+sidebarTitle: "Card Messages"
+description: "Let your Mastra BYOA agent reply with rich, interactive cards designed in Card Builder."
+---
+
+import CardMessages from '/snippets/ai-agents/card-messages.mdx';
+
+
diff --git a/ai-agents/vercel-card-messages.mdx b/ai-agents/vercel-card-messages.mdx
new file mode 100644
index 000000000..13fcca422
--- /dev/null
+++ b/ai-agents/vercel-card-messages.mdx
@@ -0,0 +1,9 @@
+---
+title: "Card Messages"
+sidebarTitle: "Card Messages"
+description: "Let your Vercel AI BYOA agent reply with rich, interactive cards designed in Card Builder."
+---
+
+import CardMessages from '/snippets/ai-agents/card-messages.mdx';
+
+
diff --git a/card-builder/building-cards.mdx b/card-builder/building-cards.mdx
new file mode 100644
index 000000000..175f69288
--- /dev/null
+++ b/card-builder/building-cards.mdx
@@ -0,0 +1,92 @@
+---
+title: "Building Cards"
+sidebarTitle: "Building Cards"
+description: "Walk through the Card Builder editor — the canvas, the element palette, and the properties panel — to design, style, and save a card in the CometChat Dashboard."
+---
+
+This guide walks through designing a card in Card Builder, from a blank canvas to a saved template.
+
+
+
+
+
+## The Editor
+
+Card Builder is organized into three areas:
+
+| Area | What it does |
+| --- | --- |
+| **Palette** (left) | The elements and ready-made components you can add to a card. |
+| **Canvas** (center) | A live preview of your card as you build it. Select an element here to edit it. |
+| **Properties** (right) | Settings for the selected element, the card structure (tree), and overall card style. |
+
+The top bar holds the card name, import and export, undo/redo, and **Save**.
+
+
+
+
+
+## 1. Start a Card
+
+When you open Card Builder, choose a starting point:
+
+- **Template library** — pick a ready-made template (Product Card, Order Confirmation, and more) and customize it.
+- **Blank card** — start from scratch.
+
+
+
+
+
+## 2. Add Elements
+
+Click an element in the palette to add it to your card. New elements are placed relative to your current selection — inside a selected layout element, or after the selected element. You can add content such as text, images, and buttons, and arrange them using layout elements like rows, columns, and grids. For the full list, see [Elements & Actions](/card-builder/elements).
+
+You can also add a **component** — a pre-built group of elements (for example a product card or an order timeline) — and then edit its pieces.
+
+## 3. Arrange the Layout
+
+By default, elements stack vertically. To change the layout:
+
+- **Row** — place elements side by side.
+- **Column** — group elements vertically inside a row.
+- **Grid** — arrange elements in a grid.
+- **Carousel** — let users scroll horizontally through items.
+
+Use the structure tree in the properties panel to drag elements into a new order, nest them inside layouts, or remove them.
+
+## 4. Style the Card
+
+Select an element to edit its properties, or click an empty area of the card to edit the overall **card style**:
+
+- **Background** — set a fill color, or make it transparent.
+- **Corner radius** — round the card's corners.
+- **Border** — add a border color and width.
+- **Padding** — control the spacing inside the card.
+
+### Light and Dark Mode
+
+Colors are set separately for **light** and **dark** mode, so your card looks right in both. You can set a color for one mode and leave the other transparent.
+
+## 5. Make It Interactive
+
+Add an **action** to a button, icon button, link, or chip so it does something when tapped — open a URL, start a chat, send a message, make a call, and more. See [Elements & Actions](/card-builder/elements#actions) for the full list.
+
+## 6. Use Variables
+
+Insert [variables](/card-builder/elements#variables) — placeholders such as `{{user.name}}` or `{{order.id}}` — from the variable picker wherever you enter text or a URL. They're filled with real values when the card is sent, so a single card personalizes for every recipient. Available variables depend on where the card is used.
+
+## 7. Notifications (Push)
+
+A card is a message in CometChat. When that message triggers a push notification, the push can't show the full rich card — so the **Notification** tab is where you define the **notification text** for the message: the title and body shown in the push. A device preview shows how it will appear, and you can insert [variables](#6-use-variables) into the title and body so the notification is personalized per recipient.
+
+
+
+
+
+## 8. Save
+
+Give the card a name in the top bar and click **Save**. Saved cards are stored as templates so you can open them again from the template library, edit them, and reuse them.
+
+---
+
+Next: [Elements & Actions](/card-builder/elements) — a reference of everything you can add to a card.
diff --git a/card-builder/elements.mdx b/card-builder/elements.mdx
new file mode 100644
index 000000000..678c0b3ce
--- /dev/null
+++ b/card-builder/elements.mdx
@@ -0,0 +1,91 @@
+---
+title: "Elements & Actions"
+sidebarTitle: "Elements & Actions"
+description: "A reference of everything a card can contain — content, layout, and interactive elements, the actions a card can trigger, and the ready-made components you can add to a card."
+---
+
+A card is made up of **elements** arranged on the canvas. Interactive elements can trigger **actions**, and **components** give you ready-made groups of elements to start from. This page lists what's available.
+
+## Elements
+
+### Content
+
+| Element | Description |
+| --- | --- |
+| **Text** | A line or paragraph of text, with heading and body styles. |
+| **Markdown** | Rich text written in Markdown. |
+| **Image** | An image from a URL. |
+| **Icon** | An icon from the built-in library or a custom image. |
+| **Avatar** | A circular user or entity image. |
+| **Badge** | A small label, often for status or counts. |
+| **Chip** | A compact, tappable tag. |
+| **Code block** | Pre-formatted, monospaced text. |
+
+### Layout
+
+| Element | Description |
+| --- | --- |
+| **Row** | Arranges elements side by side. |
+| **Column** | Groups elements vertically, usually inside a row. |
+| **Grid** | Arranges elements in a grid. |
+| **Accordion** | Collapsible sections that expand on tap. |
+| **Tabs** | Switch between sections of content. |
+| **Divider** | A horizontal line to separate content. |
+| **Spacer** | Empty space to control vertical rhythm. |
+
+Rows, columns, and grids can also have their own background color, corner radius, and border.
+
+### Interactive
+
+| Element | Description |
+| --- | --- |
+| **Button** | A labeled button that triggers an action. |
+| **Icon button** | An icon-only button that triggers an action. |
+| **Link** | Tappable text that triggers an action. |
+
+### Data
+
+| Element | Description |
+| --- | --- |
+| **Table** | Rows and columns of structured data. |
+| **Progress bar** | A visual indicator of progress. |
+
+## Actions
+
+Add an action to a button, icon button, link, or chip to make it interactive. When a user taps the element, the action runs.
+
+| Action | What it does |
+| --- | --- |
+| **Open URL** | Opens a web address. |
+| **Chat with user** | Starts a one-to-one conversation with a user. |
+| **Chat with group** | Opens a group conversation. |
+| **Send message** | Sends a message on the user's behalf. |
+| **Copy to clipboard** | Copies text to the clipboard. |
+| **Download file** | Downloads a file. |
+| **Initiate call** | Starts a voice or video call. |
+| **API call** | Makes a request to a configured endpoint. |
+| **Custom callback** | Triggers custom handling in your app. |
+
+## Variables
+
+Variables are placeholders you insert into text and URL fields, written as `{{name}}` (for example `{{user.name}}`). They're replaced with real values when the card is sent, letting one card adapt to each recipient. Insert them from the variable picker wherever you enter text.
+
+## Components
+
+Components are pre-built groups of elements you can add to a card and then edit. They're a fast way to start a common card:
+
+| Component | Use case |
+| --- | --- |
+| **Product Card** | A product with image, details, and a call to action. |
+| **Order Confirmation** | Order summary with status. |
+| **Order Tracking** | A delivery timeline. |
+| **Event Card** | Event details with date and location. |
+| **Announcement** | News or an update. |
+| **Quick Reply Buttons** | Tappable response options. |
+| **Feedback** | A quick rating or response prompt. |
+| **Data Table** | Structured rows of data. |
+| **Carousel** | A horizontally scrollable set of cards. |
+
+## Fallback Text
+
+Every card includes **fallback text** — what a CometChat UI Kit renders if it can't display the card itself (for example, if the card JSON is malformed or the client doesn't support cards). Always set it so the message still conveys its meaning.
diff --git a/card-builder/example-order-status.mdx b/card-builder/example-order-status.mdx
new file mode 100644
index 000000000..007e9728c
--- /dev/null
+++ b/card-builder/example-order-status.mdx
@@ -0,0 +1,98 @@
+---
+title: "Building an Order Status Card"
+sidebarTitle: "Building an Order Status Card"
+description: "Step-by-step guide to building an interactive Order Status card from scratch in Card Builder — a heading, a progress bar, status rows with variables, a divider, and two action buttons in a row."
+---
+
+This guide builds an **Order Status** card from a blank canvas — the kind of card you might send when a customer's order ships. You'll add each element yourself: a heading, a progress bar, three status rows driven by variables, a divider, and two action buttons side by side.
+
+## What You'll Build
+
+A single card that shows order status at a glance and lets the customer act on it:
+
+- An **Order Status** heading (heading style)
+- A **progress bar** labelled **In Transit**, filled to the current stage
+- Three rows — **Status**, **ETA**, and **Tracking #** — filled from `{{order.*}}` variables
+- A **divider**
+- Two buttons in a **row** — **Track** and **Contact Support**
+
+## Prerequisites
+
+- Access to **Card Builder** in your app — see [Overview](/card-builder/overview) for how to open it.
+- Familiarity with the editor layout — see [Building Cards](/card-builder/building-cards).
+
+## Steps
+
+### Step 1 — Start a blank card
+
+In the template library, click **+ New Card**. The editor opens with an empty canvas ("Click an element or component to add it here"). Switch the left palette to the **Elements** tab — elements are grouped under **Layout**, **Content**, **Data Display**, and **Actions**.
+
+### Step 2 — Add the heading
+
+From **Content**, click **Text** to add it, then in the **Element** tab set its content to `Order Status` and change its **Variant** to **heading2**.
+
+
+
+
+
+### Step 3 — Add the progress bar and status rows
+
+From **Data Display**, add a **Progress Bar**. In the Element tab set its **Value** to `60` and its **Label** to `In Transit` (the label renders just below the heading).
+
+Then add three more **Text** elements and, in each, type the label and insert a [variable](/card-builder/building-cards#6-use-variables) from the variable picker:
+
+| Text element | Content |
+| --- | --- |
+| Status | `Status: {{order.status}}` |
+| ETA | `ETA: {{order.eta}}` |
+| Tracking # | `Tracking #: {{order.trackingNumber}}` |
+
+Variables are resolved to real values when the card is sent, so one card personalizes for every order.
+
+
+
+
+
+### Step 4 — Add a divider and the buttons
+
+From **Layout**, add a **Divider**. Then add a **Row** so the buttons sit side by side — with the row selected, add a **Button** (it nests inside the row) and set its label to `Track`. Select the row again, add a second **Button**, and label it `Contact Support`.
+
+
+
+
+
+### Step 5 — Give the buttons their actions
+
+Select a button, scroll to the **Action** section, and choose an [action](/card-builder/elements#actions):
+
+- **Track** → **Open URL**, with the URL `https://example.com/track/{{order.trackingNumber}}` (variables work in URLs too).
+- **Contact Support** → **Chat with user**, with the support agent's user ID.
+
+
+
+
+
+### Step 6 — Set the message type and fallback text
+
+Open the **Card** tab. Set the message **Type** to `order_status` — a meaningful identifier your app can use to recognize this kind of card (it defaults to `custom_type`).
+
+Then fill in **Fallback Text**. This is what a CometChat UI Kit renders if it ever **can't display the card itself** — for example if the card JSON is malformed or the client doesn't support cards — so the message still conveys its meaning. Because the card (and its buttons) won't be shown in that case, write plain copy that **stands on its own** and doesn't reference interactive elements like "tap Track". For this card:
+
+> Your order is in transit. We'll notify you when it's out for delivery.
+
+
+
+
+
+### Step 7 — Save
+
+Give the card a name (for example, **Order Status**) in the top bar and click **Save**. It now appears under **Saved Templates** and can be reused or edited any time.
+
+
+
+
+
+## Next steps
+
+- Browse what else a card can hold in [Elements & Actions](/card-builder/elements).
+- Reuse this card as a [saved template](/card-builder/building-cards#8-save) for future orders.
diff --git a/card-builder/overview.mdx b/card-builder/overview.mdx
new file mode 100644
index 000000000..a6188baa3
--- /dev/null
+++ b/card-builder/overview.mdx
@@ -0,0 +1,50 @@
+---
+title: "CometChat Card Builder"
+sidebarTitle: "Overview"
+description: "Card Builder is a visual tool in the CometChat Dashboard for designing rich, interactive card messages — product cards, order confirmations, quick replies, and more — that your CometChat UI Kits render natively."
+---
+
+Card Builder is a visual tool in the [CometChat Dashboard](https://app.cometchat.com) for designing **card messages** — structured, interactive messages such as product cards, order confirmations, event invites, and quick-reply prompts.
+
+Instead of sending plain text, you compose a card visually and CometChat UI Kits render it natively in your chat — with images, buttons, layouts, and actions that respond when a user taps them.
+
+
+
+
+
+With Card Builder, you can:
+
+- **Design cards visually** — add text, images, buttons, and layouts and see them on a live canvas.
+- **Add interactivity** — wire buttons and links to actions like opening a URL, starting a chat, or making a call.
+- **Use variables** — insert placeholders such as `{{user.name}}` that are filled in when the card is sent.
+- **Preview in light and dark mode** — set colors for each mode and see the result instantly.
+- **Save and reuse templates** — store finished cards and load them again whenever you need them.
+
+## What You Can Build
+
+Start from a blank card, or from a ready-made template — Product Card, Order Confirmation, Order Tracking, Event Card, Announcement, Quick Reply Buttons, and more. See the full set in [Components](/card-builder/elements#components).
+
+## How to Open Card Builder
+
+Card Builder opens in a new browser tab from the dashboard:
+
+- **For chat** — open your app in the [CometChat Dashboard](https://app.cometchat.com), expand **Chat & Messaging** in the sidebar, and select **Card Builder**.
+- **For an AI Agent** — open your agent and select **Card Builder** from the agent configuration menu.
+
+
+
+
+
+
+Card Builder is available to app owners, admins, and developers.
+
+
+## The Design Workflow
+
+1. **Choose a starting point** — open a blank card or a template from the library.
+2. **Build the card** — add elements from the palette and arrange them with rows, columns, and grids.
+3. **Style and preview** — set colors, spacing, and corner radius, and preview in light and dark mode.
+4. **Add actions and variables** — make buttons interactive and insert `{{placeholder}}` values.
+5. **Save** — save the card as a template to reuse it later.
+
+Continue to [Building Cards](/card-builder/building-cards) for a walkthrough of the editor, or see [Elements & Actions](/card-builder/elements) for everything a card can contain.
diff --git a/card-builder/schema.mdx b/card-builder/schema.mdx
new file mode 100644
index 000000000..6dc5172ef
--- /dev/null
+++ b/card-builder/schema.mdx
@@ -0,0 +1,1666 @@
+---
+title: "Card JSON Schema"
+sidebarTitle: "JSON Schema"
+description: "The complete JSON schema a card must conform to — for developers generating cards programmatically, such as from a BYOA agent or a Custom API Tool."
+---
+
+Every card is a JSON document that conforms to the **CometChat Card Message Schema**. [Card Builder](/card-builder/overview) produces conforming JSON automatically, so you only need this page if you generate cards **programmatically** — for example, from a [BYOA agent](/ai-agents/cometchat-ag-ui-byoa) or a [Custom API Tool](/ai-agents/agent-builder/tools/overview).
+
+The schema is **Draft-07**.
+
+
+Data placeholders (`{{variable}}`) must be **resolved before the card is sent** — the backend passes the JSON through as-is and does not substitute them.
+
+
+## Root structure
+
+| Field | Required | Type | Notes |
+| --- | --- | --- | --- |
+| `version` | Yes | string | Always `"1.0"` (the string, not a number). |
+| `body` | Yes | array | The card's elements, rendered top to bottom. Must be non-empty. |
+| `style` | Yes | object | Card-level style. Its `background` is required; `borderRadius`, `borderColor`, `borderWidth`, `padding` are optional. |
+| `fallbackText` | Yes | string | Plain text shown when a client can't render the card. Always set it. |
+
+```json
+{
+ "version": "1.0",
+ "style": { "background": { "light": "#FFFFFF", "dark": "#1C1C1E" } },
+ "body": [ /* one or more elements */ ],
+ "fallbackText": "Your order #1234 has shipped"
+}
+```
+
+
+**Push notifications are not part of the card.** When a card is sent, the *message's* `data.text` carries the push/preview text — set from the **Notification** tab in Card Builder, falling back to `fallbackText`. The card JSON itself has no notification field.
+
+
+## Colors
+
+Color fields are **objects with explicit light- and dark-mode values**, so a card looks right in both themes. Each side is a 6-digit hex string or `"transparent"`:
+
+```json
+"background": { "light": "#FFFFFF", "dark": "#1C1C1E" }
+```
+
+Use `"transparent"` to apply no color for one mode while setting the other, and **omit the property entirely** if you don't need a color override (where allowed — note `style.background` is required).
+
+## Elements
+
+Every element needs a unique `id` and a `type`. The `type` determines its other required fields. No element may include properties not defined for its type (`additionalProperties: false`).
+
+| Element `type` | Required fields (besides `id`/`type`) |
+| --- | --- |
+| `text` | `content` |
+| `markdown` | `content` |
+| `image` | `url` |
+| `icon` | `name` or `url` (at least one) |
+| `avatar` | — |
+| `badge` | `text` |
+| `chip` | `text` |
+| `codeBlock` | `content` |
+| `divider` | — |
+| `spacer` | `height` |
+| `row` | `items` (non-empty) |
+| `column` | `items` (non-empty) |
+| `grid` | `items` (non-empty) |
+| `accordion` | `header`, `body` (non-empty) |
+| `tabs` | `tabs` (non-empty, each `{ label, content }`) |
+| `button` | `label`, `action` |
+| `iconButton` | `icon`, `action` |
+| `link` | `text`, `action` |
+| `table` | `columns` (non-empty), `rows` |
+| `progressBar` | `value` (0–100) |
+
+For a description of each element, see [Elements & Actions](/card-builder/elements).
+
+## Actions
+
+Add an `action` to a `button`, `iconButton`, `link`, or `chip`. Every action needs a `type` plus its required fields.
+
+| Action `type` | Required fields |
+| --- | --- |
+| `openUrl` | `url` (optional `openIn`: `browser` \| `webview`) |
+| `chatWithUser` | `uid` |
+| `chatWithGroup` | `guid` |
+| `sendMessage` | `text` |
+| `copyToClipboard` | `value` |
+| `downloadFile` | `url` |
+| `initiateCall` | `callType` (`audio` \| `video`) **and** `uid` or `guid` |
+| `apiCall` | `url` (optional `method`, `headers`, `body`) |
+| `customCallback` | — (just `type`) |
+
+## Variables
+
+Insert variables as `{{name}}` (for example `{{user.name}}`, `{{order.id}}`) into text and URL fields. They personalize a single card per recipient, but **must be resolved before sending** — when an agent sends a card, instruct it to fill them in first.
+
+## Full JSON Schema
+
+This is the complete schema. Validate generated cards against it (any Draft-07 validator, e.g. Ajv) before sending.
+
+
+```json
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "$id": "https://schema.cometchat.com/card/v1.0",
+ "title": "CometChat Card Message Schema",
+ "description": "Schema for rich, interactive message cards rendered natively by CometChat UI Kits. Used by the Dashboard Card Builder, external developers via API, and AI Agents for structured message generation. Data placeholders ({{variable}}) must be resolved before sending — the backend passes JSON through as-is.",
+ "type": "object",
+ "required": [
+ "version",
+ "body",
+ "style",
+ "fallbackText"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "version": {
+ "type": "string",
+ "const": "1.0",
+ "description": "Schema version. Always '1.0' for this release."
+ },
+ "body": {
+ "type": "array",
+ "description": "Ordered list of elements rendered top-to-bottom (vertical stack). This is always vertical. Use 'row' for horizontal, 'grid' for grid, or 'carousel' for scrollable horizontal layout.",
+ "minItems": 1,
+ "items": {
+ "$ref": "#/definitions/element"
+ }
+ },
+ "style": {
+ "$ref": "#/definitions/cardStyle"
+ },
+ "fallbackText": {
+ "type": "string",
+ "description": "Plain text shown on older UI Kit versions that cannot render cards. Required for graceful degradation."
+ }
+ },
+ "definitions": {
+ "padding": {
+ "description": "Padding. Single number applies to all sides, or specify per-side.",
+ "oneOf": [
+ {
+ "type": "number",
+ "minimum": 0
+ },
+ {
+ "type": "object",
+ "properties": {
+ "top": {
+ "type": "number",
+ "minimum": 0
+ },
+ "right": {
+ "type": "number",
+ "minimum": 0
+ },
+ "bottom": {
+ "type": "number",
+ "minimum": 0
+ },
+ "left": {
+ "type": "number",
+ "minimum": 0
+ }
+ },
+ "additionalProperties": false
+ }
+ ]
+ },
+ "sizeOrPercentage": {
+ "description": "Size in pixels (number) or percentage string (e.g. '50%').",
+ "oneOf": [
+ {
+ "type": "number",
+ "minimum": 0
+ },
+ {
+ "type": "string",
+ "pattern": "^\\d+(\\.\\d+)?%$"
+ }
+ ]
+ },
+ "colorSide": {
+ "description": "A single color side value — either a 6-digit hex or 'transparent' for transparent/default.",
+ "oneOf": [
+ {
+ "type": "string",
+ "pattern": "^#[0-9A-Fa-f]{6}$",
+ "description": "6-digit hex color for this mode."
+ },
+ {
+ "type": "string",
+ "const": "transparent",
+ "description": "Transparent/default — no color override for this mode."
+ }
+ ]
+ },
+ "colorValue": {
+ "type": "object",
+ "description": "Color value with explicit light and dark mode values. Each side is either a 6-digit hex or 'transparent'. Use 'transparent' to apply no color for a specific mode while setting a color for the other. Omit the property entirely if no color override is needed for either mode.",
+ "required": [
+ "light",
+ "dark"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "light": {
+ "$ref": "#/definitions/colorSide",
+ "description": "Color for light mode."
+ },
+ "dark": {
+ "$ref": "#/definitions/colorSide",
+ "description": "Color for dark mode."
+ }
+ }
+ },
+ "iconRef": {
+ "type": "object",
+ "description": "Reference to an icon. Use 'name' for built-in icons from the icon library, or 'url' for custom icon URLs. At least one must be provided. If both are present, 'url' takes precedence for rendering while 'name' serves as a fallback identifier.",
+ "anyOf": [
+ {
+ "required": [
+ "name"
+ ]
+ },
+ {
+ "required": [
+ "url"
+ ]
+ }
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "Icon name from the built-in icon library (e.g. 'check', 'star', 'calendar_today')."
+ },
+ "url": {
+ "type": "string",
+ "description": "Direct URL to the icon image asset. Takes precedence over 'name' for rendering."
+ }
+ }
+ },
+ "action": {
+ "description": "An action triggered by user interaction (button tap, link click, toggle change).",
+ "oneOf": [
+ {
+ "type": "object",
+ "title": "openUrl",
+ "required": [
+ "type",
+ "url"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "type": {
+ "const": "openUrl"
+ },
+ "url": {
+ "type": "string",
+ "description": "URL to open. Supports {{placeholder}}."
+ },
+ "openIn": {
+ "type": "string",
+ "enum": [
+ "browser",
+ "webview"
+ ],
+ "default": "browser"
+ }
+ }
+ },
+ {
+ "type": "object",
+ "title": "chatWithUser",
+ "required": [
+ "type",
+ "uid"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "type": {
+ "const": "chatWithUser"
+ },
+ "uid": {
+ "type": "string",
+ "description": "CometChat user uid."
+ }
+ }
+ },
+ {
+ "type": "object",
+ "title": "chatWithGroup",
+ "required": [
+ "type",
+ "guid"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "type": {
+ "const": "chatWithGroup"
+ },
+ "guid": {
+ "type": "string",
+ "description": "CometChat group guid."
+ }
+ }
+ },
+ {
+ "type": "object",
+ "title": "sendMessage",
+ "required": [
+ "type",
+ "text"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "type": {
+ "const": "sendMessage"
+ },
+ "text": {
+ "type": "string"
+ },
+ "receiverUid": {
+ "type": "string",
+ "description": "Send to a specific user. If omitted along with receiverGuid, sends in the current conversation."
+ },
+ "receiverGuid": {
+ "type": "string",
+ "description": "Send to a specific group. If omitted along with receiverUid, sends in the current conversation."
+ }
+ }
+ },
+ {
+ "type": "object",
+ "title": "copyToClipboard",
+ "required": [
+ "type",
+ "value"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "type": {
+ "const": "copyToClipboard"
+ },
+ "value": {
+ "type": "string"
+ }
+ }
+ },
+ {
+ "type": "object",
+ "title": "downloadFile",
+ "required": [
+ "type",
+ "url"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "type": {
+ "const": "downloadFile"
+ },
+ "url": {
+ "type": "string"
+ },
+ "filename": {
+ "type": "string"
+ }
+ }
+ },
+ {
+ "type": "object",
+ "title": "initiateCall",
+ "required": [
+ "type",
+ "callType"
+ ],
+ "anyOf": [
+ {
+ "required": [
+ "uid"
+ ]
+ },
+ {
+ "required": [
+ "guid"
+ ]
+ }
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "type": {
+ "const": "initiateCall"
+ },
+ "uid": {
+ "type": "string",
+ "description": "User uid for 1:1 call."
+ },
+ "guid": {
+ "type": "string",
+ "description": "Group guid for group call."
+ },
+ "callType": {
+ "type": "string",
+ "enum": [
+ "audio",
+ "video"
+ ]
+ }
+ }
+ },
+ {
+ "type": "object",
+ "title": "apiCall",
+ "required": [
+ "type",
+ "url"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "type": {
+ "const": "apiCall"
+ },
+ "url": {
+ "type": "string"
+ },
+ "method": {
+ "type": "string",
+ "enum": [
+ "GET",
+ "POST",
+ "PUT",
+ "DELETE"
+ ],
+ "default": "POST"
+ },
+ "headers": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ }
+ },
+ "body": {
+ "type": "object"
+ }
+ }
+ },
+ {
+ "type": "object",
+ "title": "customCallback",
+ "required": [
+ "type"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "type": {
+ "const": "customCallback"
+ }
+ }
+ }
+ ]
+ },
+ "element": {
+ "description": "A UI element inside a card. Discriminated by the 'type' field.",
+ "oneOf": [
+ {
+ "$ref": "#/definitions/elements/text"
+ },
+ {
+ "$ref": "#/definitions/elements/image"
+ },
+ {
+ "$ref": "#/definitions/elements/icon"
+ },
+ {
+ "$ref": "#/definitions/elements/avatar"
+ },
+ {
+ "$ref": "#/definitions/elements/badge"
+ },
+ {
+ "$ref": "#/definitions/elements/divider"
+ },
+ {
+ "$ref": "#/definitions/elements/spacer"
+ },
+ {
+ "$ref": "#/definitions/elements/chip"
+ },
+ {
+ "$ref": "#/definitions/elements/progressBar"
+ },
+ {
+ "$ref": "#/definitions/elements/codeBlock"
+ },
+ {
+ "$ref": "#/definitions/elements/markdown"
+ },
+ {
+ "$ref": "#/definitions/elements/row"
+ },
+ {
+ "$ref": "#/definitions/elements/column"
+ },
+ {
+ "$ref": "#/definitions/elements/grid"
+ },
+ {
+ "$ref": "#/definitions/elements/accordion"
+ },
+ {
+ "$ref": "#/definitions/elements/tabs"
+ },
+ {
+ "$ref": "#/definitions/elements/button"
+ },
+ {
+ "$ref": "#/definitions/elements/iconButton"
+ },
+ {
+ "$ref": "#/definitions/elements/link"
+ },
+ {
+ "$ref": "#/definitions/elements/table"
+ }
+ ]
+ },
+ "elements": {
+ "text": {
+ "type": "object",
+ "title": "Text",
+ "description": "Renders text content. Supports data placeholders {{var}}.",
+ "required": [
+ "id",
+ "type",
+ "content"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "Unique element identifier. Must be unique across all elements in the card."
+ },
+ "type": {
+ "const": "text"
+ },
+ "content": {
+ "type": "string",
+ "description": "Text content. Supports {{placeholder}} syntax."
+ },
+ "variant": {
+ "type": "string",
+ "enum": [
+ "title",
+ "heading1",
+ "heading2",
+ "heading3",
+ "heading4",
+ "body",
+ "caption1",
+ "caption2"
+ ],
+ "default": "body",
+ "description": "Typography level: title (32px), heading1 (24px), heading2 (20px), heading3 (18px), heading4 (16px), body (14px), caption1 (12px), caption2 (10px)."
+ },
+ "color": {
+ "$ref": "#/definitions/colorValue"
+ },
+ "align": {
+ "type": "string",
+ "enum": [
+ "left",
+ "center",
+ "right",
+ "justify"
+ ],
+ "default": "left"
+ },
+ "fontWeight": {
+ "type": "string",
+ "enum": [
+ "regular",
+ "medium",
+ "bold"
+ ],
+ "default": "regular",
+ "description": "Maps to UI Kit weights: regular (400), medium (500), bold (700)."
+ },
+ "maxLines": {
+ "type": "integer",
+ "minimum": 1
+ },
+ "padding": {
+ "$ref": "#/definitions/padding"
+ }
+ }
+ },
+ "image": {
+ "type": "object",
+ "title": "Image",
+ "description": "Renders an image. URL supports {{placeholder}}.",
+ "required": [
+ "id",
+ "type",
+ "url"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "Unique element identifier. Must be unique across all elements in the card."
+ },
+ "type": {
+ "const": "image"
+ },
+ "url": {
+ "type": "string",
+ "description": "Image source URL. Supports {{placeholder}}."
+ },
+ "altText": {
+ "type": "string"
+ },
+ "fit": {
+ "type": "string",
+ "enum": [
+ "cover",
+ "contain",
+ "fill"
+ ],
+ "default": "cover"
+ },
+ "width": {
+ "$ref": "#/definitions/sizeOrPercentage"
+ },
+ "height": {
+ "$ref": "#/definitions/sizeOrPercentage"
+ },
+ "borderRadius": {
+ "type": "number",
+ "minimum": 0
+ },
+ "padding": {
+ "$ref": "#/definitions/padding"
+ }
+ }
+ },
+ "icon": {
+ "type": "object",
+ "title": "Icon",
+ "description": "Renders an icon from the icon library or a custom URL. Use 'name' for built-in icons, or 'url' for custom icon URLs. At least one of 'name' or 'url' must be provided.",
+ "required": [
+ "id",
+ "type"
+ ],
+ "anyOf": [
+ {
+ "required": [
+ "name"
+ ]
+ },
+ {
+ "required": [
+ "url"
+ ]
+ }
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "Unique element identifier. Must be unique across all elements in the card."
+ },
+ "type": {
+ "const": "icon"
+ },
+ "name": {
+ "type": "string",
+ "description": "Icon name from the built-in icon library (e.g. 'check', 'star', 'calendar_today')."
+ },
+ "url": {
+ "type": "string",
+ "description": "Direct URL to the icon image asset. Takes precedence over 'name' for rendering."
+ },
+ "size": {
+ "type": "number",
+ "minimum": 0
+ },
+ "color": {
+ "$ref": "#/definitions/colorValue"
+ },
+ "backgroundColor": {
+ "$ref": "#/definitions/colorValue"
+ },
+ "borderRadius": {
+ "type": "number",
+ "minimum": 0
+ },
+ "padding": {
+ "type": "number",
+ "minimum": 0,
+ "description": "Padding around the icon in px."
+ }
+ }
+ },
+ "avatar": {
+ "type": "object",
+ "title": "Avatar",
+ "description": "Renders a user avatar with image or fallback initials.",
+ "required": [
+ "id",
+ "type"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "Unique element identifier. Must be unique across all elements in the card."
+ },
+ "type": {
+ "const": "avatar"
+ },
+ "imageUrl": {
+ "type": "string",
+ "description": "Avatar image URL. Supports {{placeholder}}."
+ },
+ "fallbackInitials": {
+ "type": "string",
+ "maxLength": 2
+ },
+ "size": {
+ "type": "number",
+ "minimum": 0,
+ "description": "Size in density-independent pixels. Suggested presets: 28 (small), 36 (medium), 48 (large)."
+ },
+ "borderRadius": {
+ "type": "number",
+ "minimum": 0,
+ "description": "Corner radius in px. Set to half of size for circle, ~size/4 for rounded."
+ },
+ "backgroundColor": {
+ "$ref": "#/definitions/colorValue",
+ "description": "Background color for the fallback initials circle."
+ },
+ "fontSize": {
+ "type": "number",
+ "minimum": 0,
+ "description": "Font size for fallback initials in px."
+ },
+ "fontWeight": {
+ "type": "string",
+ "enum": [
+ "regular",
+ "medium",
+ "bold"
+ ],
+ "description": "Font weight for fallback initials."
+ }
+ }
+ },
+ "badge": {
+ "type": "object",
+ "title": "Badge",
+ "description": "Renders a small label badge (e.g. status, priority).",
+ "required": [
+ "id",
+ "type",
+ "text"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "Unique element identifier. Must be unique across all elements in the card."
+ },
+ "type": {
+ "const": "badge"
+ },
+ "text": {
+ "type": "string"
+ },
+ "color": {
+ "$ref": "#/definitions/colorValue"
+ },
+ "size": {
+ "type": "number",
+ "minimum": 0,
+ "description": "Badge height in px. Suggested presets: 20 (small), 24 (medium)."
+ },
+ "backgroundColor": {
+ "$ref": "#/definitions/colorValue"
+ },
+ "borderColor": {
+ "$ref": "#/definitions/colorValue"
+ },
+ "borderWidth": {
+ "type": "number",
+ "minimum": 0
+ },
+ "borderRadius": {
+ "type": "number",
+ "minimum": 0
+ },
+ "padding": {
+ "$ref": "#/definitions/padding"
+ },
+ "fontSize": {
+ "type": "number",
+ "minimum": 0,
+ "description": "Font size in px."
+ }
+ }
+ },
+ "divider": {
+ "type": "object",
+ "title": "Divider",
+ "description": "Renders a horizontal line separator.",
+ "required": [
+ "id",
+ "type"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "Unique element identifier. Must be unique across all elements in the card."
+ },
+ "type": {
+ "const": "divider"
+ },
+ "color": {
+ "$ref": "#/definitions/colorValue"
+ },
+ "thickness": {
+ "type": "number",
+ "minimum": 0
+ },
+ "margin": {
+ "type": "number",
+ "minimum": 0,
+ "description": "Top and bottom margin in px."
+ }
+ }
+ },
+ "spacer": {
+ "type": "object",
+ "title": "Spacer",
+ "description": "Adds vertical empty space.",
+ "required": [
+ "id",
+ "type",
+ "height"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "Unique element identifier. Must be unique across all elements in the card."
+ },
+ "type": {
+ "const": "spacer"
+ },
+ "height": {
+ "type": "number",
+ "minimum": 0
+ }
+ }
+ },
+ "chip": {
+ "type": "object",
+ "title": "Chip",
+ "description": "Renders a compact label chip, optionally with an icon.",
+ "required": [
+ "id",
+ "type",
+ "text"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "Unique element identifier. Must be unique across all elements in the card."
+ },
+ "type": {
+ "const": "chip"
+ },
+ "text": {
+ "type": "string"
+ },
+ "color": {
+ "$ref": "#/definitions/colorValue"
+ },
+ "icon": {
+ "$ref": "#/definitions/iconRef",
+ "description": "Optional icon displayed in the chip."
+ },
+ "backgroundColor": {
+ "$ref": "#/definitions/colorValue"
+ },
+ "borderColor": {
+ "$ref": "#/definitions/colorValue"
+ },
+ "borderWidth": {
+ "type": "number",
+ "minimum": 0
+ },
+ "borderRadius": {
+ "type": "number",
+ "minimum": 0
+ },
+ "padding": {
+ "$ref": "#/definitions/padding"
+ },
+ "fontSize": {
+ "type": "number",
+ "minimum": 0,
+ "description": "Font size in px."
+ }
+ }
+ },
+ "progressBar": {
+ "type": "object",
+ "title": "Progress Bar",
+ "description": "Renders a horizontal progress bar.",
+ "required": [
+ "id",
+ "type",
+ "value"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "Unique element identifier. Must be unique across all elements in the card."
+ },
+ "type": {
+ "const": "progressBar"
+ },
+ "value": {
+ "type": "number",
+ "minimum": 0,
+ "maximum": 100
+ },
+ "color": {
+ "$ref": "#/definitions/colorValue"
+ },
+ "trackColor": {
+ "$ref": "#/definitions/colorValue"
+ },
+ "height": {
+ "type": "number",
+ "minimum": 0
+ },
+ "label": {
+ "type": "string"
+ },
+ "borderRadius": {
+ "type": "number",
+ "minimum": 0
+ },
+ "labelFontSize": {
+ "type": "number",
+ "minimum": 0,
+ "description": "Font size for the label text in px."
+ },
+ "labelColor": {
+ "$ref": "#/definitions/colorValue",
+ "description": "Color for the label text."
+ }
+ }
+ },
+ "codeBlock": {
+ "type": "object",
+ "title": "Code Block",
+ "description": "Renders a code snippet with optional syntax highlighting label.",
+ "required": [
+ "id",
+ "type",
+ "content"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "Unique element identifier. Must be unique across all elements in the card."
+ },
+ "type": {
+ "const": "codeBlock"
+ },
+ "content": {
+ "type": "string"
+ },
+ "language": {
+ "type": "string"
+ },
+ "backgroundColor": {
+ "$ref": "#/definitions/colorValue"
+ },
+ "textColor": {
+ "$ref": "#/definitions/colorValue"
+ },
+ "padding": {
+ "$ref": "#/definitions/padding"
+ },
+ "borderRadius": {
+ "type": "number",
+ "minimum": 0
+ },
+ "fontSize": {
+ "type": "number",
+ "minimum": 0,
+ "description": "Font size in px."
+ },
+ "languageLabelFontSize": {
+ "type": "number",
+ "minimum": 0,
+ "description": "Font size for the language label in px."
+ },
+ "languageLabelColor": {
+ "$ref": "#/definitions/colorValue",
+ "description": "Color for the language label text."
+ }
+ }
+ },
+ "markdown": {
+ "type": "object",
+ "title": "Markdown",
+ "description": "Renders markdown content.",
+ "required": [
+ "id",
+ "type",
+ "content"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "Unique element identifier. Must be unique across all elements in the card."
+ },
+ "type": {
+ "const": "markdown"
+ },
+ "content": {
+ "type": "string"
+ },
+ "baseFontSize": {
+ "type": "number",
+ "minimum": 0
+ },
+ "linkColor": {
+ "$ref": "#/definitions/colorValue"
+ },
+ "color": {
+ "$ref": "#/definitions/colorValue"
+ },
+ "lineHeight": {
+ "type": "number",
+ "minimum": 0,
+ "description": "Line height multiplier (e.g. 1.5)."
+ }
+ }
+ },
+ "row": {
+ "type": "object",
+ "title": "Row",
+ "description": "Horizontal layout container. Children are arranged left-to-right. Use 'scrollable' for horizontal scroll with optional snap and peek (carousel behavior).",
+ "required": [
+ "id",
+ "type",
+ "items"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "Unique element identifier. Must be unique across all elements in the card."
+ },
+ "type": {
+ "const": "row"
+ },
+ "items": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/element"
+ },
+ "minItems": 1
+ },
+ "gap": {
+ "type": "number",
+ "minimum": 0
+ },
+ "align": {
+ "type": "string",
+ "enum": [
+ "start",
+ "center",
+ "end",
+ "spaceBetween",
+ "spaceAround"
+ ],
+ "default": "start"
+ },
+ "crossAlign": {
+ "type": "string",
+ "enum": [
+ "start",
+ "center",
+ "end"
+ ],
+ "default": "start",
+ "description": "Cross-axis (vertical) alignment of children within the row."
+ },
+ "wrap": {
+ "type": "boolean",
+ "default": false
+ },
+ "scrollable": {
+ "type": "boolean",
+ "default": false,
+ "description": "Enable horizontal scrolling when items overflow the card width."
+ },
+ "peek": {
+ "type": "number",
+ "minimum": 0,
+ "description": "Pixels of the next item visible when scrollable. Only applies when scrollable is true."
+ },
+ "snap": {
+ "type": "string",
+ "enum": [
+ "item",
+ "free"
+ ],
+ "default": "item",
+ "description": "Snap behavior when scrolling. Only applies when scrollable is true."
+ },
+ "padding": {
+ "$ref": "#/definitions/padding"
+ },
+ "backgroundColor": {
+ "$ref": "#/definitions/colorValue"
+ },
+ "borderRadius": {
+ "type": "number",
+ "minimum": 0
+ },
+ "borderColor": {
+ "$ref": "#/definitions/colorValue"
+ },
+ "borderWidth": {
+ "type": "number",
+ "minimum": 0
+ }
+ }
+ },
+ "column": {
+ "type": "object",
+ "title": "Column",
+ "description": "Vertical layout container. Children are arranged top-to-bottom.",
+ "required": [
+ "id",
+ "type",
+ "items"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "Unique element identifier. Must be unique across all elements in the card."
+ },
+ "type": {
+ "const": "column"
+ },
+ "items": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/element"
+ },
+ "minItems": 1
+ },
+ "gap": {
+ "type": "number",
+ "minimum": 0
+ },
+ "align": {
+ "type": "string",
+ "enum": [
+ "start",
+ "center",
+ "end",
+ "stretch"
+ ],
+ "default": "start"
+ },
+ "crossAlign": {
+ "type": "string",
+ "enum": [
+ "start",
+ "center",
+ "end"
+ ],
+ "default": "start",
+ "description": "Cross-axis (horizontal) alignment of children within the column."
+ },
+ "padding": {
+ "$ref": "#/definitions/padding"
+ },
+ "backgroundColor": {
+ "$ref": "#/definitions/colorValue"
+ },
+ "borderRadius": {
+ "type": "number",
+ "minimum": 0
+ },
+ "borderColor": {
+ "$ref": "#/definitions/colorValue"
+ },
+ "borderWidth": {
+ "type": "number",
+ "minimum": 0
+ }
+ }
+ },
+ "grid": {
+ "type": "object",
+ "title": "Grid",
+ "description": "Grid layout with 2-4 columns. Items fill left-to-right, top-to-bottom.",
+ "required": [
+ "id",
+ "type",
+ "items"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "Unique element identifier. Must be unique across all elements in the card."
+ },
+ "type": {
+ "const": "grid"
+ },
+ "items": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/element"
+ },
+ "minItems": 1
+ },
+ "columns": {
+ "type": "integer",
+ "enum": [
+ 2,
+ 3,
+ 4
+ ],
+ "default": 2
+ },
+ "gap": {
+ "type": "number",
+ "minimum": 0
+ },
+ "padding": {
+ "$ref": "#/definitions/padding"
+ },
+ "backgroundColor": {
+ "$ref": "#/definitions/colorValue"
+ },
+ "borderRadius": {
+ "type": "number",
+ "minimum": 0
+ },
+ "borderColor": {
+ "$ref": "#/definitions/colorValue"
+ },
+ "borderWidth": {
+ "type": "number",
+ "minimum": 0
+ }
+ }
+ },
+ "accordion": {
+ "type": "object",
+ "title": "Accordion",
+ "description": "Collapsible section with a header and expandable body.",
+ "required": [
+ "id",
+ "type",
+ "header",
+ "body"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "Unique element identifier. Must be unique across all elements in the card."
+ },
+ "type": {
+ "const": "accordion"
+ },
+ "header": {
+ "type": "string"
+ },
+ "headerIcon": {
+ "$ref": "#/definitions/iconRef",
+ "description": "Optional icon displayed in the accordion header."
+ },
+ "body": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/element"
+ },
+ "minItems": 1
+ },
+ "expandedByDefault": {
+ "type": "boolean",
+ "default": false
+ },
+ "border": {
+ "type": "boolean"
+ },
+ "padding": {
+ "$ref": "#/definitions/padding"
+ },
+ "fontSize": {
+ "type": "number",
+ "minimum": 0,
+ "description": "Font size for the header text in px."
+ },
+ "fontWeight": {
+ "type": "string",
+ "enum": [
+ "regular",
+ "medium",
+ "bold"
+ ],
+ "description": "Font weight for the header text."
+ },
+ "borderRadius": {
+ "type": "number",
+ "minimum": 0
+ }
+ }
+ },
+ "tabs": {
+ "type": "object",
+ "title": "Tabs",
+ "description": "Tabbed container. Each tab has a label and content elements.",
+ "required": [
+ "id",
+ "type",
+ "tabs"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "Unique element identifier. Must be unique across all elements in the card."
+ },
+ "type": {
+ "const": "tabs"
+ },
+ "tabs": {
+ "type": "array",
+ "minItems": 1,
+ "items": {
+ "type": "object",
+ "required": [
+ "label",
+ "content"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "label": {
+ "type": "string"
+ },
+ "content": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/element"
+ },
+ "minItems": 1
+ }
+ }
+ }
+ },
+ "defaultActiveTab": {
+ "type": "integer",
+ "minimum": 0,
+ "default": 0
+ },
+ "tabAlign": {
+ "type": "string",
+ "enum": [
+ "start",
+ "center",
+ "stretch"
+ ],
+ "default": "start"
+ },
+ "tabPadding": {
+ "$ref": "#/definitions/padding",
+ "description": "Padding inside each tab label."
+ },
+ "contentPadding": {
+ "$ref": "#/definitions/padding",
+ "description": "Padding inside the tab content area."
+ },
+ "fontSize": {
+ "type": "number",
+ "minimum": 0,
+ "description": "Font size for tab labels in px."
+ }
+ }
+ },
+ "button": {
+ "type": "object",
+ "title": "Button",
+ "description": "A clickable button that triggers an action.",
+ "required": [
+ "id",
+ "type",
+ "label",
+ "action"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "Unique element identifier. Must be unique across all elements in the card."
+ },
+ "type": {
+ "const": "button"
+ },
+ "label": {
+ "type": "string"
+ },
+ "action": {
+ "$ref": "#/definitions/action"
+ },
+ "backgroundColor": {
+ "$ref": "#/definitions/colorValue"
+ },
+ "textColor": {
+ "$ref": "#/definitions/colorValue"
+ },
+ "icon": {
+ "$ref": "#/definitions/iconRef",
+ "description": "Optional icon displayed in the button."
+ },
+ "iconPosition": {
+ "type": "string",
+ "enum": [
+ "left",
+ "right"
+ ],
+ "default": "left"
+ },
+ "size": {
+ "type": "number",
+ "minimum": 0,
+ "description": "Button height in px. Suggested presets: 32 (small), 40 (medium), 48 (large)."
+ },
+ "fullWidth": {
+ "type": "boolean",
+ "default": false
+ },
+ "borderColor": {
+ "$ref": "#/definitions/colorValue"
+ },
+ "borderWidth": {
+ "type": "number",
+ "minimum": 0
+ },
+ "borderRadius": {
+ "type": "number",
+ "minimum": 0
+ },
+ "padding": {
+ "$ref": "#/definitions/padding"
+ },
+ "fontSize": {
+ "type": "number",
+ "minimum": 0,
+ "description": "Font size in px."
+ }
+ }
+ },
+ "iconButton": {
+ "type": "object",
+ "title": "Icon Button",
+ "description": "A compact icon-only button.",
+ "required": [
+ "id",
+ "type",
+ "icon",
+ "action"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "Unique element identifier. Must be unique across all elements in the card."
+ },
+ "type": {
+ "const": "iconButton"
+ },
+ "icon": {
+ "$ref": "#/definitions/iconRef",
+ "description": "Icon to display in the button."
+ },
+ "action": {
+ "$ref": "#/definitions/action"
+ },
+ "size": {
+ "type": "number",
+ "minimum": 0
+ },
+ "color": {
+ "$ref": "#/definitions/colorValue"
+ },
+ "backgroundColor": {
+ "$ref": "#/definitions/colorValue"
+ },
+ "borderRadius": {
+ "type": "number",
+ "minimum": 0,
+ "description": "Corner radius in px. Set to half of size for circle, 0 for square."
+ }
+ }
+ },
+ "link": {
+ "type": "object",
+ "title": "Link",
+ "description": "An inline text link that triggers an action.",
+ "required": [
+ "id",
+ "type",
+ "text",
+ "action"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "Unique element identifier. Must be unique across all elements in the card."
+ },
+ "type": {
+ "const": "link"
+ },
+ "text": {
+ "type": "string"
+ },
+ "action": {
+ "$ref": "#/definitions/action"
+ },
+ "color": {
+ "$ref": "#/definitions/colorValue"
+ },
+ "underline": {
+ "type": "boolean",
+ "default": true
+ },
+ "fontSize": {
+ "type": "number",
+ "minimum": 0,
+ "description": "Font size in px."
+ }
+ }
+ },
+ "table": {
+ "type": "object",
+ "title": "Table",
+ "description": "Renders a data table with headers and rows.",
+ "required": [
+ "id",
+ "type",
+ "columns",
+ "rows"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "Unique element identifier. Must be unique across all elements in the card."
+ },
+ "type": {
+ "const": "table"
+ },
+ "columns": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "minItems": 1,
+ "description": "Header labels."
+ },
+ "rows": {
+ "type": "array",
+ "items": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "description": "Row data. Cell values support {{placeholder}}."
+ },
+ "headerBackgroundColor": {
+ "$ref": "#/definitions/colorValue"
+ },
+ "border": {
+ "type": "boolean"
+ },
+ "stripedRows": {
+ "type": "boolean"
+ },
+ "cellPadding": {
+ "type": "number",
+ "minimum": 0,
+ "description": "Padding inside each cell in px."
+ },
+ "fontSize": {
+ "type": "number",
+ "minimum": 0,
+ "description": "Font size for table content in px."
+ },
+ "stripedRowColor": {
+ "$ref": "#/definitions/colorValue",
+ "description": "Background color for striped rows."
+ },
+ "borderColor": {
+ "$ref": "#/definitions/colorValue",
+ "description": "Color for table borders."
+ }
+ }
+ }
+ },
+ "cardStyle": {
+ "type": "object",
+ "description": "Visual settings for the message card container.",
+ "required": [
+ "background"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "background": {
+ "$ref": "#/definitions/colorValue",
+ "description": "Background color for the card container. Required: UI Kits always expect a background key. Provide an explicit color per mode, or set 'transparent' per side when no fill is wanted. If this key is omitted, the card inherits a color from its surrounding context, which is incorrect."
+ },
+ "borderRadius": {
+ "type": "number",
+ "minimum": 0,
+ "description": "Corner radius in px."
+ },
+ "borderColor": {
+ "$ref": "#/definitions/colorValue"
+ },
+ "borderWidth": {
+ "type": "number",
+ "minimum": 0
+ },
+ "padding": {
+ "$ref": "#/definitions/padding"
+ }
+ }
+ }
+ }
+}
+```
+
diff --git a/docs.json b/docs.json
index f2ad5f2c5..455edff8d 100644
--- a/docs.json
+++ b/docs.json
@@ -104,6 +104,27 @@
]
}
]
+ },
+ {
+ "tab": "Card Builder",
+ "hidden": true,
+ "pages": [
+ {
+ "group": "Card Builder",
+ "pages": [
+ "card-builder/overview",
+ "card-builder/building-cards",
+ "card-builder/elements",
+ "card-builder/schema"
+ ]
+ },
+ {
+ "group": "Guides",
+ "pages": [
+ "card-builder/example-order-status"
+ ]
+ }
+ ]
}
]
},
@@ -5963,6 +5984,7 @@
"/ai-agents/agent-builder/instructions",
"/ai-agents/agent-builder/knowledge-base/overview",
"/ai-agents/agent-builder/tools/overview",
+ "/ai-agents/agent-builder/card-messages",
"/ai-agents/agent-builder/mcp/overview",
"/ai-agents/agent-builder/frontend-actions/overview",
"/ai-agents/agent-builder/variables/overview"
@@ -5987,6 +6009,7 @@
"/ai-agents/mastra-actions",
"/ai-agents/mastra-tools",
"/ai-agents/mastra-runtime-context",
+ "/ai-agents/mastra-card-messages",
{
"group": "Guides",
"pages": [
@@ -6012,6 +6035,7 @@
"/ai-agents/crew-ai",
"/ai-agents/crew-ai-actions",
"/ai-agents/crew-ai-tools",
+ "/ai-agents/crew-ai-card-messages",
{
"group": "Guides",
"pages": [
@@ -6033,6 +6057,7 @@
"/ai-agents/agno",
"/ai-agents/agno-actions",
"/ai-agents/agno-tools",
+ "/ai-agents/agno-card-messages",
{
"group": "Guides",
"pages": [
@@ -6054,6 +6079,7 @@
"/ai-agents/vercel",
"/ai-agents/vercel-actions",
"/ai-agents/vercel-tools",
+ "/ai-agents/vercel-card-messages",
{
"group": "Guides",
"pages": [
@@ -6073,6 +6099,7 @@
"icon": "/images/icons/lang-graph.svg",
"pages": [
"/ai-agents/langgraph",
+ "/ai-agents/langgraph-card-messages",
{
"group": "Guides",
"pages": [
@@ -6094,6 +6121,7 @@
"/ai-agents/ag2",
"/ai-agents/ag2-actions",
"/ai-agents/ag2-tools",
+ "/ai-agents/ag2-card-messages",
{
"group": "Guides",
"pages": [
@@ -6115,6 +6143,7 @@
"/ai-agents/ag-ui",
"/ai-agents/ag-ui-actions",
"/ai-agents/ag-ui-tools",
+ "/ai-agents/ag-ui-card-messages",
{
"group": "Guides",
"pages": [
diff --git a/images/card-builder/build-1-heading.mp4 b/images/card-builder/build-1-heading.mp4
new file mode 100644
index 000000000..4cb4cff7c
Binary files /dev/null and b/images/card-builder/build-1-heading.mp4 differ
diff --git a/images/card-builder/build-2-details.mp4 b/images/card-builder/build-2-details.mp4
new file mode 100644
index 000000000..5c67f258b
Binary files /dev/null and b/images/card-builder/build-2-details.mp4 differ
diff --git a/images/card-builder/build-3-buttons.mp4 b/images/card-builder/build-3-buttons.mp4
new file mode 100644
index 000000000..b6dbde354
Binary files /dev/null and b/images/card-builder/build-3-buttons.mp4 differ
diff --git a/images/card-builder/build-4-actions.mp4 b/images/card-builder/build-4-actions.mp4
new file mode 100644
index 000000000..56b2223cd
Binary files /dev/null and b/images/card-builder/build-4-actions.mp4 differ
diff --git a/images/card-builder/build-5-fallback.mp4 b/images/card-builder/build-5-fallback.mp4
new file mode 100644
index 000000000..53e5750ee
Binary files /dev/null and b/images/card-builder/build-5-fallback.mp4 differ
diff --git a/images/card-builder/editor.png b/images/card-builder/editor.png
new file mode 100644
index 000000000..e793acc21
Binary files /dev/null and b/images/card-builder/editor.png differ
diff --git a/images/card-builder/nav-card-builder.png b/images/card-builder/nav-card-builder.png
new file mode 100644
index 000000000..95333a196
Binary files /dev/null and b/images/card-builder/nav-card-builder.png differ
diff --git a/images/card-builder/notification.png b/images/card-builder/notification.png
new file mode 100644
index 000000000..87e5c004f
Binary files /dev/null and b/images/card-builder/notification.png differ
diff --git a/images/card-builder/template-library.png b/images/card-builder/template-library.png
new file mode 100644
index 000000000..a903c4455
Binary files /dev/null and b/images/card-builder/template-library.png differ
diff --git a/snippets/ai-agents/card-messages.mdx b/snippets/ai-agents/card-messages.mdx
new file mode 100644
index 000000000..756098696
--- /dev/null
+++ b/snippets/ai-agents/card-messages.mdx
@@ -0,0 +1,44 @@
+Your [Bring Your Own Agent (BYOA)](/ai-agents/cometchat-ag-ui-byoa) can reply with flexible, interactive cards — buttons, images, progress bars, layouts — instead of plain text. You design each card in [Card Builder](/card-builder/overview) so it renders uniformly, and your agent returns the card as JSON.
+
+## Enable card messages
+
+1. Open your BYOA agent in the dashboard.
+2. Turn on **Enable card messages**.
+
+Card messages are **opt-in** and off by default.
+
+## How it works
+
+When card messages are enabled, CometChat gives your agent a **card reference — working examples plus a field reference** — describing the same structure documented in the [Card JSON Schema](/card-builder/schema). Your agent returns a card simply by responding with **JSON that follows that reference**, and CometChat renders it as a native card in the chat.
+
+You only supply **what** card to send — the **how** is automatic. The format CometChat uses to recognize a card in your agent's response is part of the injected reference and is handled for you, **as long as card messages stays enabled**. This holds even if you use your own instructions or a predefined card: keep the feature on and just provide the card content. Don't disable it and try to emit cards from the raw schema alone — your agent won't have the format, and the card won't render.
+
+
+A reply is delivered as an ordered sequence of **elements** — plain-text segments and at most **one card**. So an agent can send a card on its own, or with text before and/or after it, in a single reply. To present multiple sections *inside* the card, use layout elements (`row`, `column`, `grid`, `tabs`, `accordion`) rather than sending a second card.
+
+
+## Keep cards uniform
+
+Because the agent has the card reference, it *can* generate cards freely — but free-form generation drifts in layout and styling. To keep every card consistent, design it once and reuse it:
+
+1. **Design your card** visually in [Card Builder](/card-builder/overview) — see [Building an Order Status Card](/card-builder/example-order-status) for a full walkthrough.
+2. Use **Export → Copy Card JSON** to copy the finished card.
+3. Have your agent **return that exact JSON** for the relevant reply, rather than composing a card from scratch.
+
+
+A fixed card renders exactly as designed. If it includes `{{placeholder}}` variables, your agent must fill them in with real values **before** returning the JSON — CometChat passes the JSON through as-is and does not resolve placeholders.
+
+
+## Reference
+
+
+
+ The complete schema your agent's card JSON must conform to.
+
+
+ Design and export cards visually — palette, canvas, elements, actions, and variables.
+
+
+ Build an interactive Order Status card from scratch, step by step.
+
+