Pushing Templates via API
Learn how to push and sync email templates using the upsert API for CI/CD pipelines and version-controlled workflows.
Pushing Templates via API
The Push Template endpoint (PUT /templates/alias/:alias) lets you create or update templates idempotently using their alias as a stable identifier. If a template with the alias exists, it updates; if not, it creates. This is the recommended approach for CI/CD pipelines, infrastructure-as-code workflows, and any scenario where you want to declaratively manage templates.
Why Use Push Instead of Create?
| Approach | Behavior on duplicate alias | Best for |
|---|---|---|
POST /templates | Returns 500 error | One-time manual creation |
PUT /templates/alias/:alias | Updates existing template | CI/CD, automation, idempotent deploys |
With push, you can safely run your template sync script on every deploy without worrying about whether templates already exist.
Basic Usage
Push a Single Template
import { Transactional } from '@usetransactional/node';
const client = new Transactional({
apiKey: process.env.TRANSACTIONAL_API_KEY,
});
// This will create the template if it doesn't exist,
// or update it if a template with alias "welcome-email" already exists
const response = await fetch('https://api.usetransactional.com/templates/alias/welcome-email', {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'X-Server-Token': process.env.TRANSACTIONAL_SERVER_TOKEN,
},
body: JSON.stringify({
name: 'Welcome Email',
subject: 'Welcome to {{companyName}}, {{firstName}}!',
htmlBody: `
<h1>Welcome, {{firstName}}!</h1>
<p>Thanks for joining {{companyName}}. We're excited to have you.</p>
<a href="{{loginUrl}}">Get Started</a>
`,
textBody: `
Welcome, {{firstName}}!
Thanks for joining {{companyName}}.
Get started: {{loginUrl}}
`,
}),
});
const template = await response.json();
console.log(`Template ${template.alias} (ID: ${template.id}) synced.`);Push with cURL
curl -X PUT "https://api.usetransactional.com/templates/alias/welcome-email" \
-H "Content-Type: application/json" \
-H "X-Server-Token: YOUR_SERVER_TOKEN" \
-d '{
"name": "Welcome Email",
"subject": "Welcome to {{companyName}}, {{firstName}}!",
"htmlBody": "<h1>Welcome, {{firstName}}!</h1><p>Thanks for joining.</p>",
"textBody": "Welcome, {{firstName}}! Thanks for joining."
}'CI/CD Template Sync
Store your templates as files in your repo and push them on every deploy.
1. Define Templates as Files
templates/
├── welcome-email.json
├── password-reset.json
├── order-confirmation.json
└── invoice.json
Each file contains the template definition:
{
"name": "Welcome Email",
"subject": "Welcome to {{companyName}}, {{firstName}}!",
"htmlBody": "<h1>Welcome, {{firstName}}!</h1><p>Thanks for joining {{companyName}}.</p>",
"textBody": "Welcome, {{firstName}}!\n\nThanks for joining {{companyName}}."
}2. Create a Sync Script
// scripts/sync-templates.ts
import fs from 'fs';
import path from 'path';
const API_URL = process.env.TRANSACTIONAL_API_URL || 'https://api.usetransactional.com';
const SERVER_TOKEN = process.env.TRANSACTIONAL_SERVER_TOKEN;
const TEMPLATE_DIR = path.join(__dirname, '../templates');
async function syncTemplates() {
const files = fs.readdirSync(TEMPLATE_DIR).filter(f => f.endsWith('.json'));
console.log(`Syncing ${files.length} templates...`);
for (const file of files) {
const alias = path.basename(file, '.json');
const content = JSON.parse(fs.readFileSync(path.join(TEMPLATE_DIR, file), 'utf-8'));
const res = await fetch(`${API_URL}/templates/alias/${alias}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'X-Server-Token': SERVER_TOKEN!,
},
body: JSON.stringify(content),
});
if (!res.ok) {
console.error(`Failed to sync ${alias}: ${res.status} ${await res.text()}`);
process.exit(1);
}
const template = await res.json();
console.log(` ✓ ${alias} (ID: ${template.id})`);
}
console.log('All templates synced.');
}
syncTemplates();3. Add to Your CI/CD Pipeline
# GitHub Actions example
- name: Sync email templates
run: npx tsx scripts/sync-templates.ts
env:
TRANSACTIONAL_SERVER_TOKEN: ${{ secrets.TRANSACTIONAL_SERVER_TOKEN }}Request & Response
Request
PUT /templates/alias/:alias
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Template display name |
subject | string | Yes | Email subject (supports {{variables}}) |
htmlBody | string | No | HTML email body |
textBody | string | No | Plain text email body |
layoutTemplateId | number | No | Layout template ID to wrap content |
Response
{
"id": 1,
"alias": "welcome-email",
"name": "Welcome Email",
"subject": "Welcome to {{companyName}}, {{firstName}}!",
"htmlBody": "<h1>Welcome, {{firstName}}!</h1>...",
"textBody": "Welcome, {{firstName}}! ...",
"status": "ACTIVE",
"associatedServerId": 1,
"layoutTemplateId": null
}Next Steps
- Using Email Templates - Template variables, conditionals, and loops
- Sending Emails - Send emails using templates
- API Reference - Complete API documentation