@sendly/node
Official Node.js SDK for the Sendly SMS API.
Installation
npm install @sendly/node
yarn add @sendly/node
pnpm add @sendly/node
Requirements
Quick Start
import Sendly from '@sendly/node';
const sendly = new Sendly('sk_live_v1_your_api_key');
const message = await sendly.messages.send({
to: '+15551234567',
text: 'Hello from Sendly!'
});
console.log(`Message sent: ${message.id}`);
console.log(`Status: ${message.status}`);
Prerequisites for Live Messaging
Before sending live SMS messages, you need:
-
Business Verification - Complete verification in the Sendly dashboard
- International: Instant approval (just provide Sender ID)
- US/Canada: Requires carrier approval (3-7 business days)
-
Credits - Add credits to your account
- Test keys (
sk_test_*) work without credits (sandbox mode)
- Live keys (
sk_live_*) require credits for each message
-
Live API Key - Generate after verification + credits
- Dashboard → API Keys → Create Live Key
Test vs Live Keys
| Test | sk_test_v1_* | No | No | Development, testing |
| Live | sk_live_v1_* | Yes | Yes | Production messaging |
Note: You can start development immediately with a test key. Messages to sandbox test numbers are free and don't require verification.
Features
- ✅ Full TypeScript support with exported types
- ✅ Automatic retries with exponential backoff
- ✅ Rate limit handling (respects
Retry-After)
- ✅ Promise-based async/await API
- ✅ ESM and CommonJS support
- ✅ Zero runtime dependencies
Usage
Sending Messages
import Sendly from '@sendly/node';
const sendly = new Sendly('sk_live_v1_xxx');
const message = await sendly.messages.send({
to: '+15551234567',
text: 'Your verification code is: 123456'
});
const message = await sendly.messages.send({
to: '+447700900123',
text: 'Hello from MyApp!',
from: 'MYAPP'
});
Listing Messages
const { data: messages, count } = await sendly.messages.list();
const { data: messages } = await sendly.messages.list({ limit: 10 });
for (const msg of messages) {
console.log(`${msg.to}: ${msg.status}`);
}
Getting a Message
const message = await sendly.messages.get('msg_xxx');
console.log(`Status: ${message.status}`);
console.log(`Delivered: ${message.deliveredAt}`);
Rate Limit Information
await sendly.messages.send({ to: '+1555...', text: 'Hello!' });
const rateLimit = sendly.getRateLimitInfo();
if (rateLimit) {
console.log(`${rateLimit.remaining}/${rateLimit.limit} requests remaining`);
console.log(`Resets in ${rateLimit.reset} seconds`);
}
Configuration
import Sendly from '@sendly/node';
const sendly = new Sendly({
apiKey: 'sk_live_v1_xxx',
baseUrl: 'https://sendly.live/api',
timeout: 60000,
maxRetries: 5
});
Error Handling
The SDK provides typed error classes for different error scenarios:
import Sendly, {
SendlyError,
AuthenticationError,
RateLimitError,
InsufficientCreditsError,
ValidationError,
NotFoundError
} from '@sendly/node';
const sendly = new Sendly('sk_live_v1_xxx');
try {
await sendly.messages.send({
to: '+15551234567',
text: 'Hello!'
});
} catch (error) {
if (error instanceof AuthenticationError) {
console.error('Invalid API key:', error.message);
} else if (error instanceof RateLimitError) {
console.error(`Rate limited. Retry after ${error.retryAfter} seconds`);
} else if (error instanceof InsufficientCreditsError) {
console.error(`Not enough credits. Need ${error.creditsNeeded}, have ${error.currentBalance}`);
} else if (error instanceof ValidationError) {
console.error('Invalid request:', error.message);
} else if (error instanceof NotFoundError) {
console.error('Resource not found:', error.message);
} else if (error instanceof SendlyError) {
console.error(`API error [${error.code}]:`, error.message);
} else {
throw error;
}
}
Testing (Sandbox Mode)
Use a test API key (sk_test_v1_xxx) to test without sending real messages:
import Sendly, { SANDBOX_TEST_NUMBERS } from '@sendly/node';
const sendly = new Sendly('sk_test_v1_xxx');
console.log(sendly.isTestMode());
await sendly.messages.send({
to: SANDBOX_TEST_NUMBERS.SUCCESS,
text: 'Test message'
});
await sendly.messages.send({
to: SANDBOX_TEST_NUMBERS.INVALID,
text: 'Test message'
});
Available Test Numbers
+15550001234 | Instant success |
+15550001010 | Success after 10s delay |
+15550001001 | Fails: invalid_number |
+15550001002 | Fails: carrier_rejected (2s delay) |
+15550001003 | Fails: rate_limit_exceeded |
Pricing Tiers
import { CREDITS_PER_SMS, SUPPORTED_COUNTRIES } from '@sendly/node';
console.log(CREDITS_PER_SMS.domestic);
console.log(CREDITS_PER_SMS.tier1);
console.log(CREDITS_PER_SMS.tier2);
console.log(CREDITS_PER_SMS.tier3);
console.log(SUPPORTED_COUNTRIES.domestic);
console.log(SUPPORTED_COUNTRIES.tier1);
Utilities
The SDK exports validation utilities for advanced use cases:
import {
validatePhoneNumber,
getCountryFromPhone,
isCountrySupported,
calculateSegments
} from '@sendly/node';
validatePhoneNumber('+15551234567');
validatePhoneNumber('555-1234');
getCountryFromPhone('+447700900123');
getCountryFromPhone('+15551234567');
isCountrySupported('GB');
isCountrySupported('XX');
calculateSegments('Hello!');
calculateSegments('A'.repeat(200));
TypeScript
The SDK is written in TypeScript and exports all types:
import type {
SendlyConfig,
SendMessageRequest,
Message,
MessageStatus,
ListMessagesOptions,
MessageListResponse,
RateLimitInfo,
PricingTier
} from '@sendly/node';
API Reference
Sendly
Constructor
new Sendly(apiKey: string)
new Sendly(config: SendlyConfig)
Properties
messages - Messages resource
Methods
isTestMode() - Returns true if using a test API key
getRateLimitInfo() - Returns current rate limit info
getBaseUrl() - Returns configured base URL
sendly.messages
send(request: SendMessageRequest): Promise<Message>
Send an SMS message.
list(options?: ListMessagesOptions): Promise<MessageListResponse>
List sent messages.
get(id: string): Promise<Message>
Get a specific message by ID.
Support
License
MIT