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
.tsxcomponent 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 amissingarray 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.
/v1/sendSend an email using a template with variable substitution.
Authorizations
Bearer authentication header of the form Bearer <token>, where <token> is your API Key.
Body
fromstringrequiredSender email address
tostring[]requiredArray of recipient email addresses
templateIdstringrequiredUUID of the email template
variablesRecord<string, string>optionalKey-value pairs for template variable substitution
subjectstringoptionalOverride template subject
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"
}
}'{
"success": true,
"scheduled": false,
"jobId": "abc-123-def",
"message": "Email queued for sending",
"statusUrl": "/v1/send/abc-123-def"
}/v1/renderRender a template with variables without sending. Useful for previewing templates or generating HTML for other purposes.
Authorizations
Bearer authentication header of the form Bearer <token>, where <token> is your API Key.
Body
templateIdstringrequiredUUID of the email template to render
variablesRecord<string, string>optionalKey-value pairs for template variable substitution
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"
}
}'{
"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"
}