Sending SMS

Learn how to send single and batch SMS messages via the API.

Sending Single Messages

Send a single SMS using the /sms endpoint:

Using TypeScript SDK

import { Transactional } from 'transactional-sdk';
 
const client = new Transactional({
  apiKey: process.env.TRANSACTIONAL_API_KEY,
});
 
const result = await client.sms.send({
  to: '+14155551234',
  templateAlias: 'otp-verification',
  templateModel: {
    code: '123456',
  },
  tag: 'verification',
  metadata: {
    userId: 'user_123',
  },
});
 
console.log(result.messageId);

Using cURL

curl -X POST https://api.usetransactional.com/v1/sms \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "to": "+14155551234",
    "templateAlias": "otp-verification",
    "templateModel": {
      "code": "123456"
    },
    "tag": "verification",
    "metadata": {
      "userId": "user_123"
    }
  }'

Response

{
  "to": "+14155551234",
  "submittedAt": "2024-01-01T00:00:00.000Z",
  "messageId": "sms_abc123",
  "errorCode": 0,
  "message": "OK"
}

Request Parameters

ParameterTypeRequiredDescription
tostringYesRecipient phone number in E.164 format
templateAliasstringOne requiredPool template alias or your custom alias
templateIdnumberOne requiredPool template ID
templateModelobjectNoVariables to substitute in template
tagstringNoTag for filtering messages (max 255 chars)
metadataobjectNoCustom key-value metadata

Batch Sending

Send up to 500 messages in a single API call:

Using TypeScript SDK

const results = await client.sms.sendBatch([
  {
    to: '+14155551234',
    templateAlias: 'otp-verification',
    templateModel: { code: '123456' },
  },
  {
    to: '+14155555678',
    templateAlias: 'otp-verification',
    templateModel: { code: '789012' },
  },
  {
    to: '+14155559999',
    templateAlias: 'order-shipped',
    templateModel: { orderId: 'ORD-123' },
  },
]);
 
for (const result of results) {
  console.log(`${result.to}: ${result.errorCode === 0 ? 'OK' : result.message}`);
}

Using cURL

curl -X POST https://api.usetransactional.com/v1/sms/batch \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '[
    {
      "to": "+14155551234",
      "templateAlias": "otp-verification",
      "templateModel": { "code": "123456" }
    },
    {
      "to": "+14155555678",
      "templateAlias": "otp-verification",
      "templateModel": { "code": "789012" }
    }
  ]'

Batch Response

[
  {
    "to": "+14155551234",
    "submittedAt": "2024-01-01T00:00:00.000Z",
    "messageId": "sms_abc123",
    "errorCode": 0,
    "message": "OK"
  },
  {
    "to": "+14155555678",
    "submittedAt": "2024-01-01T00:00:00.000Z",
    "messageId": "sms_def456",
    "errorCode": 0,
    "message": "OK"
  }
]

Partial Failures

In batch sending, some messages may fail while others succeed. Each message in the response array has its own status:

[
  {
    "to": "+14155551234",
    "messageId": "sms_abc123",
    "errorCode": 0,
    "message": "OK"
  },
  {
    "to": "+14155555678",
    "errorCode": 1006,
    "message": "Recipient has opted out of SMS messages"
  }
]

Message Segments

SMS messages are limited by character count:

EncodingCharacters per Segment
GSM-7 (standard)160 characters
Unicode70 characters

Messages exceeding these limits are split into multiple segments, each billed separately.

Checking Segments

The API response includes segment count:

const message = await client.sms.get('sms_abc123');
console.log('Segments:', message.segments);

Unicode Detection

Messages with non-ASCII characters automatically use Unicode encoding:

// GSM-7: 1 segment for 160 chars
await client.sms.send({
  to: '+14155551234',
  templateAlias: 'simple-alert',
  templateModel: { message: 'Hello World' },
});
 
// Unicode: 1 segment for 70 chars
await client.sms.send({
  to: '+14155551234',
  templateAlias: 'simple-alert',
  templateModel: { message: 'Hello World! ' },  // Emoji triggers Unicode
});

Tags and Metadata

Tags

Use tags to categorize messages for filtering and analytics:

await client.sms.send({
  to: '+14155551234',
  templateAlias: 'otp-verification',
  templateModel: { code: '123456' },
  tag: 'login-verification',
});
 
// Later, filter by tag
const messages = await client.sms.list({ tag: 'login-verification' });

Metadata

Store custom data with each message:

await client.sms.send({
  to: '+14155551234',
  templateAlias: 'order-confirmation',
  templateModel: { orderId: 'ORD-123' },
  metadata: {
    userId: 'user_456',
    orderId: 'order_789',
    source: 'checkout',
  },
});

Metadata is returned when retrieving message details.

Error Handling

Common Error Codes

CodeDescription
0Success
1001Invalid phone number format
1002Template not found
1003Template not approved for organization
1004No pool number available for country
1005SMS not enabled for organization
1006Recipient opted out (suppressed)

Handling Errors

try {
  const result = await client.sms.send({
    to: '+14155551234',
    templateAlias: 'otp-verification',
    templateModel: { code: '123456' },
  });
 
  if (result.errorCode !== 0) {
    console.error('Send failed:', result.message);
  }
} catch (error) {
  console.error('API error:', error.message);
}

Rate Limits

Limit TypeValue
Single send100 requests/second
Batch send10 requests/second
Batch size500 messages/request

Best Practices

1. Use Batch for Multiple Messages

When sending to multiple recipients, use batch API to reduce latency:

// Good - single API call
await client.sms.sendBatch(messages);
 
// Avoid - multiple API calls
for (const msg of messages) {
  await client.sms.send(msg);
}

2. Handle Partial Failures

Always check each result in batch responses:

const results = await client.sms.sendBatch(messages);
const failed = results.filter(r => r.errorCode !== 0);
if (failed.length > 0) {
  // Log or retry failed messages
}

3. Use Meaningful Tags

Tags help with debugging and analytics:

tag: `${featureName}-${environment}`  // e.g., "login-otp-production"

Next Steps