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/send

Send an email using a template with variable substitution.

Authorizations

Authorizationstring · headerrequired

Bearer authentication header of the form Bearer <token>, where <token> is your API Key.

Body

fromstringrequired

Sender email address

tostring[]required

Array of recipient email addresses

templateIdstringrequired

UUID of the email template

variablesRecord<string, string>optional

Key-value pairs for template variable substitution

subjectstringoptional

Override template subject

POST /v1/send
curl -X POST https://your-posthawk-instance.com/v1/send \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer 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
{
  "success": true,
  "scheduled": false,
  "jobId": "abc-123-def",
  "message": "Email queued for sending",
  "statusUrl": "/v1/send/abc-123-def"
}
POST/v1/render

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

Authorizations

Authorizationstring · headerrequired

Bearer authentication header of the form Bearer <token>, where <token> is your API Key.

Body

templateIdstringrequired

UUID of the email template to render

variablesRecord<string, string>optional

Key-value pairs for template variable substitution

POST /v1/render
curl -X POST https://your-posthawk-instance.com/v1/render \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer your_api_key" \
  -d '{
    "templateId": "template-uuid-here",
    "variables": {
      "firstName": "John",
      "companyName": "Acme Inc"
    }
  }'
Response
{
  "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"
}