@sendly/node 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,329 @@
1
+ # @sendly/node
2
+
3
+ Official Node.js SDK for the [Sendly](https://sendly.live) SMS API.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @sendly/node
9
+ # or
10
+ yarn add @sendly/node
11
+ # or
12
+ pnpm add @sendly/node
13
+ ```
14
+
15
+ ## Requirements
16
+
17
+ - Node.js 18.0.0 or higher
18
+ - A Sendly API key ([get one here](https://sendly.live/dashboard))
19
+
20
+ ## Quick Start
21
+
22
+ ```typescript
23
+ import Sendly from '@sendly/node';
24
+
25
+ // Initialize with your API key
26
+ const sendly = new Sendly('sk_live_v1_your_api_key');
27
+
28
+ // Send an SMS
29
+ const message = await sendly.messages.send({
30
+ to: '+15551234567',
31
+ text: 'Hello from Sendly!'
32
+ });
33
+
34
+ console.log(`Message sent: ${message.id}`);
35
+ console.log(`Status: ${message.status}`);
36
+ ```
37
+
38
+ ## Prerequisites for Live Messaging
39
+
40
+ Before sending live SMS messages, you need:
41
+
42
+ 1. **Business Verification** - Complete verification in the [Sendly dashboard](https://sendly.live/dashboard)
43
+ - **International**: Instant approval (just provide Sender ID)
44
+ - **US/Canada**: Requires carrier approval (3-7 business days)
45
+
46
+ 2. **Credits** - Add credits to your account
47
+ - Test keys (`sk_test_*`) work without credits (sandbox mode)
48
+ - Live keys (`sk_live_*`) require credits for each message
49
+
50
+ 3. **Live API Key** - Generate after verification + credits
51
+ - Dashboard → API Keys → Create Live Key
52
+
53
+ ### Test vs Live Keys
54
+
55
+ | Key Type | Prefix | Credits Required | Verification Required | Use Case |
56
+ |----------|--------|------------------|----------------------|----------|
57
+ | Test | `sk_test_v1_*` | No | No | Development, testing |
58
+ | Live | `sk_live_v1_*` | Yes | Yes | Production messaging |
59
+
60
+ > **Note**: You can start development immediately with a test key. Messages to sandbox test numbers are free and don't require verification.
61
+
62
+ ## Features
63
+
64
+ - ✅ Full TypeScript support with exported types
65
+ - ✅ Automatic retries with exponential backoff
66
+ - ✅ Rate limit handling (respects `Retry-After`)
67
+ - ✅ Promise-based async/await API
68
+ - ✅ ESM and CommonJS support
69
+ - ✅ Zero runtime dependencies
70
+
71
+ ## Usage
72
+
73
+ ### Sending Messages
74
+
75
+ ```typescript
76
+ import Sendly from '@sendly/node';
77
+
78
+ const sendly = new Sendly('sk_live_v1_xxx');
79
+
80
+ // Basic usage
81
+ const message = await sendly.messages.send({
82
+ to: '+15551234567',
83
+ text: 'Your verification code is: 123456'
84
+ });
85
+
86
+ // With custom sender ID (international)
87
+ const message = await sendly.messages.send({
88
+ to: '+447700900123',
89
+ text: 'Hello from MyApp!',
90
+ from: 'MYAPP'
91
+ });
92
+ ```
93
+
94
+ ### Listing Messages
95
+
96
+ ```typescript
97
+ // Get recent messages (default limit: 50)
98
+ const { data: messages, count } = await sendly.messages.list();
99
+
100
+ // Get last 10 messages
101
+ const { data: messages } = await sendly.messages.list({ limit: 10 });
102
+
103
+ // Iterate through messages
104
+ for (const msg of messages) {
105
+ console.log(`${msg.to}: ${msg.status}`);
106
+ }
107
+ ```
108
+
109
+ ### Getting a Message
110
+
111
+ ```typescript
112
+ const message = await sendly.messages.get('msg_xxx');
113
+
114
+ console.log(`Status: ${message.status}`);
115
+ console.log(`Delivered: ${message.deliveredAt}`);
116
+ ```
117
+
118
+ ### Rate Limit Information
119
+
120
+ ```typescript
121
+ // After any API call, you can check rate limit status
122
+ await sendly.messages.send({ to: '+1555...', text: 'Hello!' });
123
+
124
+ const rateLimit = sendly.getRateLimitInfo();
125
+ if (rateLimit) {
126
+ console.log(`${rateLimit.remaining}/${rateLimit.limit} requests remaining`);
127
+ console.log(`Resets in ${rateLimit.reset} seconds`);
128
+ }
129
+ ```
130
+
131
+ ## Configuration
132
+
133
+ ```typescript
134
+ import Sendly from '@sendly/node';
135
+
136
+ const sendly = new Sendly({
137
+ apiKey: 'sk_live_v1_xxx',
138
+
139
+ // Optional: Custom base URL (for testing)
140
+ baseUrl: 'https://sendly.live/api',
141
+
142
+ // Optional: Request timeout in ms (default: 30000)
143
+ timeout: 60000,
144
+
145
+ // Optional: Max retry attempts (default: 3)
146
+ maxRetries: 5
147
+ });
148
+ ```
149
+
150
+ ## Error Handling
151
+
152
+ The SDK provides typed error classes for different error scenarios:
153
+
154
+ ```typescript
155
+ import Sendly, {
156
+ SendlyError,
157
+ AuthenticationError,
158
+ RateLimitError,
159
+ InsufficientCreditsError,
160
+ ValidationError,
161
+ NotFoundError
162
+ } from '@sendly/node';
163
+
164
+ const sendly = new Sendly('sk_live_v1_xxx');
165
+
166
+ try {
167
+ await sendly.messages.send({
168
+ to: '+15551234567',
169
+ text: 'Hello!'
170
+ });
171
+ } catch (error) {
172
+ if (error instanceof AuthenticationError) {
173
+ console.error('Invalid API key:', error.message);
174
+ } else if (error instanceof RateLimitError) {
175
+ console.error(`Rate limited. Retry after ${error.retryAfter} seconds`);
176
+ } else if (error instanceof InsufficientCreditsError) {
177
+ console.error(`Not enough credits. Need ${error.creditsNeeded}, have ${error.currentBalance}`);
178
+ } else if (error instanceof ValidationError) {
179
+ console.error('Invalid request:', error.message);
180
+ } else if (error instanceof NotFoundError) {
181
+ console.error('Resource not found:', error.message);
182
+ } else if (error instanceof SendlyError) {
183
+ console.error(`API error [${error.code}]:`, error.message);
184
+ } else {
185
+ throw error;
186
+ }
187
+ }
188
+ ```
189
+
190
+ ## Testing (Sandbox Mode)
191
+
192
+ Use a test API key (`sk_test_v1_xxx`) to test without sending real messages:
193
+
194
+ ```typescript
195
+ import Sendly, { SANDBOX_TEST_NUMBERS } from '@sendly/node';
196
+
197
+ const sendly = new Sendly('sk_test_v1_xxx');
198
+
199
+ // Check if in test mode
200
+ console.log(sendly.isTestMode()); // true
201
+
202
+ // Use sandbox test numbers
203
+ await sendly.messages.send({
204
+ to: SANDBOX_TEST_NUMBERS.SUCCESS, // +15550001234 - Always succeeds
205
+ text: 'Test message'
206
+ });
207
+
208
+ await sendly.messages.send({
209
+ to: SANDBOX_TEST_NUMBERS.INVALID, // +15550001001 - Returns invalid_number error
210
+ text: 'Test message'
211
+ });
212
+ ```
213
+
214
+ ### Available Test Numbers
215
+
216
+ | Number | Behavior |
217
+ |--------|----------|
218
+ | `+15550001234` | Instant success |
219
+ | `+15550001010` | Success after 10s delay |
220
+ | `+15550001001` | Fails: invalid_number |
221
+ | `+15550001002` | Fails: carrier_rejected (2s delay) |
222
+ | `+15550001003` | Fails: rate_limit_exceeded |
223
+
224
+ ## Pricing Tiers
225
+
226
+ ```typescript
227
+ import { CREDITS_PER_SMS, SUPPORTED_COUNTRIES } from '@sendly/node';
228
+
229
+ // Credits per SMS by tier
230
+ console.log(CREDITS_PER_SMS.domestic); // 1 (US/Canada)
231
+ console.log(CREDITS_PER_SMS.tier1); // 8 (UK, Poland, India, etc.)
232
+ console.log(CREDITS_PER_SMS.tier2); // 12 (France, Japan, Australia, etc.)
233
+ console.log(CREDITS_PER_SMS.tier3); // 16 (Germany, Italy, Mexico, etc.)
234
+
235
+ // Supported countries by tier
236
+ console.log(SUPPORTED_COUNTRIES.domestic); // ['US', 'CA']
237
+ console.log(SUPPORTED_COUNTRIES.tier1); // ['GB', 'PL', 'IN', ...]
238
+ ```
239
+
240
+ ## Utilities
241
+
242
+ The SDK exports validation utilities for advanced use cases:
243
+
244
+ ```typescript
245
+ import {
246
+ validatePhoneNumber,
247
+ getCountryFromPhone,
248
+ isCountrySupported,
249
+ calculateSegments
250
+ } from '@sendly/node';
251
+
252
+ // Validate phone number format
253
+ validatePhoneNumber('+15551234567'); // OK
254
+ validatePhoneNumber('555-1234'); // Throws ValidationError
255
+
256
+ // Get country from phone number
257
+ getCountryFromPhone('+447700900123'); // 'GB'
258
+ getCountryFromPhone('+15551234567'); // 'US'
259
+
260
+ // Check if country is supported
261
+ isCountrySupported('GB'); // true
262
+ isCountrySupported('XX'); // false
263
+
264
+ // Calculate SMS segments
265
+ calculateSegments('Hello!'); // 1
266
+ calculateSegments('A'.repeat(200)); // 2
267
+ ```
268
+
269
+ ## TypeScript
270
+
271
+ The SDK is written in TypeScript and exports all types:
272
+
273
+ ```typescript
274
+ import type {
275
+ SendlyConfig,
276
+ SendMessageRequest,
277
+ Message,
278
+ MessageStatus,
279
+ ListMessagesOptions,
280
+ MessageListResponse,
281
+ RateLimitInfo,
282
+ PricingTier
283
+ } from '@sendly/node';
284
+ ```
285
+
286
+ ## API Reference
287
+
288
+ ### `Sendly`
289
+
290
+ #### Constructor
291
+
292
+ ```typescript
293
+ new Sendly(apiKey: string)
294
+ new Sendly(config: SendlyConfig)
295
+ ```
296
+
297
+ #### Properties
298
+
299
+ - `messages` - Messages resource
300
+
301
+ #### Methods
302
+
303
+ - `isTestMode()` - Returns `true` if using a test API key
304
+ - `getRateLimitInfo()` - Returns current rate limit info
305
+ - `getBaseUrl()` - Returns configured base URL
306
+
307
+ ### `sendly.messages`
308
+
309
+ #### `send(request: SendMessageRequest): Promise<Message>`
310
+
311
+ Send an SMS message.
312
+
313
+ #### `list(options?: ListMessagesOptions): Promise<MessageListResponse>`
314
+
315
+ List sent messages.
316
+
317
+ #### `get(id: string): Promise<Message>`
318
+
319
+ Get a specific message by ID.
320
+
321
+ ## Support
322
+
323
+ - 📚 [Documentation](https://sendly.live/docs)
324
+ - 💬 [Discord](https://discord.gg/sendly)
325
+ - 📧 [support@sendly.live](mailto:support@sendly.live)
326
+
327
+ ## License
328
+
329
+ MIT