Relay SMS Platform

Using SMS Templates

Required for Starter Tier

If you're on the Starter tier ($19/mo), templates are REQUIRED. You cannot send messages without using one of our 9 pre-approved templates.

The relay.messages.send() method will return a 402 TEMPLATE_REQUIRED error for Starter tier accounts.

Relay provides 9 production-ready templates for common use cases with built-in validation, type safety, and compliance features.

Why Templates are Required (Starter Tier)

Starter tier uses shared phone numbers that must comply with strict carrier regulations:

  • Carrier compliance - Shared numbers require pre-approved message patterns
  • Spam prevention - Templates prevent abuse and maintain high deliverability
  • 10DLC requirements - Only 2FA and Customer Care campaign types allowed
  • Quality assurance - Professional, tested message formats

Pro tier (post-launch) provides dedicated 10DLC numbers with custom message sending.

Template Benefits (All Tiers)

  • Save time - Pre-written messages for common scenarios
  • Type-safe - Full TypeScript support with auto-completion
  • Validated - Runtime validation catches errors before sending
  • Compliance-ready - 10DLC campaign metadata included
  • SMS-optimized - Character counting and segment calculation built-in

Installation

TerminalCode
npm install @relay-works/templates

Quick Start

JavascriptCode
const { getTemplate, renderTemplate } = require('@relay-works/templates'); // Get a template const otpTemplate = getTemplate('otp-verify'); // Render with your data const result = renderTemplate(otpTemplate, { code: '482916', company: 'Acme' }); console.log(result.text); // "482916 is your Acme verification code." console.log(result.segments); // 1

Available Templates

Authentication Templates (4)

OTP Verification

Send one-time password codes for 2FA.

JavascriptCode
const template = getTemplate('otp-verify'); const result = renderTemplate(template, { code: '482916', company: 'Acme' }); // "482916 is your Acme verification code."

Variables:

  • code (string) - 6-digit verification code
  • company (string) - Your company name

Best for: Two-factor authentication, login verification, account verification


Password Reset

Send password reset links with expiration time.

JavascriptCode
const template = getTemplate('password-reset'); const result = renderTemplate(template, { company: 'Acme', url: 'https://relay.link/rst-x7k', minutes: 15 }); // "Reset your Acme password: https://relay.link/rst-x7k. Link expires in 15 min."

Variables:

  • company (string) - Your company name
  • url (string) - Password reset URL (use short links)
  • minutes (number) - Expiration time in minutes

Best for: Password recovery, account access restoration


New Login Alert

Notify users of new login from unrecognized device.

JavascriptCode
const template = getTemplate('new-login-alert'); const result = renderTemplate(template, { company: 'Acme', location: 'New York, NY', device: 'iPhone 15', url: 'https://relay.link/secure' }); // "New login to your Acme account from iPhone 15 in New York, NY. Not you? Secure account: https://relay.link/secure"

Variables:

  • company (string) - Your company name
  • location (string) - City and state/country
  • device (string) - Device name
  • url (string) - Security action URL

Best for: Security notifications, suspicious activity alerts


Account Security Alert

Generic security notification for account changes.

JavascriptCode
const template = getTemplate('account-security-alert'); const result = renderTemplate(template, { company: 'Acme', action: 'password changed', url: 'https://relay.link/help' }); // "Your Acme account security: password changed. Didn't do this? https://relay.link/help"

Variables:

  • company (string) - Your company name
  • action (string) - What security action occurred
  • url (string) - Help/support URL

Best for: Password changes, email updates, 2FA settings changes


Transaction Templates (4)

Order Confirmed

Confirm order placement with tracking link.

JavascriptCode
const template = getTemplate('order-confirmed'); const result = renderTemplate(template, { company: 'Acme Store', orderNumber: 'A1B2C3', itemCount: 3, amount: '49.99', url: 'https://relay.link/order-123' }); // "Acme Store: Order #A1B2C3 confirmed! 3 items, $49.99. Track: https://relay.link/order-123"

Variables:

  • company (string) - Your store name
  • orderNumber (string) - Order ID
  • itemCount (number) - Number of items
  • amount (string) - Total amount (formatted)
  • url (string) - Order tracking URL

Best for: E-commerce order confirmations


