@unsent/sdk 1.0.2 → 1.0.4

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 CHANGED
@@ -1,5 +1,7 @@
1
1
  # @unsent/sdk SDK
2
2
 
3
+ The official TypeScript SDK for the Unsent API. Send transactional emails, manage contacts, campaigns, and more with ease.
4
+
3
5
  ## Prerequisites
4
6
 
5
7
  - [unsent API key](https://app.unsent.dev/dev-settings/api-keys)
@@ -46,22 +48,22 @@ const client = new unsent("un_xxxx");
46
48
  You can also set your API key using environment variables:
47
49
 
48
50
  ```typescript
49
- // Set UNSENT_API_KEY or UNSENT_API_KEY in your environment
51
+ // Set UNSENT_API_KEY in your environment
50
52
  // Then initialize without passing the key
51
53
  const client = new unsent();
52
54
  ```
53
55
 
54
- ### Sending Emails
56
+ ### Emails
55
57
 
56
- #### Simple Email
58
+ #### Send Email
57
59
 
58
60
  ```typescript
59
61
  const { data, error } = await client.emails.send({
60
62
  to: "hello@acme.com",
61
63
  from: "hello@company.com",
62
64
  subject: "unsent email",
63
- html: "<p>unsent is the best email service provider to send emails</p>",
64
- text: "unsent is the best email service provider to send emails",
65
+ html: "<p>unsent is the best email service provider</p>",
66
+ text: "unsent is the best email service provider",
65
67
  });
66
68
 
67
69
  if (error) {
@@ -71,385 +73,384 @@ if (error) {
71
73
  }
72
74
  ```
73
75
 
74
- #### Email with Attachments
76
+ #### Get Email
75
77
 
76
78
  ```typescript
77
- const { data, error } = await client.emails.send({
78
- to: "hello@acme.com",
79
- from: "hello@company.com",
80
- subject: "Email with attachment",
81
- html: "<p>Please find the attachment below</p>",
82
- attachments: [
83
- {
84
- filename: "document.pdf",
85
- content: "base64-encoded-content-here",
86
- },
87
- ],
88
- });
79
+ const { data, error } = await client.emails.get("email_id");
89
80
  ```
90
81
 
91
- #### Email with React Component
82
+ #### Send Batch Emails
92
83
 
93
84
  ```typescript
94
- import { MyEmailTemplate } from "./templates/MyEmailTemplate"
85
+ const emails = [
86
+ { to: "user1@example.com", from: "hello@company.com", subject: "Hi", html: "<p>Hi</p>" },
87
+ { to: "user2@example.com", from: "hello@company.com", subject: "Hello", html: "<p>Hello</p>" }
88
+ ];
95
89
 
96
- const { data, error } = await client.emails.send({
97
- to: "hello@acme.com",
98
- from: "hello@company.com",
99
- subject: "Email with React template",
100
- react: <MyEmailTemplate name="John" />,
101
- })
90
+ const { data, error } = await client.emails.batch(emails);
102
91
  ```
103
92
 
104
- #### Scheduled Email
93
+ #### Schedule Email
105
94
 
106
95
  ```typescript
107
- const scheduledTime = new Date();
108
- scheduledTime.setHours(scheduledTime.getHours() + 1); // Schedule for 1 hour from now
109
-
110
96
  const { data, error } = await client.emails.send({
111
97
  to: "hello@acme.com",
112
98
  from: "hello@company.com",
113
99
  subject: "Scheduled email",
114
- html: "<p>This email was scheduled</p>",
115
- scheduledAt: scheduledTime.toISOString(),
100
+ html: "<p>This is scheduled</p>",
101
+ scheduledAt: "2024-12-25T10:00:00Z",
116
102
  });
117
103
  ```
118
104
 
119
- #### Batch Emails
105
+ #### Cancel Scheduled Email
120
106
 
121
107
  ```typescript
122
- const emails = [
123
- {
124
- to: "user1@example.com",
125
- from: "hello@company.com",
126
- subject: "Hello User 1",
127
- html: "<p>Welcome User 1</p>",
128
- },
129
- {
130
- to: "user2@example.com",
131
- from: "hello@company.com",
132
- subject: "Hello User 2",
133
- html: "<p>Welcome User 2</p>",
134
- },
135
- ];
108
+ const { data, error } = await client.emails.cancel("email_id");
109
+ ```
136
110
 
137
- const { data, error } = await client.emails.batch(emails);
111
+ ### Contacts
138
112
 
139
- if (error) {
140
- console.error("Error:", error);
141
- } else {
142
- console.log(`Sent ${data.length} emails`);
143
- }
113
+ #### Create Contact
114
+
115
+ ```typescript
116
+ const { data, error } = await client.contacts.create("contact_book_id", {
117
+ email: "user@example.com",
118
+ firstName: "John",
119
+ lastName: "Doe",
120
+ metadata: { role: "Admin" }
121
+ });
144
122
  ```
145
123
 
146
- #### Idempotency Keys
124
+ #### List Contacts
125
+
126
+ ```typescript
127
+ const { data, error } = await client.contacts.list("contact_book_id", {
128
+ page: 1,
129
+ limit: 20,
130
+ emails: "user@example.com",
131
+ ids: "id1,id2"
132
+ });
133
+ ```
147
134
 
148
- Safely retry email sends with an idempotency key to prevent duplicate sends. This is especially useful for critical emails like signup confirmations or password resets.
135
+ #### Get Contact
149
136
 
150
137
  ```typescript
151
- // Safely retry sends with an idempotency key
152
- const { data, error } = await client.emails.send(
153
- {
154
- to: "hello@acme.com",
155
- from: "hello@company.com",
156
- subject: "unsent email",
157
- html: "<p>unsent is the best open source product to send emails</p>",
158
- },
159
- { idempotencyKey: "signup-123" },
160
- );
138
+ const { data, error } = await client.contacts.get("contact_book_id", "contact_id");
139
+ ```
161
140
 
162
- if (error) {
163
- console.error("Error:", error);
164
- } else {
165
- console.log("Email sent! ID:", data.id);
166
- }
141
+ #### Update Contact
142
+
143
+ ```typescript
144
+ const { data, error } = await client.contacts.update("contact_book_id", "contact_id", {
145
+ firstName: "Jane"
146
+ });
167
147
  ```
168
148
 
169
- Idempotency keys also work for batch sends:
170
-
171
- ```typescript
172
- // Works for bulk sends too
173
- const { data, error } = await client.emails.batch(
174
- [
175
- {
176
- to: "a@example.com",
177
- from: "hello@company.com",
178
- subject: "Welcome",
179
- html: "<p>Hello A</p>",
180
- },
181
- {
182
- to: "b@example.com",
183
- from: "hello@company.com",
184
- subject: "Welcome",
185
- html: "<p>Hello B</p>",
186
- },
187
- ],
188
- { idempotencyKey: "bulk-welcome-1" },
189
- );
149
+ #### Upsert Contact
190
150
 
191
- if (error) {
192
- console.error("Error:", error);
193
- } else {
194
- console.log(`Sent ${data.length} emails`);
195
- }
151
+ ```typescript
152
+ const { data, error } = await client.contacts.upsert("contact_book_id", "contact_id", {
153
+ email: "user@example.com",
154
+ firstName: "John"
155
+ });
196
156
  ```
197
157
 
198
- > **Note:** Reusing the same idempotency key with a different payload will return HTTP 409 (Conflict). This ensures that retries are safe and prevents accidental duplicate sends with modified content.
158
+ #### Delete Contact
159
+
160
+ ```typescript
161
+ const { data, error } = await client.contacts.delete("contact_book_id", "contact_id");
162
+ ```
199
163
 
200
- ### Managing Emails
164
+ ### Contact Books
201
165
 
202
- #### Get Email Details
166
+ #### List Contact Books
203
167
 
204
168
  ```typescript
205
- const { data, error } = await client.emails.get("email_id");
169
+ const { data, error } = await client.contactBooks.list();
170
+ ```
206
171
 
207
- if (error) {
208
- console.error("Error:", error);
209
- } else {
210
- console.log("Email status:", data.status);
211
- }
172
+ #### Create Contact Book
173
+
174
+ ```typescript
175
+ const { data, error } = await client.contactBooks.create({
176
+ name: "Newsletter Subscribers",
177
+ emoji: "📧"
178
+ });
179
+ ```
180
+
181
+ #### Get Contact Book
182
+
183
+ ```typescript
184
+ const { data, error } = await client.contactBooks.get("book_id");
212
185
  ```
213
186
 
214
- #### Update Email
187
+ #### Update Contact Book
215
188
 
216
189
  ```typescript
217
- const { data, error } = await client.emails.update("email_id", {
218
- subject: "Updated subject",
219
- html: "<p>Updated content</p>",
190
+ const { data, error } = await client.contactBooks.update("book_id", {
191
+ name: "New Name"
220
192
  });
221
193
  ```
222
194
 
223
- #### Cancel Scheduled Email
195
+ #### Delete Contact Book
224
196
 
225
197
  ```typescript
226
- const { data, error } = await client.emails.cancel("email_id");
198
+ const { data, error } = await client.contactBooks.delete("book_id");
199
+ ```
227
200
 
228
- if (error) {
229
- console.error("Error:", error);
230
- } else {
231
- console.log("Email cancelled successfully");
232
- }
201
+ ### Campaigns
202
+
203
+ #### Create Campaign
204
+
205
+ ```typescript
206
+ const { data, error } = await client.campaigns.create({
207
+ name: "Monthly Newsletter",
208
+ from: "news@company.com",
209
+ subject: "January Updates",
210
+ contactBookId: "book_id",
211
+ html: "<h1>News</h1>",
212
+ sendNow: false // set to true to send immediately
213
+ });
233
214
  ```
234
215
 
235
- ### Managing Contacts
216
+ #### Get Campaign
236
217
 
237
- #### Create Contact
218
+ ```typescript
219
+ const { data, error } = await client.campaigns.get("campaign_id");
220
+ ```
221
+
222
+ #### Schedule Campaign
238
223
 
239
224
  ```typescript
240
- const { data, error } = await client.contacts.create("contact_book_id", {
241
- email: "user@example.com",
242
- firstName: "John",
243
- lastName: "Doe",
244
- metadata: {
245
- company: "Acme Inc",
246
- role: "Developer",
247
- },
225
+ const { data, error } = await client.campaigns.schedule("campaign_id", {
226
+ scheduledAt: "2025-01-01T09:00:00Z",
227
+ batchSize: 500
248
228
  });
249
229
  ```
250
230
 
251
- #### Get Contact
231
+ #### Pause/Resume Campaign
252
232
 
253
233
  ```typescript
254
- const { data, error } = await client.contacts.get(
255
- "contact_book_id",
256
- "contact_id",
257
- );
234
+ await client.campaigns.pause("campaign_id");
235
+ await client.campaigns.resume("campaign_id");
258
236
  ```
259
237
 
260
- #### Update Contact
238
+ ### Templates
239
+
240
+ #### List Templates
261
241
 
262
242
  ```typescript
263
- const { data, error } = await client.contacts.update(
264
- "contact_book_id",
265
- "contact_id",
266
- {
267
- firstName: "Jane",
268
- metadata: {
269
- role: "Senior Developer",
270
- },
271
- },
272
- );
243
+ const { data, error } = await client.templates.list();
273
244
  ```
274
245
 
275
- #### Upsert Contact
246
+ #### Create Template
276
247
 
277
248
  ```typescript
278
- // Creates if doesn't exist, updates if exists
279
- const { data, error } = await client.contacts.upsert(
280
- "contact_book_id",
281
- "contact_id",
282
- {
283
- email: "user@example.com",
284
- firstName: "John",
285
- lastName: "Doe",
286
- },
287
- );
249
+ const { data, error } = await client.templates.create({
250
+ name: "Welcome Email",
251
+ subject: "Welcome {{name}}",
252
+ html: "<h1>Welcome!</h1>"
253
+ });
288
254
  ```
289
255
 
290
- #### Delete Contact
256
+ #### Get Template
291
257
 
292
258
  ```typescript
293
- const { data, error } = await client.contacts.delete(
294
- "contact_book_id",
295
- "contact_id",
296
- );
259
+ const { data, error } = await client.templates.get("template_id");
297
260
  ```
298
261
 
299
- ### Managing Campaigns
262
+ #### Update Template
300
263
 
301
- Create and manage email campaigns:
264
+ ```typescript
265
+ const { data, error } = await client.templates.update("template_id", {
266
+ subject: "New Subject"
267
+ });
268
+ ```
269
+
270
+ #### Delete Template
302
271
 
303
272
  ```typescript
304
- import { unsent } from "@unsent/sdk";
273
+ const { data, error } = await client.templates.delete("template_id");
274
+ ```
305
275
 
306
- const client = new unsent("un_xxxx");
276
+ ### Webhooks
307
277
 
308
- // Create a campaign
309
- const campaign = await client.campaigns.create({
310
- name: "Welcome Series",
311
- from: "hello@company.com",
312
- subject: "Welcome to our platform!",
313
- contactBookId: "cb_12345",
314
- html: "<h1>Welcome!</h1><p>Thanks for joining us.</p>",
315
- sendNow: false,
278
+ > **Note:** Webhooks are currently in development. The following methods are placeholders for future implementation.
279
+
280
+ #### List Webhooks
281
+
282
+ ```typescript
283
+ const { data, error } = await client.webhooks.list();
284
+ ```
285
+
286
+ #### Create Webhook
287
+
288
+ ```typescript
289
+ const { data, error } = await client.webhooks.create({
290
+ url: "https://api.myapp.com/webhooks/unsent",
291
+ events: ["email.sent", "email.opened"]
316
292
  });
293
+ ```
317
294
 
318
- if (campaign.error) {
319
- console.error("Error creating campaign:", campaign.error);
320
- } else {
321
- console.log("Campaign created:", campaign.data.id);
322
- }
295
+ #### Update Webhook
323
296
 
324
- // Schedule a campaign
325
- const scheduleResult = await client.campaigns.schedule(campaign.data.id, {
326
- scheduledAt: "2024-12-01T09:00:00Z",
327
- batchSize: 1000,
297
+ ```typescript
298
+ const { data, error } = await client.webhooks.update("webhook_id", {
299
+ events: ["email.bounced"]
328
300
  });
301
+ ```
329
302
 
330
- if (scheduleResult.error) {
331
- console.error("Error scheduling campaign:", scheduleResult.error);
332
- } else {
333
- console.log("Campaign scheduled successfully");
334
- }
303
+ #### Delete Webhook
335
304
 
336
- // Get campaign details
337
- const details = await client.campaigns.get(campaign.data.id);
305
+ ```typescript
306
+ const { data, error } = await client.webhooks.delete("webhook_id");
307
+ ```
338
308
 
339
- if (details.error) {
340
- console.error("Error getting details:", details.error);
341
- } else {
342
- console.log("Campaign status:", details.data.status);
343
- console.log("Total recipients:", details.data.total);
344
- }
309
+ ### Domains
345
310
 
346
- // Pause a campaign
347
- const pauseResult = await client.campaigns.pause(campaign.data.id);
311
+ #### List Domains
348
312
 
349
- if (pauseResult.error) {
350
- console.error("Error pausing campaign:", pauseResult.error);
351
- } else {
352
- console.log("Campaign paused successfully");
353
- }
313
+ ```typescript
314
+ const { data, error } = await client.domains.list();
315
+ ```
354
316
 
355
- // Resume a campaign
356
- const resumeResult = await client.campaigns.resume(campaign.data.id);
317
+ #### Create Domain
357
318
 
358
- if (resumeResult.error) {
359
- console.error("Error resuming campaign:", resumeResult.error);
360
- } else {
361
- console.log("Campaign resumed successfully");
362
- }
319
+ ```typescript
320
+ const { data, error } = await client.domains.create({
321
+ domain: "mail.example.com"
322
+ });
363
323
  ```
364
324
 
365
- ### Error Handling
325
+ #### Verify Domain
366
326
 
367
- The SDK returns a consistent response structure with `data` and `error`:
327
+ ```typescript
328
+ const { data, error } = await client.domains.verify("123"); // Uses domain ID (string)
329
+ ```
330
+
331
+ #### Get Domain
368
332
 
369
333
  ```typescript
370
- const { data, error } = await client.emails.send({
371
- to: "invalid-email",
372
- from: "hello@company.com",
373
- subject: "Test",
374
- html: "<p>Test</p>",
334
+ const { data, error } = await client.domains.get("123");
335
+ ```
336
+
337
+ #### Delete Domain
338
+
339
+ ```typescript
340
+ const { data, error } = await client.domains.delete("123");
341
+ ```
342
+
343
+ ### Analytics
344
+
345
+ #### Get General Analytics
346
+
347
+ ```typescript
348
+ const { data, error } = await client.analytics.get();
349
+ ```
350
+
351
+ #### Get Time Series
352
+
353
+ ```typescript
354
+ const { data, error } = await client.analytics.getTimeSeries({
355
+ days: 30,
356
+ domain: "example.com"
375
357
  });
358
+ ```
376
359
 
377
- if (error) {
378
- console.error(`Error ${error.code}: ${error.message}`);
379
- return;
380
- }
360
+ #### Get Reputation
381
361
 
382
- // Safe to use data here
383
- console.log("Email sent:", data.id);
362
+ ```typescript
363
+ const { data, error } = await client.analytics.getReputation({
364
+ domain: "example.com"
365
+ });
384
366
  ```
385
367
 
386
- ### TypeScript Support
368
+ ### Suppressions
387
369
 
388
- The SDK is fully typed with TypeScript:
370
+ #### List Suppressions
389
371
 
390
372
  ```typescript
391
- import { unsent } from "@unsent/sdk";
373
+ const { data, error } = await client.suppressions.list({
374
+ page: 1,
375
+ limit: 10,
376
+ search: "test",
377
+ reason: "COMPLAINT"
378
+ });
379
+ ```
392
380
 
393
- const client = new unsent("un_xxxx");
381
+ #### Add Suppression
394
382
 
395
- // Full type inference and autocomplete
396
- const result = await client.emails.send({
397
- to: "hello@acme.com",
398
- from: "hello@company.com",
399
- subject: "Typed email",
400
- html: "<p>Fully typed!</p>",
383
+ ```typescript
384
+ const { data, error } = await client.suppressions.add({
385
+ email: "bad@example.com",
386
+ reason: "COMPLAINT"
401
387
  });
388
+ ```
402
389
 
403
- // Type-safe access
404
- if (result.data) {
405
- const emailId: string = result.data.id;
406
- }
390
+ #### Delete Suppression
391
+
392
+ ```typescript
393
+ const { data, error } = await client.suppressions.delete("bad@example.com");
394
+ ```
395
+
396
+ ### API Keys
397
+
398
+ #### List API Keys
399
+
400
+ ```typescript
401
+ const { data, error } = await client.apiKeys.list();
402
+ ```
403
+
404
+ #### Create API Key
405
+
406
+ ```typescript
407
+ const { data, error } = await client.apiKeys.create({
408
+ name: "Prod Key",
409
+ permission: "FULL"
410
+ });
407
411
  ```
408
412
 
409
- ## API Reference
413
+ #### Delete API Key
414
+
415
+ ```typescript
416
+ const { data, error } = await client.apiKeys.delete("key_id");
417
+ ```
410
418
 
411
- ### Client Methods
419
+ ### Settings
412
420
 
413
- - `new unsent(key?, url?)` - Initialize the client
421
+ #### Get Settings
414
422
 
415
- ### Email Methods
423
+ ```typescript
424
+ const { data, error } = await client.settings.get();
425
+ ```
416
426
 
417
- - `client.emails.send(payload)` - Send an email (alias for `create`)
418
- - `client.emails.create(payload)` - Create and send an email
419
- - `client.emails.batch(emails)` - Send multiple emails in batch (max 100)
420
- - `client.emails.get(emailId)` - Get email details
421
- - `client.emails.update(emailId, payload)` - Update a scheduled email
422
- - `client.emails.cancel(emailId)` - Cancel a scheduled email
427
+ ## Error Handling
423
428
 
424
- ### Contact Methods
429
+ The SDK returns a consistent response structure with `data` and `error`:
425
430
 
426
- - `client.contacts.create(bookId, payload)` - Create a contact
427
- - `client.contacts.get(bookId, contactId)` - Get contact details
428
- - `client.contacts.update(bookId, contactId, payload)` - Update a contact
429
- - `client.contacts.upsert(bookId, contactId, payload)` - Upsert a contact
430
- - `client.contacts.delete(bookId, contactId)` - Delete a contact
431
+ ```typescript
432
+ const { data, error } = await client.emails.send({ ... });
431
433
 
432
- ### Campaign Methods
434
+ if (error) {
435
+ // error: { code: string; message: string; }
436
+ console.error(`Error ${error.code}: ${error.message}`);
437
+ return;
438
+ }
433
439
 
434
- - `client.campaigns.create(payload)` - Create a campaign
435
- - `client.campaigns.get(campaignId)` - Get campaign details
436
- - `client.campaigns.schedule(campaignId, payload)` - Schedule a campaign
437
- - `client.campaigns.pause(campaignId)` - Pause a campaign
438
- - `client.campaigns.resume(campaignId)` - Resume a campaign
440
+ console.log("Success:", data);
441
+ ```
439
442
 
440
- ## Features
443
+ ### TypeScript Support
441
444
 
442
- - 🔐 **Type-safe** - Full TypeScript support with type inference
443
- - ⚡ **Modern** - Built with ESM and async/await
444
- - 🎨 **React Email** - Send emails using React components
445
- - 📦 **Lightweight** - Minimal dependencies
446
- - 🔄 **Batch sending** - Send up to 100 emails in a single request
447
- - ⏰ **Scheduled emails** - Schedule emails for later delivery
445
+ The SDK is fully typed. You can use inferred types:
448
446
 
449
- ## Requirements
447
+ ```typescript
448
+ import { unsent } from "@unsent/sdk";
450
449
 
451
- - Node.js 16+
452
- - TypeScript 4.7+ (for TypeScript projects)
450
+ const client = new unsent();
451
+ // Types are automatically inferred
452
+ const { data } = await client.domains.list();
453
+ ```
453
454
 
454
455
  ## License
455
456