> ## 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.

# Create a template

> POST /v1/templates — save a reusable email template with {{handlebars}} merge variables, scoped to one project.

Save a reusable email with merge variables. Reference it later by id or slug from a send — the body is rendered server-side, so the markup never travels in your send call.

**`POST /v1/templates`**

Templates are scoped to a single project (sender). Use `{{handlebars}}` placeholders anywhere in the subject, HTML, or text — supply their values as `data` when you [render](/api-reference/templates/render) or [send](/api-reference/emails/send).

## Body parameters

<ParamField body="name" type="string" required>
  Human-readable name shown in the dashboard.
</ParamField>

<ParamField body="subject" type="string" required>
  Subject line. May contain merge variables.
</ParamField>

<ParamField body="html" type="string">
  HTML body. Supports `{{handlebars}}` merge variables, `{{#if}}` / `{{#each}}` blocks, and filters such as `{{name | default: "there"}}`.
</ParamField>

<ParamField body="text" type="string">
  Plain-text body. Recommended alongside `html` for clients that don't render HTML.
</ParamField>

<ParamField body="slug" type="string">
  Stable handle used as `templateId` on a send. Lowercase `[a-z0-9-]`, unique per project. Auto-derived from `name` when omitted.
</ParamField>

## Request

<CodeGroup>
  ```bash cURL theme={null}
  curl https://api.drin.run/v1/templates \
    -H "Authorization: Bearer $DRIN_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "name": "Order Receipt",
      "subject": "Receipt {{orderId}}",
      "html": "<p>Hi {{firstName}}, thanks for your order.</p>"
    }'
  ```

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

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

  const template = await drin.templates.create({
    name: "Order Receipt",
    subject: "Receipt {{orderId}}",
    html: "<p>Hi {{firstName}}, thanks for your order.</p>",
  });

  console.log(template.slug); // "order-receipt"
  ```
</CodeGroup>

## Response

Returns `201 Created` with the saved template. The `variables` array lists the merge fields the engine found — a quick way to confirm a placeholder didn't get mistyped.

```json 201 Created theme={null}
{
  "id": "tmpl_8XQ2k9",
  "slug": "order-receipt",
  "name": "Order Receipt",
  "subject": "Receipt {{orderId}}",
  "html": "<p>Hi {{firstName}}, thanks for your order.</p>",
  "text": null,
  "variables": ["firstName", "orderId"],
  "createdAt": "2026-06-02T10:00:00.000Z",
  "updatedAt": "2026-06-02T10:00:00.000Z"
}
```

<Warning>
  **Slug already in use.** A duplicate `slug` within the same project returns `409 conflict` (`template_slug_taken`). Pick a different slug or [update](/api-reference/templates/update) the existing template.
</Warning>