Order Shipped

Notify when order has shipped.

JavascriptCode
const template = getTemplate('order-shipped'); const result = renderTemplate(template, { company: 'Acme', orderNumber: 'A1B2C3', carrier: 'USPS', trackingNumber: '9400111899562537599698', url: 'https://relay.link/track-123' }); // "Acme: Order #A1B2C3 shipped via USPS. Tracking: 9400111899562537599698. Track: https://relay.link/track-123"

Variables:

  • company (string) - Your company name
  • orderNumber (string) - Order ID
  • carrier (string) - Shipping carrier (USPS, UPS, FedEx, etc.)
  • trackingNumber (string) - Carrier tracking number
  • url (string) - Tracking URL

Best for: Shipping notifications, delivery updates


Payment Confirmed

Confirm successful payment received.

JavascriptCode
const template = getTemplate('payment-confirmed'); const result = renderTemplate(template, { company: 'Acme', amount: '49.99', last4: '4242', invoiceNumber: 'INV-001' }); // "Payment received! $49.99 charged to card ending in 4242. Invoice: INV-001. Thank you! - Acme"

Variables:

  • company (string) - Your company name
  • amount (string) - Payment amount (formatted)
  • last4 (string) - Last 4 digits of payment method
  • invoiceNumber (string) - Invoice/receipt number

Best for: Payment confirmations, receipt notifications


Payment Failed

Alert when payment has failed.

JavascriptCode
const template = getTemplate('payment-failed'); const result = renderTemplate(template, { company: 'Acme', amount: '49.99', reason: 'insufficient funds', url: 'https://relay.link/payment' }); // "Payment failed: $49.99 - insufficient funds. Update payment: https://relay.link/payment - Acme"

Variables:

  • company (string) - Your company name
  • amount (string) - Failed payment amount
  • reason (string) - Reason for failure
  • url (string) - Payment update URL

Best for: Failed payment alerts, billing issues


Appointment Templates (1)

Appointment Reminder

Send appointment reminders with confirmation option.

JavascriptCode
const template = getTemplate('appointment-reminder'); const result = renderTemplate(template, { company: 'Acme Clinic', date: 'Jan 15', time: '2:00 PM', location: 'Downtown Office', confirmUrl: 'https://relay.link/confirm' }); // "Reminder: Your Acme Clinic appointment is Jan 15 at 2:00 PM at Downtown Office. Confirm: https://relay.link/confirm"

Variables:

  • company (string) - Your business name
  • date (string) - Appointment date (keep short)
  • time (string) - Appointment time
  • location (string) - Location name
  • confirmUrl (string) - Confirmation URL

Best for: Appointment reminders, booking confirmations, calendar events

Validation

Templates include built-in validation to catch errors before sending.

JavascriptCode
const { validateTemplateData } = require('@relay-works/templates'); const template = getTemplate('otp-verify'); // Validate your data const validation = validateTemplateData(template, { code: '123', // Too short! company: 'A'.repeat(50) // Too long! }); if (!validation.valid) { validation.errors.forEach(error => { console.log(`${error.field}: ${error.message}`); console.log(`Suggestion: ${error.suggestion}`); }); } // Output: // code: Must be exactly 6 characters // Suggestion: Use a 6-digit verification code // company: Must be 20 characters or less // Suggestion: Use a shorter company name or abbreviation

Sending Templates with Relay

Starter Tier: This is Your Primary API

For Starter tier users, the template API (sendTypedTemplate / POST /v1/messages/send-template) is the only way to send messages. The examples below are not optional - they are required.

