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?

ApproachBehavior on duplicate aliasBest for
POST /templatesReturns 500 errorOne-time manual creation
PUT /templates/alias/:aliasUpdates existing templateCI/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
FieldTypeRequiredDescription
namestringYesTemplate display name
subjectstringYesEmail subject (supports {{variables}})
htmlBodystringNoHTML email body
textBodystringNoPlain text email body
layoutTemplateIdnumberNoLayout 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