# Render blocks to email HTML

`POST /v1/templates/render`

Requires an API key with the `templates:read` scope. [About keys and scopes](/docs/api/authentication)

Renders a block tree and theme to the HTML and plain text a recipient would get, without saving anything: the builder preview, plain-text view and HTML export. Merge tags show their defaults, or pass `contactId` to render them as that contact would see them (not from an embed session). `warnings` flags problems such as a missing unsubscribe link or an oversized message.

## Request body

- `schemaVersion` (integer, optional, min > 0, max 1000) — The block format version.
- `blocks` (EmailBlockInput[], required, at least 1 item, at most 200 items) — At most 200 blocks across the entire tree and five levels including the root. Footer blocks must remain at root. Known child fields are validated recursively.
  - `id` (string, required, 1–128 characters) — Identifies the block within the template; unique among its blocks.
  - `type` (string, required, 1–64 characters) — The block type: `header`, `heading`, `text`, `image`, `button`, `divider`, `spacer`, `columns`, `columns3`, `imagetext`, `imagegroup`, `boxed`, `quote`, `list`, `product`, `video`, `social`, `menu`, `html`, `section`, `footer`, `repeat`, `shared`. Each type reads its own fields next to `type`; an unknown type is kept but not validated.
  - `style` (EmailBlockStyleInput, optional) — Visual overrides for this block, such as colours, font and spacing.
    - `backgroundColor` (string, optional) — Fill behind the block.
    - `fontFamily` (string, optional, one of `Arial`, `Verdana`, `Georgia`, `Tahoma`, `Times New Roman`, `Courier New`, `Inter`, `Roboto`, `Open Sans`, `Lato`, `Montserrat`, `Poppins`, `DM Sans`, `Nunito`, `Work Sans`, `Oswald`, `Playfair Display`, `Merriweather`, `Lora`, `Libre Baskerville`, `EB Garamond`) — A font every client has (Arial, Verdana, Georgia, Tahoma, Times New Roman, Courier New), or a web font, which shows where the client loads it and falls back to a safe font elsewhere.
    - `fontSize` (integer, optional, min 12, max 72) — Text size in px, 12 to 72.
    - `mobileFontSize` (integer, optional, min 12, max 72) — Text size in px on phones (screens up to 620px), 12 to 72.
    - `padding` (object, optional) — Space inside the block in px, 0 to 100 per side; omitted sides keep their default.
      - `top` (integer, optional, min 0, max 100)
      - `right` (integer, optional, min 0, max 100)
      - `bottom` (integer, optional, min 0, max 100)
      - `left` (integer, optional, min 0, max 100)
    - `borderWidth` (integer, optional, min 0, max 10) — Border thickness in px; 0 for none.
    - `borderStyle` (string, optional, one of `solid`, `dashed`, `dotted`) — Border line style.
    - `borderColor` (string, optional) — Border colour.
    - `borderRadius` (integer, optional, min 0, max 100) — Corner rounding in px, 0 to 100.
    - `textColor` (string, optional) — Text colour.
    - `linkColor` (string, optional) — Colour of links in the text.
    - `letterSpacing` (number, optional, min -2, max 20) — Space between letters in px, such as 3 for a spaced-out eyebrow line.
    - `textTransform` (string, optional, one of `none`, `uppercase`) — Set to `uppercase` to capitalise all text.
    - `lineHeight` (number, optional, min 1, max 3) — A multiple of the font size.
    - `fontWeight` (string, optional, one of `regular`, `bold`) — Text weight.
    - `fontStyle` (string, optional, one of `normal`, `italic`) — Text style.
    - `inset` (boolean, optional) — Draw the background and border as a box within the content width, not across the whole row.
  - `visibleIf` (object, optional) — Show the block only to contacts these segment rules match, checked as each message is rendered. Omit to show it to everyone. Not allowed on the footer.
    - One of: **Match all**
      - `all` (object[], required, at least 1 item, at most 20 items) — Every rule or nested group must match.
    - One of: **Match any**
      - `any` (object[], required, at least 1 item, at most 20 items) — At least one rule or nested group must match.
  - `showOn` (string, optional, one of `mobile`, `desktop`) — Show the block only on phones (screens up to 620px) or only on wider screens. Clients that ignore screen size show the desktop version, and so does plain text. Omit to show it everywhere. Not allowed on the footer.
  - `columns` (object[][], optional, at most 3 items) — Nested child block arrays: exactly two for columns, three for columns3. Each child follows this block contract. Omit to retain legacy text columns.
  - `blocks` (object[], optional, at most 200 items) — A section's child blocks, drawn inside its box; or a repeat block's, written out once per item of its `list`, where `{{ item.<field> }}` reads that item. Repeats do not nest.
- `theme` (EmailThemeInput, required) — Theme values this email overrides.
  - `font` (string, optional, up to 200 characters) — Body font stack, such as `Inter, sans-serif`.
  - `hfont` (string, optional, up to 200 characters) — Heading font stack.
  - `bg` (string, optional) — Background of the email card, as hex.
  - `canvas` (string, optional) — Background behind the card, as hex.
  - `text` (string, optional) — Default text colour, as hex.
  - `accent` (string, optional) — Brand colour for buttons and highlights, as hex.
  - `link` (string, optional) — Link colour, as hex.
  - `width` (string, optional, one of `560px`, `600px`, `680px`) — Width of the email card on wide screens.
  - `radius` (string, optional, one of `0px`, `6px`, `12px`, `16px`, `24px`, `999px`) — Corner rounding of the email's card.
  - `btnRadius` (string, optional, one of `0px`, `6px`, `12px`, `16px`, `24px`, `999px`) — Button corners; `radius` rounds the email's card and, when this is unset, buttons.
  - `btn` (string, optional, one of `solid`, `outline`) — Button style.
- `plainTextOverride` (string | null, optional, up to 100000 characters) — Plain text used instead of the version generated from the blocks.
- `contactId` (string, optional, uuid) — A contact whose values fill the merge tags and decide each block's `visibleIf`.
- `subject` (string, optional, 1–998 characters) — The subject line, returned rendered.
- `data` (object, optional) — Sample data for `{{ event.properties.* }}` tags and repeat lists: what a transactional send's `data` or a journey's event would carry. Without it, a repeat shows once with its item tags as written.

## Returns

Returns `200 OK` with a `TemplateRender` in `data`. Otherwise returns an error; [Errors](/docs/api/errors) lists every code and which to retry.

- `html` (string, required) — The rendered HTML.
- `plainText` (string, required) — The rendered plain-text version.
- `subject` (string, optional) — The subject with merge tags filled in.
- `sizeBytes` (integer, required, min 0, max 9007199254740991) — Size of the HTML in bytes.
- `warnings` (object[], required) — Problems that do not stop rendering, such as a size that risks clipping.
  - `code` (string, required) — A stable code for the kind of problem.
  - `title` (string, required) — A short summary.
  - `detail` (string, required) — What is wrong and how to fix it.

## Example

```bash
curl -X POST https://api.kirora.io/v1/templates/render \
  -H "Authorization: Bearer $KIRORA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "blocks": [
      {
        "id": "id_example",
        "type": "type_example"
      }
    ],
    "theme": {}
  }'
```

Response `200`:

```json
{
  "data": {
    "html": "html_example",
    "plainText": "plainText_example",
    "subject": "Your order is on its way",
    "sizeBytes": 0,
    "warnings": [
      {
        "code": "code_example",
        "title": "title_example",
        "detail": "detail_example"
      }
    ]
  }
}
```
