Skip to main content

Email Templates API

Overview

The Email Templates API provides comprehensive management of reusable email templates with versioning support. Create and maintain email templates with dynamic content, multiple versions, attachments, and tracking capabilities. Templates support both HTML and plain text content with Handlebars templating for dynamic data substitution.

Resource Description

Email templates in Stack9 consist of:

  • Template Metadata: Base template configuration including sender information and tracking settings
  • Template Versions: Multiple versions of content with independent subject lines and HTML/text bodies
  • Dynamic Content: Handlebars-based templating for personalization and dynamic data
  • Attachments: Support for file attachments via URL references
  • Template Snippets: Reusable content blocks that can be included in templates

Key Features

  • Version Control: Maintain multiple versions of each template
  • Active Version Management: Designate which version is active for sending
  • Dynamic Templating: Use Handlebars syntax for personalization
  • Preview Capabilities: Test templates with sample data before sending
  • Template Cloning: Duplicate existing templates for faster creation
  • Attachment Support: Include files via URL references

Authentication

All endpoints require API key authentication:

X-API-Key: your-api-key-here

Template Management

Create Template

Create a new email template with basic configuration.

POST /api/templates

Parameters

ParameterTypeRequiredDescription
namestringYesDisplay name for the template
from_emailstringYesSender email address (must be verified)
from_namestringNoSender display name
reply_tostringNoReply-to email address
descriptionstringNoTemplate description
typestringNoTemplate category/type for grouping
transactionalbooleanYesWhether template is transactional (bypasses unsubscribes)
open_trackingbooleanNoEnable open tracking (default: false)
click_trackingbooleanNoEnable click tracking (default: false)

Example Request

curl -X POST \
https://apis.app.stack9.co/api/templates \
-H 'X-API-Key: your-api-key-here' \
-H 'Content-Type: application/json' \
-d '{
"name": "Welcome Email",
"description": "Sent to new users after registration",
"type": "onboarding",
"from_name": "Support Team",
"from_email": "support@example.com",
"reply_to": "support@example.com",
"transactional": false,
"open_tracking": true,
"click_tracking": true
}'

Example Response

{
"id": "550e8400-e29b-41d4-a716-446655440000"
}

List Templates

Retrieve all email templates with optional filtering.

GET /api/templates

Query Parameters

ParameterTypeRequiredDescription
namestringNoFilter by template name
typestringNoFilter by template type
searchstringNoSearch across template fields
pageintegerNoPage number (default: 1)
limitintegerNoItems per page (default: 20, max: 100)

Example Request

curl -X GET \
'https://apis.app.stack9.co/api/templates?type=onboarding&page=1&limit=50' \
-H 'X-API-Key: your-api-key-here'

Example Response

{
"results": [
{
"version": 1,
"created_at": "2024-01-15T10:30:00.123Z",
"updated_at": "2024-03-20T14:45:30.456Z",
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Welcome Email",
"description": "Sent to new users after registration",
"type": "onboarding",
"from_name": "Support Team",
"from_email": "support@example.com",
"reply_to": "support@example.com",
"transactional": false,
"open_tracking": true,
"click_tracking": true
}
],
"total": 15,
"totalPages": 1
}

Get Template by ID

Retrieve a specific template by its ID.

GET /api/templates/{id}

Parameters

ParameterTypeRequiredDescription
iduuidYesTemplate ID

Example Request

curl -X GET \
https://apis.app.stack9.co/api/templates/550e8400-e29b-41d4-a716-446655440000 \
-H 'X-API-Key: your-api-key-here'

Example Response

{
"version": 2,
"created_at": "2024-01-15T10:30:00.123Z",
"updated_at": "2024-03-20T14:45:30.456Z",
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Welcome Email",
"description": "Sent to new users after registration",
"type": "onboarding",
"from_name": "Support Team",
"from_email": "support@example.com",
"reply_to": "support@example.com",
"transactional": false,
"open_tracking": true,
"click_tracking": true
}

Update Template

Update an existing template's configuration.

PUT /api/templates/{id}

Parameters

Same as Create Template, all fields are required in the update.

Example Request

curl -X PUT \
https://apis.app.stack9.co/api/templates/550e8400-e29b-41d4-a716-446655440000 \
-H 'X-API-Key: your-api-key-here' \
-H 'Content-Type: application/json' \
-d '{
"name": "Welcome Email - Updated",
"from_email": "noreply@example.com",
"from_name": "Example Team",
"transactional": false,
"open_tracking": true,
"click_tracking": false
}'

