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

> ## Agent Instructions
> Install the Courier skill before writing code: `npx skills add trycourier/courier-skills`. It carries the verified SDK shapes and the rules you cannot get wrong.
> Authenticate every request with `Authorization: Bearer <API_KEY>`. A workspace has several environments and each has its own keys, which are plain `pk_` strings with no environment prefix. Start with Test.
> Send with `client.send.message`, the default import of the v7 Node SDK. Reference a template by its `nt_` id or its alias.
> A send accepts a bare Elemental element list, but storing content on a template requires the top-level elements wrapped in a channel element.
> Templates and journeys can be built in the Courier app or created through the API. Either way they live in the workspace and are referenced by ID when you send.
> The hosted MCP server is https://mcp.courier.com. For a briefing on what Courier is and when to use it, read https://www.courier.com/llms.txt.
> Prefer the Guides tab for how-do-I questions and the Docs tab for how-does-it-behave questions. The API reference lives under /api-reference.

# Design Studio

> The visual template editor: canvas, per-channel content, blocks, variables, preview, and publish.

export const Endpoint = ({method, path, name, href, children, bare}) => {
  const verb = String(method || "").toUpperCase();
  const title = verb + " " + path;
  const label = children || name || path;
  if (bare) {
    return href ? <a href={href}><code>{title}</code></a> : <code>{title}</code>;
  }
  if (!href) {
    return <span className="cx-endpoint" data-method={verb} title={title}>
        <span className="cx-endpoint-label">{label}</span>
        <span className="cx-endpoint-method">{verb}</span>
      </span>;
  }
  return <a className="cx-endpoint" data-method={verb} href={href} title={title}>
      <span className="cx-endpoint-label">{label}</span>
      <span className="cx-endpoint-method">{verb}</span>
    </a>;
};

export const AppLink = ({href, children, name, bare}) => {
  const label = children || name || "Open in Courier";
  if (bare) {
    return <a href={href} target="_blank" rel="noreferrer">{label}</a>;
  }
  return <a className="cx-endpoint" data-kind="app" href={href} target="_blank" rel="noreferrer">
      <span className="cx-endpoint-label">{label}</span>
      <span className="cx-endpoint-method" aria-hidden="true">↗</span>
    </a>;
};

export const Doc = ({href, children, name, bare}) => {
  const label = children || name || href;
  if (bare) {
    return <a href={href}>{label}</a>;
  }
  return <a className="cx-endpoint" data-kind="doc" href={href}>
      <span className="cx-endpoint-label">{label}</span>
      <span className="cx-endpoint-method">DOC</span>
    </a>;
};

You write a notification here rather than in code, and a product manager can edit the wording after you ship it. One template holds every channel the message goes out on, each with its own content.

<Frame>
  <img src="https://mintcdn.com/courier-4f1f25dc/fN1MbwzHtG3Vhos5/assets/design-studio.webp?fit=max&auto=format&n=fN1MbwzHtG3Vhos5&q=85&s=51850c52555d0647e10435c5d0bc6ef2" alt="Design Studio: the channel rail and blocks panel on the left, the canvas in the center, and the styles panel on the right" width="1400" height="876" data-path="assets/design-studio.webp" />
</Frame>

## Design a template

