@sendmailos/sdk 1.2.0 → 1.2.2

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
@@ -33,11 +33,12 @@ await client.emails.send({
33
33
 
34
34
  - **Type-safe**: Full TypeScript support with exported types
35
35
  - **Lightweight**: Zero dependencies for core SDK
36
+ - **Email Automation**: Build workflows with triggers, delays, conditions, and actions
36
37
  - **Industry Templates**: 50+ pre-built templates for different industries
37
38
  - **Agency Workspaces**: Manage multiple clients from one account
38
39
  - **Pixel Tracking**: Track website visitors and link to email campaigns
40
+ - **Webhooks**: Real-time event notifications with signature verification
39
41
  - **React Components**: Pre-built components and hooks
40
- - **Webhook Verification**: Secure signature verification utilities
41
42
  - **Error Handling**: Custom error classes for different scenarios
42
43
 
43
44
  ## API Reference
@@ -45,7 +46,7 @@ await client.emails.send({
45
46
  ### Emails
46
47
 
47
48
  ```typescript
48
- // Send transactional email
49
+ // Send transactional email (Single Brand)
49
50
  await client.emails.send({
50
51
  to: 'user@example.com',
51
52
  subject: 'Hello!',
@@ -54,6 +55,16 @@ await client.emails.send({
54
55
  fromEmail: 'hello@acme.com',
55
56
  });
56
57
 
58
+ // Send email (Multi-Brand / SaaS Platform)
59
+ // Workspace auto-detected from fromEmail domain - no extra params needed!
60
+ await platform.emails.send({
61
+ to: 'customer@example.com',
62
+ subject: 'Your order is ready!',
63
+ html: '<h1>Order Ready!</h1>',
64
+ fromName: 'Pizza Palace',
65
+ fromEmail: 'orders@pizzapalace.com', // ← Workspace auto-detected
66
+ });
67
+
57
68
  // Send with template
58
69
  await client.emails.sendTemplate({
59
70
  to: 'user@example.com',
@@ -65,24 +76,38 @@ await client.emails.sendTemplate({
65
76
  ### Subscribers
66
77
 
67
78
  ```typescript
68
- // Create subscriber
79
+ // Create subscriber (Single Brand)
69
80
  const { subscriber } = await client.subscribers.create({
70
81
  email: 'user@example.com',
71
82
  firstName: 'John',
72
83
  tags: ['newsletter', 'premium']
73
84
  });
74
85
 
86
+ // Create subscriber (Multi-Brand / SaaS Platform)
87
+ const { subscriber } = await platform.subscribers.create({
88
+ email: 'customer@example.com',
89
+ firstName: 'Jane',
90
+ domain: 'pizzapalace.com', // Required for multi-brand
91
+ tags: ['loyalty-member']
92
+ });
93
+
75
94
  // List subscribers
76
95
  const { subscribers, total } = await client.subscribers.list({
77
96
  limit: 50,
78
97
  offset: 0
79
98
  });
99
+
100
+ // List subscribers for a specific client (Multi-Brand)
101
+ const { subscribers } = await platform.subscribers.list({
102
+ domain: 'pizzapalace.com',
103
+ limit: 50
104
+ });
80
105
  ```
81
106
 
82
107
  ### Campaigns
83
108
 
84
109
  ```typescript
85
- // Send campaign
110
+ // Send campaign (Single Brand)
86
111
  await client.campaigns.send({
87
112
  name: 'Weekly Newsletter',
88
113
  subject: 'What\'s new this week',
@@ -91,17 +116,39 @@ await client.campaigns.send({
91
116
  html: '<h1>Hello {{first_name}}!</h1>',
92
117
  tags: ['newsletter'] // Filter by subscriber tags
93
118
  });
119
+
120
+ // Send campaign (Multi-Brand / SaaS Platform)
121
+ // Workspace auto-detected from fromEmail domain
122
+ await platform.campaigns.send({
123
+ name: 'Pizza Promo',
124
+ subject: 'New menu items!',
125
+ fromName: 'Pizza Palace',
126
+ fromEmail: 'promo@pizzapalace.com', // ← Workspace auto-detected
127
+ html: '<h1>Check out our new items!</h1>',
128
+ sourceDomains: ['pizzapalace.com'] // Only send to subscribers from this domain
129
+ });
94
130
  ```
95
131
 
96
132
  ### Domains
97
133
 
98
134
  ```typescript
99
- // Add sending domain
135
+ // Add sending domain (Single Brand)
100
136
  const { domain } = await client.domains.create({
101
137
  domain: 'yourcompany.com'
102
138
  });
103
139
 
104
140
  console.log('DNS Records to add:', domain.dnsRecords);
141
+
142
+ // Add client domain (Multi-Brand / SaaS Platform)
143
+ // Show these DNS records to your client in your UI
144
+ const { dns_records, domain_id } = await platform.domains.create({
145
+ domain: 'pizzapalace.com'
146
+ });
147
+
148
+ // After client verifies DNS:
149
+ // ✓ Domain status becomes "verified"
150
+ // ✓ Workspace is AUTO-CREATED for this domain
151
+ // ✓ You can now send emails from @pizzapalace.com
105
152
  ```
106
153
 
107
154
  ## Organization & Industries
@@ -131,27 +178,97 @@ console.log(INDUSTRIES);
131
178
 
132
179
  Hotels, Restaurants, Gyms, Travel Agencies, Real Estate, Schools, E-commerce, Dentists, Car Dealerships, Events, Beauty Salons, Law Firms, Non-Profits, SaaS, Recruitment, Insurance, Online Courses, Municipalities, Personal Trainers, Influencers, Doctors/Clinics, Nightclubs, Coworking, Wedding Planners, Art Galleries, Car Rentals, Podcasters, Consultants, Bakeries, Veterinarians, Airbnb Hosts, Accountants, Developers, Musicians, Spas, Bookstores, Cleaning Services, Churches, Graphic Designers, Coffee Shops, Florists, Political Campaigns, Libraries, Taxis/Limos, Home Inspectors, Photographers, Universities, Fashion, Nutritionists, Startups
133
180
 
134
- ## Agency Workspaces
181
+ ## Account Types
182
+
183
+ ### Single Brand (Business)
184
+
185
+ For companies sending emails from their own domain. Simple setup, no workspaces needed.
186
+
187
+ ```typescript
188
+ const client = new SendMailOS('sk_live_your_api_key');
189
+
190
+ await client.emails.send({
191
+ to: 'customer@example.com',
192
+ fromEmail: 'hello@yourcompany.com',
193
+ subject: 'Welcome!',
194
+ html: '<h1>Hello!</h1>'
195
+ });
196
+ ```
197
+
198
+ ### Multi-Brand / SaaS Platform
135
199
 
136
- Agencies can manage multiple clients from one account, each with isolated data.
200
+ For agencies or SaaS platforms managing multiple clients. Each client gets their own workspace with isolated data.
201
+
202
+ ```typescript
203
+ // Your platform's master API key
204
+ const platform = new SendMailOS('sk_live_platform_key');
205
+
206
+ // 1. Client signs up → Register their domain
207
+ const { dns_records } = await platform.domains.create({
208
+ domain: 'pizzapalace.com'
209
+ });
210
+ // Show dns_records to client in your UI
211
+
212
+ // 2. Domain verified → Workspace auto-created!
213
+ // (No manual workspace creation needed)
214
+
215
+ // 3. Send emails → Workspace auto-detected from fromEmail
216
+ await platform.emails.send({
217
+ to: 'customer@example.com',
218
+ fromEmail: 'orders@pizzapalace.com', // ← Workspace detected automatically!
219
+ fromName: 'Pizza Palace',
220
+ subject: 'Your order is ready!',
221
+ html: '<h1>Order Ready!</h1>'
222
+ });
223
+
224
+ // 4. Add subscribers → Use domain param
225
+ await platform.subscribers.create({
226
+ email: 'customer@example.com',
227
+ domain: 'pizzapalace.com' // Required for multi-brand
228
+ });
229
+
230
+ // 5. List subscribers for a specific client
231
+ const { subscribers } = await platform.subscribers.list({
232
+ domain: 'pizzapalace.com'
233
+ });
234
+
235
+ // 6. Send campaign → Workspace auto-detected
236
+ await platform.campaigns.send({
237
+ subject: 'New Menu Items!',
238
+ fromName: 'Pizza Palace',
239
+ fromEmail: 'promo@pizzapalace.com', // ← Auto-detected
240
+ html: '<h1>Check out our new menu!</h1>'
241
+ });
242
+ ```
243
+
244
+ ### How Workspace Detection Works
245
+
246
+ | Action | How workspace is identified |
247
+ |--------|----------------------------|
248
+ | Register domain | Creates domain record (pending) |
249
+ | Domain verified | **Workspace auto-created** |
250
+ | Send email | Auto-detect from `fromEmail` domain |
251
+ | Send campaign | Auto-detect from `fromEmail` domain |
252
+ | Add subscriber | From `domain` parameter |
253
+ | List subscribers | From `domain` parameter |
254
+
255
+ **One verified domain = One workspace.** Simple.
256
+
257
+ ## Agency Workspaces (Advanced)
258
+
259
+ For more control, you can manually manage workspaces:
137
260
 
138
261
  ```typescript
139
262
  // Convert to agency account first
140
263
  await client.organization.convertToAgency();
141
264
 
142
- // Create client workspaces
265
+ // Create client workspaces manually
143
266
  const pizzaPlace = await client.workspaces.create({
144
267
  name: 'Pizza Palace',
145
268
  industry: 'restaurants',
146
269
  import_templates: true // Auto-import restaurant templates
147
270
  });
148
271
 
149
- const gym = await client.workspaces.create({
150
- name: 'FitLife Gym',
151
- industry: 'gyms',
152
- import_templates: true
153
- });
154
-
155
272
  // List all clients
156
273
  const { workspaces } = await client.workspaces.list();
157
274
  for (const ws of workspaces) {
@@ -167,6 +284,231 @@ console.log(details.stats);
167
284
  await client.workspaces.inviteClient(pizzaPlace.id, 'owner@pizzapalace.com');
168
285
  ```
169
286
 
287
+ ## Workflows
288
+
289
+ Automate email sequences with workflows. Create them via API, build the steps in your UI, then trigger them programmatically.
290
+
291
+ ### Workflow Lifecycle
292
+
293
+ ```
294
+ 1. Create workflow (draft)
295
+ 2. Add nodes & edges (build the flow)
296
+ 3. Activate workflow (start accepting triggers)
297
+ 4. Trigger for subscribers (via API or events)
298
+ ```
299
+
300
+ ### Create & Manage Workflows
301
+
302
+ ```typescript
303
+ // Create a workflow for a client (Multi-Brand)
304
+ const { data } = await platform.workflows.create({
305
+ name: 'Welcome Sequence',
306
+ domain: 'pizzapalace.com', // Auto-detect workspace
307
+ trigger: { type: 'api' } // Triggered via API
308
+ });
309
+
310
+ const workflowId = data.workflow.id;
311
+
312
+ // List workflows
313
+ const { data: list } = await platform.workflows.list({ domain: 'pizzapalace.com' });
314
+
315
+ // Get workflow with nodes/edges
316
+ const { data: workflow } = await platform.workflows.get(workflowId);
317
+
318
+ // Delete workflow
319
+ await platform.workflows.delete(workflowId);
320
+ ```
321
+
322
+ ### Build Workflow Steps
323
+
324
+ Update a workflow with nodes (steps) and edges (connections):
325
+
326
+ ```typescript
327
+ await platform.workflows.update(workflowId, {
328
+ nodes: [
329
+ {
330
+ id: 'trigger-1',
331
+ type: 'trigger',
332
+ data: { triggerType: 'api' }
333
+ },
334
+ {
335
+ id: 'email-1',
336
+ type: 'email',
337
+ data: {
338
+ subject: 'Welcome to {{restaurantName}}!',
339
+ templateId: 'tmpl_welcome'
340
+ }
341
+ },
342
+ {
343
+ id: 'delay-1',
344
+ type: 'delay',
345
+ data: { duration: 3, unit: 'days' }
346
+ },
347
+ {
348
+ id: 'email-2',
349
+ type: 'email',
350
+ data: {
351
+ subject: 'Your first order discount',
352
+ templateId: 'tmpl_promo'
353
+ }
354
+ }
355
+ ],
356
+ edges: [
357
+ { id: 'e1', source: 'trigger-1', target: 'email-1' },
358
+ { id: 'e2', source: 'email-1', target: 'delay-1' },
359
+ { id: 'e3', source: 'delay-1', target: 'email-2' }
360
+ ]
361
+ });
362
+ ```
363
+
364
+ ### Node Types
365
+
366
+ | Type | Description | Data Fields |
367
+ |------|-------------|-------------|
368
+ | `trigger` | Entry point | `triggerType` |
369
+ | `email` | Send email | `subject`, `templateId`, `fromName`, `fromEmail` |
370
+ | `delay` | Wait period | `duration`, `unit` (minutes/hours/days) |
371
+ | `condition` | Branch logic | `field`, `operator`, `value` |
372
+ | `tag` | Add/remove tags | `action` (add/remove), `tags` |
373
+ | `http` | Call webhook | `url`, `method`, `headers`, `body` |
374
+ | `wait_for_event` | Wait for event | `eventName`, `timeout` |
375
+ | `unsubscribe` | Unsubscribe user | - |
376
+ | `exit` | End workflow | - |
377
+
378
+ ### Activate & Pause
379
+
380
+ ```typescript
381
+ // Activate workflow (start accepting triggers)
382
+ await platform.workflows.activate(workflowId);
383
+
384
+ // Pause workflow (stop new triggers, existing runs continue)
385
+ await platform.workflows.pause(workflowId);
386
+ ```
387
+
388
+ ### Trigger Workflows
389
+
390
+ ```typescript
391
+ // When a customer signs up at the restaurant
392
+ await platform.workflows.trigger(workflowId, {
393
+ email: 'customer@example.com',
394
+ data: {
395
+ firstName: 'John',
396
+ restaurantName: 'Pizza Palace',
397
+ signupSource: 'website'
398
+ }
399
+ });
400
+ ```
401
+
402
+ ### Wait for Events
403
+
404
+ Workflows can pause and wait for specific events:
405
+
406
+ ```typescript
407
+ // Workflow has a "wait_for_event: purchase_completed" node
408
+ // When customer makes a purchase, send the event:
409
+ await platform.workflows.sendEvent({
410
+ event: 'purchase_completed',
411
+ email: 'customer@example.com',
412
+ data: { orderTotal: 45.99 }
413
+ });
414
+ // The workflow resumes from where it was waiting
415
+ ```
416
+
417
+ ### Example: Restaurant Welcome Flow
418
+
419
+ ```typescript
420
+ // 1. Create workflow
421
+ const { data } = await platform.workflows.create({
422
+ name: 'New Customer Welcome',
423
+ domain: 'pizzapalace.com'
424
+ });
425
+
426
+ // 2. Build the flow
427
+ await platform.workflows.update(data.workflow.id, {
428
+ nodes: [
429
+ { id: '1', type: 'trigger', data: { triggerType: 'api' } },
430
+ { id: '2', type: 'email', data: { subject: 'Welcome!', templateId: 'tmpl_welcome' } },
431
+ { id: '3', type: 'delay', data: { duration: 2, unit: 'days' } },
432
+ { id: '4', type: 'condition', data: { field: 'has_ordered', operator: 'eq', value: true } },
433
+ { id: '5', type: 'email', data: { subject: 'Thanks for ordering!', templateId: 'tmpl_thanks' } },
434
+ { id: '6', type: 'email', data: { subject: '10% off your first order', templateId: 'tmpl_promo' } }
435
+ ],
436
+ edges: [
437
+ { id: 'e1', source: '1', target: '2' },
438
+ { id: 'e2', source: '2', target: '3' },
439
+ { id: 'e3', source: '3', target: '4' },
440
+ { id: 'e4', source: '4', target: '5', sourceHandle: 'yes' },
441
+ { id: 'e5', source: '4', target: '6', sourceHandle: 'no' }
442
+ ]
443
+ });
444
+
445
+ // 3. Activate
446
+ await platform.workflows.activate(data.workflow.id);
447
+
448
+ // 4. Trigger when new customer signs up
449
+ await platform.workflows.trigger(data.workflow.id, {
450
+ email: 'newcustomer@gmail.com',
451
+ data: { firstName: 'Jane', restaurantName: 'Pizza Palace' }
452
+ });
453
+ ```
454
+
455
+ ## Webhooks
456
+
457
+ Receive real-time notifications when events occur (emails sent, opened, clicked, bounced, etc.).
458
+
459
+ ### Create & Manage Webhooks
460
+
461
+ ```typescript
462
+ // Create a webhook endpoint
463
+ const { webhook } = await client.webhooks.create({
464
+ url: 'https://yourserver.com/webhooks',
465
+ events: ['email.sent', 'email.delivered', 'email.opened', 'email.clicked', 'email.bounced'],
466
+ });
467
+
468
+ console.log('Webhook secret:', webhook.secret); // Use this to verify signatures
469
+
470
+ // List all webhooks
471
+ const { webhooks } = await client.webhooks.list();
472
+
473
+ // Get webhook with delivery history
474
+ const { webhook, recentDeliveries, stats } = await client.webhooks.get('webhook-id');
475
+
476
+ // Update webhook
477
+ await client.webhooks.update('webhook-id', {
478
+ events: ['email.sent', 'email.bounced', 'email.complained']
479
+ });
480
+
481
+ // Test webhook endpoint
482
+ const result = await client.webhooks.test('webhook-id');
483
+ if (result.test.sent) {
484
+ console.log(`Test delivered in ${result.test.responseTimeMs}ms`);
485
+ }
486
+
487
+ // Disable/Enable webhook
488
+ await client.webhooks.disable('webhook-id');
489
+ await client.webhooks.enable('webhook-id');
490
+
491
+ // Delete webhook
492
+ await client.webhooks.delete('webhook-id');
493
+ ```
494
+
495
+ ### Event Types
496
+
497
+ | Event | Description |
498
+ |-------|-------------|
499
+ | `email.sent` | Email was sent to the recipient |
500
+ | `email.delivered` | Email was delivered to recipient's server |
501
+ | `email.opened` | Recipient opened the email |
502
+ | `email.clicked` | Recipient clicked a link in the email |
503
+ | `email.bounced` | Email bounced (hard or soft) |
504
+ | `email.complained` | Recipient marked email as spam |
505
+ | `subscriber.created` | New subscriber was added |
506
+ | `subscriber.updated` | Subscriber was updated |
507
+ | `subscriber.unsubscribed` | Subscriber unsubscribed |
508
+ | `campaign.sent` | Campaign finished sending |
509
+ | `workflow.started` | Workflow execution started |
510
+ | `workflow.completed` | Workflow execution completed |
511
+
170
512
  ## Pixel Tracking
171
513
 
172
514
  Track website visitors and connect their behavior to email campaigns.