Delete Template

Delete a template and all its versions.

DELETE /api/templates/{id}

Example Request

curl -X DELETE \
https://apis.app.stack9.co/api/templates/550e8400-e29b-41d4-a716-446655440000 \
-H 'X-API-Key: your-api-key-here'

Template Versions

Each template can have multiple versions with different content. Only one version can be active at a time.

Create Template Version

Add a new version to an existing template.

POST /api/templates/{template_id}/versions

Parameters

ParameterTypeRequiredDescription
template_iduuidYesParent template ID
activebooleanYesSet as active version
subjectstringYesEmail subject line (supports Handlebars)
html_contentstringYesHTML email body (supports Handlebars)
plain_contentstringNoPlain text body
generate_plain_contentbooleanNoAuto-generate plain text from HTML
template_builder_contentobjectNoVisual builder JSON data
test_dataobjectNoSample data for previewing
data_fields_schemaarrayNoField definitions for template
attachmentsarrayNoFile attachments via URL

Attachment Object Structure

{
"name": "invoice.pdf",
"type": "application/pdf",
"url": "https://example.com/files/invoice.pdf"
}

Example Request

curl -X POST \
https://apis.app.stack9.co/api/templates/550e8400-e29b-41d4-a716-446655440000/versions \
-H 'X-API-Key: your-api-key-here' \
-H 'Content-Type: application/json' \
-d '{
"active": true,
"subject": "Welcome to {{company_name}}, {{first_name}}!",
"html_content": "<html><body><h1>Welcome {{first_name}}!</h1><p>Thank you for joining {{company_name}}.</p></body></html>",
"plain_content": "Welcome {{first_name}}! Thank you for joining {{company_name}}.",
"test_data": {
"first_name": "John",
"company_name": "Example Corp"
},
"attachments": [
{
"name": "welcome-guide.pdf",
"type": "application/pdf",
"url": "https://example.com/guides/welcome.pdf"
}
]
}'

Example Response

{
"id": "660e8400-e29b-41d4-a716-446655440001",
"version": 1
}

List Template Versions

Get all versions for a template.

GET /api/templates/{template_id}/versions

Query Parameters

ParameterTypeRequiredDescription
pageintegerNoPage number (default: 1)
limitintegerNoItems per page (default: 20)

Example Request

curl -X GET \
https://apis.app.stack9.co/api/templates/550e8400-e29b-41d4-a716-446655440000/versions \
-H 'X-API-Key: your-api-key-here'

Example Response

{
"results": [
{
"id": "660e8400-e29b-41d4-a716-446655440001",
"template_id": "550e8400-e29b-41d4-a716-446655440000",
"version": 2,
"active": true,
"subject": "Welcome to {{company_name}}, {{first_name}}!",
"html_content": "<html><body><h1>Welcome!</h1></body></html>",
"plain_content": "Welcome!",
"generate_plain_content": false,
"test_data": {
"first_name": "John",
"company_name": "Example Corp"
},
"attachments": []
},
{
"id": "660e8400-e29b-41d4-a716-446655440002",
"template_id": "550e8400-e29b-41d4-a716-446655440000",
"version": 1,
"active": false,
"subject": "Welcome!",
"html_content": "<html><body>Welcome to our service!</body></html>",
"plain_content": null,
"generate_plain_content": true,
"test_data": null,
"attachments": []
}
],
"total": 2,
"totalPages": 1
}

Get Template Version

Retrieve a specific template version.

GET /api/templates/{template_id}/versions/{id}

Example Request

curl -X GET \
https://apis.app.stack9.co/api/templates/550e8400-e29b-41d4-a716-446655440000/versions/660e8400-e29b-41d4-a716-446655440001 \
-H 'X-API-Key: your-api-key-here'

Update Template Version

Update an existing template version.

PUT /api/templates/{template_id}/versions/{id}

Parameters are the same as Create Template Version.

Example Request

curl -X PUT \
https://apis.app.stack9.co/api/templates/550e8400-e29b-41d4-a716-446655440000/versions/660e8400-e29b-41d4-a716-446655440001 \
-H 'X-API-Key: your-api-key-here' \
-H 'Content-Type: application/json' \
-d '{
"active": true,
"subject": "Welcome to {{company_name}}!",
"html_content": "<html><body><h1>Welcome!</h1><p>We are excited to have you.</p></body></html>"
}'

Delete Template Version

Remove a specific template version.

DELETE /api/templates/{template_id}/versions/{id}

Example Request