<Steps>
  <Step title="Create a Template">
    Open <AppLink href="https://app.courier.com/content/templates">Templates</AppLink>, select **Add template**, and choose **Design Studio v2**. Name it and create it.

    <Note>
      This page documents **Design Studio v2**. The other editor in the console is <Doc href="/docs/design/templates/classic-designer">Classic Designer</Doc>.
    </Note>
  </Step>

  <Step title="Pick a channel and its routing">
    Select the **Email** channel tab to activate it. Open the **routing selector** in the toolbar to choose which Provider delivers it. Routing configurations are reusable across Templates, so a change applies everywhere. See <Doc href="/docs/send/routing">routing</Doc>.
  </Step>

  <Step title="Add content">
    Drag blocks onto the canvas: **Text** for the message, **Button** for the call to action, plus **Heading**, **Image**, **Divider**, and **Spacer**. Select a block to edit it inline. Use the settings panel for alignment, size, and color. Courier auto-saves.

    <Frame>
      <img src="https://mintcdn.com/courier-4f1f25dc/fN1MbwzHtG3Vhos5/assets/design-studio.webp?fit=max&auto=format&n=fN1MbwzHtG3Vhos5&q=85&s=51850c52555d0647e10435c5d0bc6ef2" alt="The template editor: channel rail and blocks on the left, canvas in the center, styles panel on the right" width="1400" height="876" data-path="assets/design-studio.webp" />
    </Frame>
  </Step>

  <Step title="Insert a variable">
    Type `{{` to open the variable picker, or select the variable icon in the block toolbar. Variables are **double-braced**:

    * `{{profile.name}}` for a Profile field
    * `{{data.invite_url}}` for send data
    * `{{tenant.name}}` and `{{tenant.properties.tier}}` for the <Doc href="/docs/tenants/context">tenant</Doc> on the send
    * `{{urls.preferences}}` and `{{urls.unsubscribe}}` for the built-in links

    Every variable needs its namespace prefix. A bare `{{invite_url}}` does not fall back to `data`, so the editor marks it invalid. See <Doc href="/docs/design/templates/variables">variables</Doc>.
  </Step>

  <Step title="Build per-channel variants">
    Switch channel tabs to build variants for SMS, push, in-app, and chat. Each channel gets an editor built for its format. Courier adapts shared content to each channel's requirements.
  </Step>

  <Step title="Preview and send a test">
    Select **Preview & Test**, create a test event, then fill the `data` and `profile` objects with values matching your variables:

    ```json theme={null}
    {
      "data": { "invite_url": "https://www.acme-corp.com/invite" },
      "profile": { "email": "sarah@acme-corp.com", "name": "Sarah Bennett" }
    }
    ```

    The preview renders every channel variant with your data. A variable still showing as raw `{{...}}` means the path does not match your test event. **Send Test** delivers a live copy to yourself, so you catch broken links before publishing.
  </Step>

  <Step title="Apply a Brand and publish">
    Optionally apply a <Doc href="/docs/design/brands">Brand</Doc> from the toolbar for a consistent logo, colors, header, and footer. Then select **Publish**. Edits stay in the draft until you publish.

    Copy the Template ID from the top of the editor.
  </Step>
</Steps>

## Layout

Three areas, left to right:

1. **Channel tabs** switch between Email, SMS, Push, In-App, Slack, and MS Teams.
2. **Canvas** is where you drag blocks and edit content.
3. **Settings** holds the selected block's options.

The toolbar carries the Brand selector, routing selector, version history, **Preview & Test**, and <Doc href="/docs/design/templates/template-settings">template settings</Doc> (name, alias, subscription Topic, message tags).

## Channels

Not every block works on every channel.

| Channel             | Blocks    | Notes                                                                                                               |
| ------------------- | --------- | ------------------------------------------------------------------------------------------------------------------- |
| **Email**           | All       | Full HTML, images, HTML blocks, Brand header and footer, and custom <Doc href="/docs/design/elemental/fonts">fonts</Doc> |
| **SMS**             | Text only | No formatting. Variables work. Carrier character limits apply.                                                      |
| **Push**            | Text only | Title and body. Length limits vary by platform.                                                                     |
| **In-App**          | Text only | Renders in the <Doc href="/docs/in-app/overview">Courier Inbox</Doc>.                                                    |
| **Slack**           | Subset    |                                                                                                                     |
| **Microsoft Teams** | Subset    |                                                                                                                     |

## Available blocks

