Transactional Emails
Transactional emails are triggered programmatically for individual users—order confirmations, password resets, account notifications, and other time-sensitive communications.
Transactional vs Marketing
| Transactional | Marketing |
|---|
| Triggered by user action | Sent to segments |
| One recipient at a time | Multiple recipients |
| Time-sensitive | Can be scheduled |
| Expected by user | Promotional |
| Higher deliverability | May be filtered |
Examples of transactional emails:
- Order confirmation
- Shipping notification
- Password reset
- Account verification
- Payment receipt
- Security alert
Two Sending Modes
1. Template Mode (Recommended)
Create reusable templates in the dashboard, send via API using the template slug.
curl -X POST "https://api.sequenzy.com/api/v1/transactional/send" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"to": "[email protected]",
"slug": "order-confirmation",
"variables": {
"orderNumber": "ORD-12345",
"total": "$99.99",
"deliveryDate": "January 20, 2024"
}
}'
Benefits:
- Non-developers can edit templates
- Consistent branding
- Version control in dashboard
- Analytics per template
2. Direct Mode
Send email content directly without a pre-created template.
curl -X POST "https://api.sequenzy.com/api/v1/transactional/send" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"to": "[email protected]",
"subject": "Your Order #{{orderNumber}}",
"body": "<h1>Thank you for your order!</h1><p>Order: {{orderNumber}}</p>",
"variables": {
"orderNumber": "ORD-12345"
}
}'
Use cases:
- Dynamic content generated by your app
- One-off emails that don’t need templates
- Testing and development
Creating Templates
In the Dashboard
- Go to Transactional in your dashboard
- Click Create Template
- Enter a slug (URL-friendly identifier)
- Design your email with the visual editor
- Add variable placeholders where needed
- Save and activate
Template Slugs
Slugs are unique identifiers for your templates:
order-confirmation
password-reset
welcome-email
invoice-reminder
shipping-update
Slugs are auto-generated from the template name but can be customized. They cannot be changed after creation.
Variables
Variables let you personalize transactional emails.
Syntax
<p>Hello {{FIRST_NAME}},</p>
<p>Your order {{orderNumber}} has shipped!</p>
With Defaults
Provide fallback values for missing variables:
<p>Hello {{FIRST_NAME|Customer}},</p>
If FIRST_NAME is empty, “Customer” is used.
System Variables
These are automatically available:
| Variable | Source |
|---|
{{NAME}} | Subscriber full name |
{{FIRST_NAME}} | Subscriber first name |
{{LAST_NAME}} | Subscriber last name |
{{EMAIL}} | Subscriber email |
Custom Attributes
Any subscriber custom attributes are available:
<p>Your plan: {{plan}}</p>
<p>Account ID: {{userId}}</p>
Passed Variables
Variables passed in the API request:
{
"variables": {
"orderNumber": "ORD-123",
"total": "$99.99"
}
}
<p>Order: {{orderNumber}}</p>
<p>Total: {{total}}</p>
API Reference
Send Email
POST /api/v1/transactional/send
Template mode:
{
"to": "[email protected]",
"slug": "template-slug",
"variables": {
"key": "value"
}
}
Direct mode:
{
"to": "[email protected]",
"subject": "Email Subject",
"body": "<html>Email content</html>",
"variables": {
"key": "value"
}
}
Response:
List Templates
GET /api/v1/transactional
Response:
{
"success": true,
"data": [
{
"id": "trans_abc123",
"slug": "order-confirmation",
"name": "Order Confirmation",
"subject": "Your Order #{{orderNumber}}",
"enabled": true
}
]
}
Get Template Details
GET /api/v1/transactional/:slug
Response:
{
"success": true,
"data": {
"id": "trans_abc123",
"slug": "order-confirmation",
"name": "Order Confirmation",
"subject": "Your Order #{{orderNumber}}",
"body": "<html>...</html>",
"enabled": true,
"variables": ["orderNumber", "total", "items"]
}
}
Auto-Creation
When you send to an email that doesn’t exist:
- A new subscriber is created automatically
- Status is set to
active
- Custom attributes from
variables are saved (if applicable)
This makes integration seamless—no need to create subscribers first.
Error Handling
Common Errors
| Error | Cause | Solution |
|---|
Template not found | Invalid slug | Check slug spelling |
Template disabled | Template is deactivated | Enable in dashboard |
Missing required fields | No to, slug/subject | Include required fields |
Missing variables | Template has unfilled variables | Pass all required variables |
No sender configured | No sender profile | Set up sender in dashboard |
Sending paused | Account sending is paused | Check sending status |
Response Codes
| Code | Description |
|---|
200 | Email queued successfully |
400 | Validation error |
401 | Invalid API key |
404 | Template not found |
500 | Server error |
Best Practices
1. Use Templates
Templates are easier to maintain and update:
✓ Template: Update once, affects all future sends
✗ Direct: Must update every code path that sends email
2. Handle Variables Gracefully
Always provide defaults or check for required variables:
<!-- Good: Has default -->
<p>Hi {{FIRST_NAME|there}},</p>
<!-- Better: Check in template -->
{{#if firstName}}
<p>Hi {{firstName}},</p>
{{else}}
<p>Hi there,</p>
{{/if}}
3. Log Job IDs
Save the returned job ID for debugging:
const response = await sendTransactional({
to: user.email,
slug: "order-confirmation",
variables: { orderNumber: order.id },
});
await saveToDatabase({
orderId: order.id,
emailJobId: response.data.jobId,
});
4. Use Meaningful Slugs
✓ "order-confirmation"
✓ "password-reset"
✓ "trial-expiring-reminder"
✗ "email1"
✗ "template_2024_01"
5. Test in Development
Use test emails before production:
const to =
process.env.NODE_ENV === "development"
? "[email protected]"
: user.email;
Integration Examples
Order Confirmation
async function sendOrderConfirmation(order) {
await fetch("https://api.sequenzy.com/api/v1/transactional/send", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.SEQUENZY_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
to: order.customerEmail,
slug: "order-confirmation",
variables: {
orderNumber: order.id,
total: formatCurrency(order.total),
items: order.items.map((i) => i.name).join(", "),
shippingAddress: formatAddress(order.shippingAddress),
estimatedDelivery: formatDate(order.estimatedDelivery),
},
}),
});
}
Password Reset
async function sendPasswordReset(email, resetToken) {
const resetUrl = `${APP_URL}/reset-password?token=${resetToken}`;
await fetch("https://api.sequenzy.com/api/v1/transactional/send", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.SEQUENZY_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
to: email,
slug: "password-reset",
variables: {
resetUrl,
expiresIn: "24 hours",
},
}),
});
}
Welcome Email
async function sendWelcome(user) {
await fetch("https://api.sequenzy.com/api/v1/transactional/send", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.SEQUENZY_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
to: user.email,
slug: "welcome",
variables: {
firstName: user.firstName,
dashboardUrl: `${APP_URL}/dashboard`,
docsUrl: `${APP_URL}/docs`,
},
}),
});
}