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

# Preview a template

> POST /v1/templates/preview — render an unsaved template draft with data. Powers a live editor.

Render an unsaved draft — the template fields travel in the request body, so nothing is stored. This is the endpoint behind the dashboard's live template editor.

**`POST /v1/templates/preview`**

To render a template you've already saved, use [POST /v1/templates/{id}/render](/api-reference/templates/render) instead, which references it by id.

## Body parameters

All fields are optional — send the draft fields you want to render.

<ParamField body="subject" type="string">
  Draft subject line with merge variables.
</ParamField>

<ParamField body="html" type="string">
  Draft HTML body.
</ParamField>

<ParamField body="text" type="string">
  Draft plain-text body.
</ParamField>

<ParamField body="data" type="object">
  Merge variables to substitute. HTML values are escaped before insertion into the `html` field.
</ParamField>

## Request

<CodeGroup>
  ```bash cURL theme={null}
  curl https://api.drin.run/v1/templates/preview \
    -H "Authorization: Bearer $DRIN_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "subject": "Hi {{name}}",
      "html": "<b>Welcome, {{name}}!</b>",
      "data": { "name": "Sam" }
    }'
  ```

  ```typescript Node.js theme={null}
  import { DrinClient } from "@drin00/sdk";

  const drin = new DrinClient({ apiKey: process.env.DRIN_API_KEY });

  const draft = await drin.templates.preview({
    subject: "Hi {{name}}",
    html: "<b>Welcome, {{name}}!</b>",
    data: { name: "Sam" },
  });
  ```
</CodeGroup>

## Response

<ResponseField name="subject" type="string">
  The rendered subject.
</ResponseField>

<ResponseField name="html" type="string | null">
  The rendered HTML, or `null` when not supplied or on a syntax error.
</ResponseField>

<ResponseField name="text" type="string | null">
  The rendered text, or `null`.
</ResponseField>

<ResponseField name="missing" type="string[]">
  Referenced variables absent from `data`.
</ResponseField>

<ResponseField name="error" type="string">
  Present only when a draft field has a template syntax error. The request still returns `200 OK` so the editor can show the message inline.
</ResponseField>

```json 200 OK theme={null}
{
  "subject": "Hi Sam",
  "html": "<b>Welcome, Sam!</b>",
  "text": null,
  "missing": []
}
```

## Syntax error

A malformed block (e.g. an unclosed `{{#if}}`) returns `200` with an `error` string rather than a 4xx, so a live editor can surface it without treating it as a failed request.

```json 200 OK · with error theme={null}
{
  "subject": "Hi Sam",
  "html": null,
  "text": null,
  "missing": [],
  "error": "unexpected end of input in {{#if"
}
```

<Note>
  **HTML escaping.** Values in `data` are HTML-escaped before substitution into `html`. Use the triple-brace `{{{raw}}}` form only for values you trust to be safe markup.
</Note>