JavascriptCode
const { RelayAPI } = require('@relay-works/sdk-js'); const relay = new RelayAPI({ apiKey: process.env.RELAY_API_KEY }); async function sendOTP(phoneNumber, code) { // Starter tier: Use sendTypedTemplate (required) const message = await relay.messages.sendTypedTemplate('otp-verify', { to: phoneNumber, data: { code, company: 'Acme' } }); console.log(`Sent! Message ID: ${message.id}`); console.log(`Segments: ${message.template.sms_segments}`); return message; } // Usage await sendOTP('+15551234567', '482916');

Template Discovery

Find templates programmatically:

JavascriptCode
const { templates, getTemplatesByCategory, getTemplatesByTag, searchTemplates } from '@relay-works/templates'; // All templates console.log(`${templates.length} templates available`); // Get by category const authTemplates = getTemplatesByCategory('authentication'); console.log(`${authTemplates.length} auth templates`); // Get by tag const securityTemplates = getTemplatesByTag('security'); // Search const passwordTemplates = searchTemplates('password');

Character Counting

Templates automatically calculate SMS segments:

JavascriptCode
const template = getTemplate('order-confirmed'); const result = renderTemplate(template, { company: 'Acme Store', orderNumber: 'A1B2C3', itemCount: 3, amount: '49.99', url: 'https://relay.link/order-123' }); console.log(`Message: ${result.text}`); console.log(`Characters: ${result.characterCount}`); console.log(`Segments: ${result.segments}`); console.log(`Cost estimate: $${result.segments * 0.02}`);

URL Shortening

Always use short URLs in templates to save characters:

JavascriptCode
// ❌ Don't do this const longUrl = 'https://mystore.com/orders/a1b2c3/tracking?utm_source=sms'; // ✅ Do this const shortUrl = 'https://relay.link/ord-123'; const result = renderTemplate(template, { company: 'Acme', orderNumber: 'A1B2C3', url: shortUrl // Saves 40+ characters! });

URL Shortening Services

Use URL shortening services like:

  • bit.ly - Free tier available
  • TinyURL - Simple and free
  • Custom domain - Best for branding (e.g., acme.link/xxx)

Best Practices

1. Keep Company Names Short

JavascriptCode
// ✅ Good company: 'Acme' company: 'ABC Co' // ❌ Avoid company: 'Acme Corporation International Inc.'

2. Use Consistent Formatting

JavascriptCode
// Consistent amount formatting amount: '49.99' // Always 2 decimal places amount: '149.00' // Even for whole numbers // Consistent date formatting date: 'Jan 15' // Short month + day time: '2:00 PM' // 12-hour format

3. Test Before Sending

JavascriptCode
// Always test rendering first const result = renderTemplate(template, data); console.log('Preview:', result.text); console.log('Segments:', result.segments); console.log('Cost:', `$${result.segments * 0.02}`); // Then send if (result.segments <= 2) { // Keep costs reasonable await relay.messages.send({ to, message: result.text }); }

4. Handle Errors Gracefully

JavascriptCode
const { validateTemplateData, renderTemplate } = require('@relay-works/templates'); async function sendTemplate(templateId, data, recipient) { const template = getTemplate(templateId); // Validate first const validation = validateTemplateData(template, data); if (!validation.valid) { console.error('Validation failed:', validation.errors); return { success: false, errors: validation.errors }; } // Render const result = renderTemplate(template, data); // Send try { const message = await relay.messages.send({ to: recipient, message: result.text }); return { success: true, messageId: message.id }; } catch (error) { console.error('Send failed:', error); return { success: false, error: error.message }; } }

Compliance Features

Templates include 10DLC compliance metadata:

JavascriptCode
const template = getTemplate('otp-verify'); console.log(template.compliance); // { // campaignType: '2FA', // riskLevel: 'LOW', // requiresOptIn: false, // containsAuthCode: true, // shaftScore: 0 // }

This helps when registering 10DLC campaigns (Pro tier and above).

TypeScript Support

Full type safety with auto-completion:

TypeScriptCode
import type { TemplateId, TemplateData, RenderResult } from '@relay-works/templates'; // Type-safe template ID const templateId: TemplateId = 'otp-verify'; // Type-safe data for specific template const data: TemplateData<'otp-verify'> = { code: '482916', company: 'Acme' // TypeScript will error if you're missing required fields! }; // Render function returns typed result const result: RenderResult = renderTemplate(getTemplate(templateId), data);

Custom Templates

Want to create your own templates? Contact us at support@relay.works for enterprise template customization.


Related Documentation:

Upgrade to Pro for Custom Messages

Want to send custom messages without templates? Pro tier (post-launch) provides:

  • Dedicated 10DLC phone numbers
  • Custom message sending via relay.messages.send()
  • All campaign types supported
  • Custom sender identity

Contact us for Pro tier early access: support@relay.works

Last modified on