Templates

Pre-built templates with dynamic variable substitution. HTML, React Email (.tsx), and plain text bodies all supported. Required-variable enforcement prevents silent missing-variable bugs.

Templates are created and managed through the dashboard. Each template has a name, subject, HTML body, optional plain text body, and an optional list of **required variables**.

## Three template formats

• **HTML** — paste raw HTML; `{{variableName}}` placeholders are substituted at send time
• **React Email** — write a `.tsx` component using @react-email/components; Posthawk renders it server-side and substitutes `{{}}` placeholders in the rendered HTML
• **Plain text** — simple text bodies for transactional emails that don't need styling

You can switch a template's format at any time without losing the existing body. The dashboard editor surfaces a one-shot hint pointing this out.

## Variables

Variables use double-curly-brace syntax: `{{variableName}}`. Pass a `variables` object on send and Posthawk substitutes them in the subject, HTML body, and text body.

Explicit values in the request (subject, html, text) override template values for per-send customization.

## Required variables (production-grade)

Each template can declare a list of `required_variables` (managed via the dashboard's "Req" pill toggle next to each variable, or via the database's `email_templates.required_variables` column).

When you send with a template that has required variables, Posthawk validates them at send time:

• If the variables object is missing any required variable, the API returns 400 with `error: "missing_required_variables"` and a `missing` array listing the names
• If a required variable is present but empty (`""`), it also fails — empty strings would render as blank text, which is almost always a bug
• Non-required variables that are missing render as the literal placeholder (e.g. `{{tagline}}`) — same as before

This catches the classic "I sent 5,000 emails saying 'Hello {{name}}'" bug at the API layer instead of the recipient inbox.
POST/v1/sendAPI Key

Send an email using a template with variable substitution.

ParameterTypeInDescription
fromrequiredstringbodySender email address
torequiredstring[]bodyArray of recipient email addresses
templateIdrequiredstringbodyUUID of the email template
variablesRecord<string, string>bodyKey-value pairs for template variable substitution
subjectstringbodyOverride template subject

Request

bash
curl -X POST https://your-posthawk-instance.com/v1/send \
  -H "Content-Type: application/json" \
  -H "X-API-Key: your_api_key" \
  -d '{
    "from": "hello@yourdomain.com",
    "to": ["user@example.com"],
    "templateId": "template-uuid-here",
    "variables": {
      "firstName": "John",
      "companyName": "Acme Inc",
      "unsubscribeUrl": "https://example.com/unsub/123"
    }
  }'

Response

json
{
  "success": true,
  "scheduled": false,
  "jobId": "abc-123-def",
  "message": "Email queued for sending",
  "statusUrl": "/v1/send/abc-123-def"
}
POST/v1/renderAPI Key

Render a template with variables without sending. Useful for previewing templates or generating HTML for other purposes.

ParameterTypeInDescription
templateIdrequiredstringbodyUUID of the email template to render
variablesRecord<string, string>bodyKey-value pairs for template variable substitution

Request

bash
curl -X POST https://your-posthawk-instance.com/v1/render \
  -H "Content-Type: application/json" \
  -H "X-API-Key: your_api_key" \
  -d '{
    "templateId": "template-uuid-here",
    "variables": {
      "firstName": "John",
      "companyName": "Acme Inc"
    }
  }'

Response

json
{
  "success": true,
  "html": "<h1>Welcome, John!</h1><p>Thanks for joining Acme Inc.</p>",
  "text": "Welcome, John! Thanks for joining Acme Inc.",
  "subject": "Welcome to Acme Inc"
}