curl -X DELETE \
https://apis.app.stack9.co/api/templates/550e8400-e29b-41d4-a716-446655440000/versions/660e8400-e29b-41d4-a716-446655440001 \
-H 'X-API-Key: your-api-key-here'

Template Operations

Preview Inline Template

Preview how a template will render with substitution data without saving it.

POST /api/templates/preview/inline

Parameters

ParameterTypeRequiredDescription
substitution_dataobjectNoData for template variables
contentobjectYesTemplate content to preview
content.fromstringYesSender email address
content.subjectstringNoEmail subject with variables
content.htmlstringYesHTML content with variables
content.textstringNoPlain text content with variables

Example Request

curl -X POST \
https://apis.app.stack9.co/api/templates/preview/inline \
-H 'X-API-Key: your-api-key-here' \
-H 'Content-Type: application/json' \
-d '{
"substitution_data": {
"first_name": "Jane",
"product_name": "Stack9 Platform",
"trial_days": 30
},
"content": {
"from": "sales@example.com",
"subject": "Start your {{trial_days}}-day trial of {{product_name}}",
"html": "<html><body><h1>Hi {{first_name}}!</h1><p>Your {{trial_days}}-day trial of {{product_name}} starts today.</p></body></html>"
}
}'

Example Response

{
"subject": "Start your 30-day trial of Stack9 Platform",
"html": "<html><body><h1>Hi Jane!</h1><p>Your 30-day trial of Stack9 Platform starts today.</p></body></html>"
}

Clone Template

Create a copy of an existing template with its active version.

POST /api/templates/clone

Parameters

ParameterTypeRequiredDescription
template_iduuidYesSource template ID to clone
namestringYesName for the new template

Example Request

curl -X POST \
https://apis.app.stack9.co/api/templates/clone \
-H 'X-API-Key: your-api-key-here' \
-H 'Content-Type: application/json' \
-d '{
"template_id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Welcome Email - Copy"
}'

Example Response

{
"id": "770e8400-e29b-41d4-a716-446655440003",
"version_id": "880e8400-e29b-41d4-a716-446655440004"
}

Template Snippets

Template snippets are reusable content blocks that can be included in multiple templates.

Create Template Snippet

POST /api/template_snippets

Parameters

ParameterTypeRequiredDescription
namestringYesSnippet name
contentstringYesSnippet HTML content
descriptionstringNoSnippet description

Example Request

curl -X POST \
https://apis.app.stack9.co/api/template_snippets \
-H 'X-API-Key: your-api-key-here' \
-H 'Content-Type: application/json' \
-d '{
"name": "footer_social_links",
"description": "Standard footer with social media links",
"content": "<div class=\"footer\"><a href=\"https://twitter.com/example\">Twitter</a> | <a href=\"https://facebook.com/example\">Facebook</a></div>"
}'

List Template Snippets

GET /api/template_snippets

Example Request

curl -X GET \
https://apis.app.stack9.co/api/template_snippets \
-H 'X-API-Key: your-api-key-here'

Get Template Snippet

GET /api/template_snippets/{id}

Update Template Snippet

PUT /api/template_snippets/{id}

Delete Template Snippet

DELETE /api/template_snippets/{id}

Handlebars Templating

Stack9 uses Handlebars for dynamic content in templates.

Basic Variable Substitution

Hello {{first_name}} {{last_name}}!

Conditionals