| Block          | What it does                                                | Notes                                                                                                                               |
| -------------- | ----------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| **Heading**    | Large text for titles and section headers                   | Choose the heading level (H1, H2, H3). A heading is a text block with a heading level, so it also supports variables and alignment. |
| **Text**       | Paragraphs of body copy                                     | Rich formatting (bold, italic, links, lists) on email. Variables work on every channel, with plain text on SMS, push, and Inbox.    |
| **Image**      | Embeds an image                                             | Set the image URL (or a variable), alt text for accessibility, an optional link, and width or alignment.                            |
| **Button**     | Clickable call-to-action button                             | See [Buttons](#buttons) for label, link, and style settings.                                                                        |
| **Spacer**     | Adds vertical space between blocks                          | Adjust the height in the block settings.                                                                                            |
| **Divider**    | Horizontal line between sections                            | Set color, thickness, and corner radius in the block settings.                                                                      |
| **List**       | Bulleted or numbered list                                   | See [Lists](#lists) for ordered vs. unordered types and looping over a data array.                                                  |
| **Column**     | Multi-column layout                                         | See [Columns](#columns) for column count and per-cell styling.                                                                      |
| **HTML**       | Raw HTML for custom markup                                  | See [HTML](#html) for inline blocks and whole-email HTML.                                                                           |
| **Blockquote** | Quoted or highlighted text for testimonials and pull quotes | Not in the default sidebar yet. Add it from the slash menu or when it is enabled for your workspace.                                |

## Adding blocks

<Steps>
  <Step title="Select a channel">
    Pick a channel from the left sidebar.
  </Step>

  <Step title="Drag a block onto the canvas">
    Drag a block from the block sidebar to the spot you want.
  </Step>

  <Step title="Reorder as needed">
    Drag blocks up or down to reorder them.
  </Step>
</Steps>

<Frame caption="Block Sidebar">
  <img src="https://mintcdn.com/courier-4f1f25dc/fN1MbwzHtG3Vhos5/assets/designer-v2-toolbar.webp?fit=max&auto=format&n=fN1MbwzHtG3Vhos5&q=85&s=0f42bd934972e032d090696d5d9151e1" alt="Block sidebar in Design Studio" width="2204" height="1304" data-path="assets/designer-v2-toolbar.webp" />
</Frame>

## Block settings

Select a block and its settings open in the right panel. <Doc href="/docs/design/templates/blocks">Block settings</Doc> is the reference for every setting each block exposes, with its default.
Click a block to open its settings in the right panel. They vary by block type and may include:

* **Frame**: padding and margin.
* **Border**: border style and radius.
* **Alignment**: text and content alignment.
* **Colors**: background and text colors.

<Frame caption="Block Settings">
  <img src="https://mintcdn.com/courier-4f1f25dc/fN1MbwzHtG3Vhos5/assets/designer-v2-block-settings.webp?fit=max&auto=format&n=fN1MbwzHtG3Vhos5&q=85&s=33e2ee15ca27989548d1416b39663b6f" alt="Block settings panel" width="1620" height="1260" data-path="assets/designer-v2-block-settings.webp" />
</Frame>

## Copying and removing blocks

When you select a block, action icons appear:

* **Copy**: duplicate the block directly below.
* **Delete**: remove the block from the canvas.

<Frame caption="Block Actions">
  <img src="https://mintcdn.com/courier-4f1f25dc/fN1MbwzHtG3Vhos5/assets/designer-v2-block-remove.webp?fit=max&auto=format&n=fN1MbwzHtG3Vhos5&q=85&s=6096682fa0009caedbe187006ef74c76" alt="Copy and delete block actions" width="1508" height="718" data-path="assets/designer-v2-block-remove.webp" />
</Frame>

## Buttons

Select a button block to open its settings:

* **Label**: text on the button. <Doc href="/docs/design/templates/variables">Variables</Doc> work here (e.g. `View {{data.product_name}}`).
* **Link URL**: where the button goes. Variables work here too.
* **Alignment**: left, center, or right.
* **Background color**: button fill color.
* **Border radius**: corner rounding.
* **Border size**: outline thickness.
* **Padding**: space around the button.

<Frame caption="Button Block">
  <img src="https://mintcdn.com/courier-4f1f25dc/fN1MbwzHtG3Vhos5/assets/designer-v2-button-new.webp?fit=max&auto=format&n=fN1MbwzHtG3Vhos5&q=85&s=707b04750dd7aa5bf88dcf06466bb8de" alt="Button block in Design Studio" width="1968" height="892" data-path="assets/designer-v2-button-new.webp" />
</Frame>

## Lists

Select a List block to open its settings:

* **Type**: toggle between **Unordered** (bulleted) and **Ordered** (numbered).
* **Padding**: horizontal and vertical padding in pixels.
* **Loop on**: repeat the list for each item in a data array (see below).

<Frame caption="List Settings">
  <img src="https://mintcdn.com/courier-4f1f25dc/fN1MbwzHtG3Vhos5/assets/designer-v2-list-settings.webp?fit=max&auto=format&n=fN1MbwzHtG3Vhos5&q=85&s=6437015ed04ab696c3b2e4500f197b99" alt="List block settings panel showing type, padding, and loop on toggle" width="1394" height="1122" data-path="assets/designer-v2-list-settings.webp" />
</Frame>

### Looping over data

The **Loop on** toggle repeats the list for each item in a data array you send on the <Endpoint method="POST" path="/send" name="Send a message" href="/docs/api-reference/send/send-a-message">Send API</Endpoint> call.

<Steps>
  <Step title="Enable Loop on">
    Select the List block and turn on **Loop on**.
  </Step>

  <Step title="Set the data path">
    Enter a **Data path** pointing to an array in your `data` payload (e.g. `data.order_items`). The path must start with `data.`.
  </Step>

  <Step title="Reference the current item">
    In list item text, reference fields on the current item as `{{$.item.name}}` and `{{$.item.price}}`.
  </Step>
</Steps>

Given this Send API payload:

```json Send request lines highlight={6-10} theme={null}
{
  "message": {
    "to": { "user_id": "user_123" },
    "template": "nt_01kx4h2jdafq8bk9aftxak4b40",
    "data": {
      "order_items": [
        { "name": "Wireless Mouse", "quantity": 1, "price": "$29.99" },
        { "name": "USB-C Hub", "quantity": 2, "price": "$44.99" },
        { "name": "Laptop Stand", "quantity": 1, "price": "$59.99" }
      ]
    }
  }
}
```

Set the data path to `data.order_items`, then use `{{$.item.name}}`, `{{$.item.quantity}}`, and `{{$.item.price}}` in your list item text. Courier expands the list at send time, one item per array entry.

<Frame caption="List Loop Preview">
  <img src="https://mintcdn.com/courier-4f1f25dc/fN1MbwzHtG3Vhos5/assets/designer-v2-list-preview.webp?fit=max&auto=format&n=fN1MbwzHtG3Vhos5&q=85&s=0710eecbb4f0989c9125b9d7892cd73e" alt="Preview showing expanded list items from a looped data array" width="3296" height="1926" data-path="assets/designer-v2-list-preview.webp" />
</Frame>

A data path must start with `data.` and point to an array. Design Studio validates it against your <Doc href="/docs/design/templates/overview">test event</Doc> data, so you catch mismatches before sending.

At render time, Courier's <Doc href="/docs/design/elemental/control-flow#loop">loop evaluation</Doc> expands every iteration into one list block, so spacing and formatting stay consistent. For loop logic the List block does not support (nested loops, conditional items, custom markup), use an [HTML block](#html) with raw Handlebars.

## Columns

A column block starts as a two-column row with equal widths. Each cell is an independent container that accepts any block type, including nested columns.

Select the column block to configure it:

* **Columns count**: choose 1, 2, 3, or 4 columns.
* **Frame**: horizontal and vertical padding (pixels) and background color for each cell.
* **Border**: width, radius, and color for each cell.
* **Conditions**: show or hide the block based on profile or data values.

Frame and border settings apply per cell, so you can style each column independently.

<Frame caption="Column Layout Settings">
  <img src="https://mintcdn.com/courier-4f1f25dc/fN1MbwzHtG3Vhos5/assets/designer-v2-column-cell-settings.webp?fit=max&auto=format&n=fN1MbwzHtG3Vhos5&q=85&s=d5b464554089afd831e5868f508e27de" alt="Column layout settings panel in Design Studio" width="1730" height="1202" data-path="assets/designer-v2-column-cell-settings.webp" />
</Frame>

Columns render differently per channel:

| Channel            | Behavior                                                                   |
| ------------------ | -------------------------------------------------------------------------- |
| **Email**          | Full multi-column layout using MJML for maximum email client compatibility |
| **Push**           | Columns stack vertically (single-column fallback)                          |
| **SMS**            | Not applicable. Content renders as plain text                              |
| **In-App (Inbox)** | Full support with responsive behavior                                      |

Mobile email clients usually stack columns vertically, so keep to 2 or 3 columns and write content that reads well both side by side and stacked.

## HTML

HTML gives you full control of your markup for custom tables, tracking pixels, or porting an existing HTML email into Courier. There are two ways to use it. Picking the wrong one returns a confusing `Invalid input`.

| Your goal                                             | Use               | How                                                           |
| ----------------------------------------------------- | ----------------- | ------------------------------------------------------------- |
| Add one custom section alongside drag-and-drop blocks | Inline HTML block | Add an HTML block in Design Studio                            |
| Bring an existing full HTML email into Courier        | Whole-email HTML  | Set `raw.html` on the email channel                           |
| Add HTML to a template programmatically (API)         | Whole-email HTML  | `raw.html` (the inline block is not writable via the API yet) |

### Add an inline HTML block

The HTML block gives you a code editor in the right panel. Enter standard HTML (like `<div>`, `<table>`, or `<img>`) and inline CSS. Your changes appear in the canvas preview as you type.

<Frame caption="HTML Block">
  <img src="https://mintcdn.com/courier-4f1f25dc/fN1MbwzHtG3Vhos5/assets/designer-v2-custom-code-new.webp?fit=max&auto=format&n=fN1MbwzHtG3Vhos5&q=85&s=357dd49ae1e721e8f9c8d58d5c24f85e" alt="HTML block in Design Studio" width="2294" height="1146" data-path="assets/designer-v2-custom-code-new.webp" />
</Frame>

**An inline HTML block is a fragment, not a full page.** Leave out `<!DOCTYPE html>`, `<html>`, `<head>`, and `<body>`, because Courier composes your markup alongside the other blocks. For a full document, use [whole-email HTML](#send-a-full-html-email).

The expand icon in the editor's top-right corner opens a larger window.

### Variables and Handlebars

HTML blocks support <Doc href="/docs/design/templates/variables">variables</Doc> in `{{variable}}` syntax and every <Doc href="/docs/design/templates/variables">Handlebars helper</Doc>, including `{{#if}}` for conditionals and `{{#each}}` for arrays. Inside an inline HTML block, Handlebars resolve automatically, with no transformer to configure.

This is the place for helper expressions. A rich-text block turns `{{` into a variable chip, so a helper call typed there is flagged invalid. An HTML block takes raw Handlebars as written.

```handlebars theme={null}
<ul>
{{#each data.items}}
  <li>{{this.name}}: {{this.price}}</li>
{{/each}}
</ul>
```

Use this for loop structures beyond the [List block's Loop on feature](#lists), such as nested loops or fully custom markup.

<Frame caption="Handlebars Example">
  <img src="https://mintcdn.com/courier-4f1f25dc/fN1MbwzHtG3Vhos5/assets/designer-v2-custom-code-rendered-handlebars.webp?fit=max&auto=format&n=fN1MbwzHtG3Vhos5&q=85&s=7d58900f29fddd2f5da8cd1165c44a67" alt="Handlebars and variables in HTML block" width="2726" height="1630" data-path="assets/designer-v2-custom-code-rendered-handlebars.webp" />
</Frame>

Variables and Handlebars expressions resolve on send, so <Doc href="/docs/design/templates/overview">preview mode</Doc> shows the raw syntax rather than sample values.

### Send a full HTML email

To use a complete HTML document, put it on the email <Doc href="/docs/design/elemental/elements/channel">channel</Doc> node's `raw.html`. Declare the `handlebars` transformer so your `{{variables}}` resolve. The `meta` title sets the subject line, and `raw.html` replaces that channel's rendered body.

```json theme={null}
{
  "content": {
    "version": "2022-01-01",
    "elements": [
      {
        "type": "channel",
        "channel": "email",
        "elements": [
          { "type": "meta", "title": "Your order confirmation" }
        ],
        "raw": {
          "transformers": ["handlebars"],
          "html": "<!DOCTYPE html><html><body><h1>Hi {{name}}</h1><p>Your order shipped.</p></body></html>"
        }
      }
    ]
  }
}
```

This shape works with <Endpoint method="POST" path="/notifications" name="Create Notification Template" href="/docs/api-reference/templates/create-notification-template" /> and <Endpoint method="PUT" path="/notifications/{id}/content" name="Replace Notification Content" href="/docs/api-reference/templates/replace-notification-content" />, and renders your markup as written.

<Warning>
  The inline `type: "html"` block is not writable through the Templates API yet, and sending one to <Endpoint method="POST" path="/notifications" name="Create Notification Template" href="/docs/api-reference/templates/create-notification-template" /> or <Endpoint method="PUT" path="/notifications/{id}/content" name="Replace Notification Content" href="/docs/api-reference/templates/replace-notification-content" /> returns `Invalid input`. Use [whole-email `raw.html`](#send-a-full-html-email) instead.
</Warning>
