Templates
Create a Template
Templates have a unique slug, a subject line, and an HTML body. Both subject and body support {{variable}} interpolation.
curl -X POST http://localhost:3891/v1/templates \
-H "x-api-key: pgn_..." \
-H "Content-Type: application/json" \
-d '{
"slug": "welcome-email",
"name": "Welcome Email",
"subject": "Welcome, {{name}}!",
"body": "<h1>Welcome to {{company}}</h1><p>Hi {{name}}, thanks for signing up.</p>",
"sampleData": {"name": "Alice", "company": "Acme"}
}'
const template = await pigeons.templates.create({
slug: 'welcome-email',
name: 'Welcome Email',
subject: 'Welcome, {{name}}!',
body: '<h1>Welcome to {{company}}</h1><p>Hi {{name}}, thanks for signing up.</p>',
sampleData: { name: 'Alice', company: 'Acme' },
})
Slug rules
- Lowercase letters, numbers, and hyphens only
- Must be unique across all templates
- Used as a stable identifier in API calls (alternative to
tpl_IDs)
Variables
Use {{variableName}} in both the subject and body. Variables are replaced with values from the data object at send time.
<h1>Welcome to {{company}}</h1>
<p>Hi {{name}},</p>
<p>Your account is ready. Your plan: {{plan}}.</p>
Sent with:
{
"data": {
"name": "Alice",
"company": "Acme",
"plan": "Pro"
}
}
Produces:
<h1>Welcome to Acme</h1>
<p>Hi Alice,</p>
<p>Your account is ready. Your plan: Pro.</p>
Sample Data
The sampleData field stores default variable values for previewing the template without passing data:
{
"sampleData": {
"name": "Alice",
"company": "Acme",
"plan": "Pro"
}
}
This data is used by the preview endpoint and is never sent to real recipients.
Preview a Template
Render a template without sending:
curl -X POST http://localhost:3891/v1/templates/welcome-email/preview \
-H "x-api-key: pgn_..." \
-H "Content-Type: application/json" \
-d '{"data": {"name": "Bob", "company": "Widgets Inc"}}'
If no data is provided, the template's sampleData is used.
Response:
{
"subject": "Welcome, Bob!",
"html": "<h1>Welcome to Widgets Inc</h1>...",
"text": "Welcome to Widgets Inc..."
}
The response includes both HTML and a plain-text version automatically generated from the HTML.
Using Templates in Sends
Direct send
Pass the template slug or ID in templateId, and variables in data:
curl -X POST http://localhost:3891/v1/emails \
-H "x-api-key: pgn_..." \
-H "Content-Type: application/json" \
-d '{
"to": "alice@example.com",
"templateId": "welcome-email",
"data": {"name": "Alice", "company": "Acme"}
}'
const email = await pigeons.emails.send({
to: 'alice@example.com',
templateId: 'welcome-email',
data: { name: 'Alice', company: 'Acme' },
})
The subject is rendered from the template. You can override it by passing subject explicitly.
In campaigns
Assign a template to a campaign. The templateData provides variables:
const campaign = await pigeons.campaigns.create({
name: 'Product Launch',
templateId: 'product-launch',
templateData: { launchDate: '2024-06-01', featureName: 'Dark Mode' },
audienceFilter: { tags: { contains: 'newsletter' } },
})
In sequences
Each email step in a sequence can reference a template:
const sequence = await pigeons.sequences.create({
name: 'Onboarding',
steps: [
{ type: 'email', templateId: 'welcome-email', subject: 'Welcome!' },
{ type: 'delay', delayDuration: '1d' },
{ type: 'email', templateId: 'getting-started' },
],
})
Lookup by Slug or ID
All template endpoints accept either the tpl_ prefixed ID or the slug:
# By slug
curl http://localhost:3891/v1/templates/welcome-email -H "x-api-key: pgn_..."
# By ID
curl http://localhost:3891/v1/templates/tpl_abc123... -H "x-api-key: pgn_..."
Versioning
Templates are automatically versioned. The version field starts at 1 and increments when you update the subject or body. This lets you track changes over time.
const updated = await pigeons.templates.update('welcome-email', {
body: '<h1>New design</h1><p>Hi {{name}}</p>',
})
console.log(updated.version) // 2
Updating only name or sampleData does not increment the version.
Delete a Template
curl -X DELETE http://localhost:3891/v1/templates/welcome-email \
-H "x-api-key: pgn_..."
Deleting a template does not affect emails already sent using it.