{{#if premium_member}}
<p>Thank you for being a premium member!</p>
{{else}}
<p>Consider upgrading to premium for exclusive benefits.</p>
{{/if}}

Loops

<ul>
{{#each products}}
<li>{{name}} - ${{price}}</li>
{{/each}}
</ul>

Helpers

<!-- Format date -->
{{formatDate order_date "MMMM DD, YYYY"}}

<!-- Uppercase text -->
{{uppercase first_name}}

<!-- Default value -->
{{#if company_name}}{{company_name}}{{else}}Your Company{{/if}}

Including Snippets

{{{snippet "footer_social_links"}}}

Best Practices

Template Design

  1. Mobile Responsive: Ensure templates work on all devices
  2. Fallback Content: Provide plain text versions for better deliverability
  3. Image Optimization: Use web-optimized images with alt text
  4. Preheader Text: Include preview text for inbox display

Version Management

  1. Test Before Activating: Always test new versions with sample data
  2. Keep Previous Versions: Maintain history for rollback capability
  3. Document Changes: Use descriptions to track version changes
  4. A/B Testing: Create multiple versions for testing

Dynamic Content

  1. Default Values: Always provide fallbacks for missing data
  2. Data Validation: Validate test data matches production structure
  3. Error Handling: Handle missing or null values gracefully
  4. Preview Testing: Test with various data scenarios

Performance

  1. HTML Size: Keep HTML under 100KB for best deliverability
  2. Attachment Limits: Total attachments should not exceed 10MB
  3. Image Hosting: Use CDN for images rather than attachments
  4. CSS Inlining: Inline CSS for better email client support

Error Handling

Common Error Responses

400 Bad Request - Invalid Template Data

{
"error": {
"code": "INVALID_TEMPLATE",
"message": "Template validation failed",
"details": {
"field": "from_email",
"message": "Sender email must be from a verified domain"
}
}
}

404 Not Found - Template Not Found

{
"error": {
"code": "TEMPLATE_NOT_FOUND",
"message": "Template with specified ID does not exist",
"details": {
"template_id": "550e8400-e29b-41d4-a716-446655440000"
}
}
}

409 Conflict - Version Conflict

{
"error": {
"code": "VERSION_CONFLICT",
"message": "Cannot delete the only version of a template",
"details": {
"template_id": "550e8400-e29b-41d4-a716-446655440000",
"version_count": 1
}
}
}

422 Unprocessable Entity - Template Rendering Error

{
"error": {
"code": "TEMPLATE_RENDER_ERROR",
"message": "Failed to render template",
"details": {
"error": "Undefined variable: customer_name",
"line": 15
}
}
}

Rate Limits

EndpointLimitWindow
GET endpoints100 requests1 minute
POST/PUT endpoints50 requests1 minute
DELETE endpoints20 requests1 minute
Preview endpoint30 requests1 minute

Migration Guide

When migrating templates from another provider:

  1. Export Existing Templates: Export HTML and metadata from current provider
  2. Create Base Templates: Create template records with metadata
  3. Import Content: Create versions with HTML/text content
  4. Update Variables: Convert to Handlebars syntax
  5. Test Rendering: Use preview endpoint to verify rendering
  6. Update Integrations: Update API calls to use new template IDs

Variable Syntax Migration

ProviderOriginalStack9 Handlebars
SendGrid{{name}}{{name}}
Mailchimp`*FNAME
Mandrill`*NAME
Custom${name}{{name}}

Code Examples

Node.js - Create and Send Template

const axios = require('axios');

// Create template
async function createTemplate() {
const template = await axios.post(
'https://apis.app.stack9.co/api/templates',
{
name: 'Order Confirmation',
from_email: 'orders@example.com',
from_name: 'Example Store',
transactional: true,
open_tracking: true
},
{
headers: {
'X-API-Key': 'your-api-key-here',
'Content-Type': 'application/json'
}
}
);

// Create version
const version = await axios.post(
`https://apis.app.stack9.co/api/templates/${template.data.id}/versions`,
{
active: true,
subject: 'Order #{{order_number}} Confirmed',
html_content: `
<html>
<body>
<h1>Thank you for your order, {{customer_name}}!</h1>
<p>Order #{{order_number}} has been confirmed.</p>
<h2>Order Details:</h2>
<ul>
{{#each items}}
<li>{{name}} - Qty: {{quantity}} - ${{price}}</li>
{{/each}}
</ul>
<p><strong>Total: ${{total}}</strong></p>
</body>
</html>
`,
test_data: {
customer_name: 'John Doe',
order_number: '12345',
items: [
{ name: 'Widget', quantity: 2, price: 10.00 }
],
total: 20.00
}
},
{
headers: {
'X-API-Key': 'your-api-key-here',
'Content-Type': 'application/json'
}
}
);

return { templateId: template.data.id, versionId: version.data.id };
}

Python - Preview Template

import requests

def preview_template(template_data, substitution_data):
url = 'https://apis.app.stack9.co/api/templates/preview/inline'

payload = {
'substitution_data': substitution_data,
'content': {
'from': 'noreply@example.com',
'subject': template_data['subject'],
'html': template_data['html']
}
}

headers = {
'X-API-Key': 'your-api-key-here',
'Content-Type': 'application/json'
}

response = requests.post(url, json=payload, headers=headers)
return response.json()

# Example usage
template = {
'subject': 'Hello {{name}}!',
'html': '<h1>Welcome {{name}}</h1><p>Your account is ready.</p>'
}

data = {
'name': 'Jane Smith'
}

result = preview_template(template, data)
print(result['html']) # <h1>Welcome Jane Smith</h1><p>Your account is ready.</p>