@voltade/envoy-sdk 1.3.0 → 1.3.1

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.
Files changed (2) hide show
  1. package/README.md +536 -64
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -11,39 +11,34 @@ npm install @voltade/envoy-sdk
11
11
  ## Quick Start
12
12
 
13
13
  ```typescript
14
- import { EnvoyClient } from '@voltade/envoy-sdk';
14
+ import { EnvoyClient } from "@voltade/envoy-sdk";
15
15
 
16
- // Initialize the client
17
16
  const client = new EnvoyClient({
18
- apiKey: 'your-api-key',
19
- accountId: 'your-account-id',
20
- baseUrl: 'https://envoy-crm.voltade.com', // optional, defaults to this
17
+ apiKey: "your-api-key",
18
+ accountId: "your-account-id",
19
+ baseUrl: "https://envoy-crm.voltade.com", // optional
21
20
  });
22
21
 
23
- // Create and send a message to a conversation
22
+ // Send a message
24
23
  const message = await client.conversations.createMessage(123, {
25
- content: 'Hello, how can I help you?',
26
- message_type: 'outgoing',
27
- private: false
24
+ content: "Hello, how can I help you?",
25
+ message_type: "outgoing",
26
+ private: false,
28
27
  });
29
28
 
30
- // Escalate a conversation to a human agent
29
+ // Escalate to human
31
30
  const result = await client.conversations.escalateToHuman(123);
32
- console.log(`Escalated: ${result.success}`);
33
31
  ```
34
32
 
35
33
  ## Features
36
34
 
37
35
  - **Type-safe**: Full TypeScript support with comprehensive type definitions
38
- - **Resource-based**: Organized API methods by resource (conversations, messages, etc.)
36
+ - **Resource-based**: Organized API methods by resource (conversations, contacts, companies, etc.)
39
37
  - **Error handling**: Structured error types for different API failures
40
- - **Easy to use**: Simple, intuitive API design
41
-
42
- ## API Reference
38
+ - **Zod schemas**: Runtime validation with exported schemas
39
+ - **Webhook support**: Parse and validate incoming webhook events
43
40
 
44
- ### EnvoyClient
45
-
46
- #### Configuration
41
+ ## Configuration
47
42
 
48
43
  ```typescript
49
44
  const client = new EnvoyClient({
@@ -54,24 +49,56 @@ const client = new EnvoyClient({
54
49
  });
55
50
  ```
56
51
 
52
+ ---
53
+
54
+ ## API Reference
55
+
57
56
  ### Conversations
58
57
 
59
- #### Create Message
58
+ #### `createMessage(conversationId, params)`
59
+
60
+ Create and send a message to a conversation. Supports text messages, WhatsApp templates, and file attachments.
60
61
 
61
62
  ```typescript
62
- const message = await client.conversations.createMessage(conversationId, {
63
- content: 'Your message',
64
- message_type: 'outgoing',
63
+ // Simple text message
64
+ const message = await client.conversations.createMessage(123, {
65
+ content: "Hello, how can I help you?",
66
+ message_type: "outgoing",
65
67
  private: false,
66
- content_type: 'text',
67
- content_attributes: {}
68
+ });
69
+
70
+ // WhatsApp template message
71
+ const templateMessage = await client.conversations.createMessage(123, {
72
+ content: "Template message",
73
+ template_params: {
74
+ name: "order_confirmation",
75
+ category: "MARKETING",
76
+ language: "en",
77
+ processed_params: {
78
+ body: { "1": "121212" },
79
+ header: {
80
+ media_url: "https://example.com/image.jpg",
81
+ media_type: "image",
82
+ },
83
+ },
84
+ },
85
+ });
86
+
87
+ // Message with file attachments
88
+ const file = new File([blob], "document.pdf", { type: "application/pdf" });
89
+ const messageWithAttachment = await client.conversations.createMessage(123, {
90
+ content: "Here is your document",
91
+ message_type: "outgoing",
92
+ file_attachments: [file],
68
93
  });
69
94
  ```
70
95
 
71
- #### Escalate to Human
96
+ #### `escalateToHuman(conversationId)`
97
+
98
+ Escalate a conversation to a human agent.
72
99
 
73
100
  ```typescript
74
- const result = await client.conversations.escalateToHuman(conversationId);
101
+ const result = await client.conversations.escalateToHuman(123);
75
102
 
76
103
  if (result.success) {
77
104
  console.log(`Escalated to ${result.escalation_type}`);
@@ -81,6 +108,336 @@ if (result.success) {
81
108
  }
82
109
  ```
83
110
 
111
+ #### `get(conversationId)`
112
+
113
+ Get a conversation by ID.
114
+
115
+ ```typescript
116
+ const conversation = await client.conversations.get(123);
117
+ console.log(conversation.status); // 'open' | 'resolved' | 'pending' | 'snoozed'
118
+ ```
119
+
120
+ #### `getMessages(conversationId)`
121
+
122
+ Get all messages for a conversation.
123
+
124
+ ```typescript
125
+ const response = await client.conversations.getMessages(123);
126
+ console.log(response.payload); // Array of messages
127
+ console.log(response.meta); // Metadata including labels, assignee
128
+ ```
129
+
130
+ ---
131
+
132
+ ### Contacts
133
+
134
+ #### `create(params)`
135
+
136
+ Create a new contact.
137
+
138
+ ```typescript
139
+ const contact = await client.contacts.create({
140
+ inbox_id: 1,
141
+ name: "John Doe",
142
+ email: "john@example.com",
143
+ phone_number: "+1234567890",
144
+ custom_attributes: { plan: "enterprise" },
145
+ });
146
+ ```
147
+
148
+ #### `update(contactId, params)`
149
+
150
+ Update an existing contact.
151
+
152
+ ```typescript
153
+ const contact = await client.contacts.update(123, {
154
+ name: "Jane Doe",
155
+ email: "jane@example.com",
156
+ custom_attributes: { plan: "pro" },
157
+ });
158
+ ```
159
+
160
+ #### `get(contactId)`
161
+
162
+ Get a contact by ID.
163
+
164
+ ```typescript
165
+ const contact = await client.contacts.get(123);
166
+ console.log(contact.name, contact.email);
167
+ ```
168
+
169
+ #### `delete(contactId)`
170
+
171
+ Delete a contact.
172
+
173
+ ```typescript
174
+ await client.contacts.delete(123);
175
+ ```
176
+
177
+ #### `list(params?)`
178
+
179
+ List all contacts with pagination.
180
+
181
+ ```typescript
182
+ const response = await client.contacts.list({ page: 1 });
183
+ console.log(response.payload); // Array of contacts
184
+ console.log(response.meta); // Pagination metadata
185
+ ```
186
+
187
+ #### `search(params)`
188
+
189
+ Search contacts by name, identifier, email, or phone number.
190
+
191
+ ```typescript
192
+ const response = await client.contacts.search({
193
+ q: "john@example.com",
194
+ page: 1,
195
+ });
196
+ console.log(response.payload);
197
+ ```
198
+
199
+ ---
200
+
201
+ ### Companies
202
+
203
+ #### `list(params?)`
204
+
205
+ List all companies with pagination.
206
+
207
+ ```typescript
208
+ const companies = await client.companies.list();
209
+
210
+ // With pagination
211
+ const companies = await client.companies.list({ page: 2, per_page: 50 });
212
+ ```
213
+
214
+ #### `create(params)`
215
+
216
+ Create a new company.
217
+
218
+ ```typescript
219
+ const company = await client.companies.create({
220
+ name: "Acme Corp",
221
+ });
222
+ ```
223
+
224
+ #### `get(companyId)`
225
+
226
+ Get a company by ID.
227
+
228
+ ```typescript
229
+ const company = await client.companies.get(456);
230
+ ```
231
+
232
+ #### `update(companyId, params)`
233
+
234
+ Update an existing company.
235
+
236
+ ```typescript
237
+ const company = await client.companies.update(456, {
238
+ name: "Acme Corp Updated",
239
+ });
240
+ ```
241
+
242
+ #### `search(query, params?)`
243
+
244
+ Search companies by name.
245
+
246
+ ```typescript
247
+ const response = await client.companies.search("Acme");
248
+
249
+ // With pagination
250
+ const response = await client.companies.search("Acme", {
251
+ page: 2,
252
+ per_page: 50,
253
+ });
254
+ console.log(response.payload); // Array of matching companies
255
+ console.log(response.meta); // { count, current_page }
256
+ ```
257
+
258
+ #### `delete(companyId)`
259
+
260
+ Delete a company.
261
+
262
+ ```typescript
263
+ await client.companies.delete(456);
264
+ ```
265
+
266
+ ---
267
+
268
+ ### Company Members
269
+
270
+ Manage contacts within a company via `client.companies.members`.
271
+
272
+ #### `list(companyId)`
273
+
274
+ List all members (contacts) of a company.
275
+
276
+ ```typescript
277
+ const members = await client.companies.members.list(456);
278
+ ```
279
+
280
+ #### `add(companyId, params)`
281
+
282
+ Add contacts to a company.
283
+
284
+ ```typescript
285
+ const members = await client.companies.members.add(456, {
286
+ contact_ids: [101, 102, 103],
287
+ });
288
+ ```
289
+
290
+ #### `remove(companyId, params)`
291
+
292
+ Remove contacts from a company.
293
+
294
+ ```typescript
295
+ await client.companies.members.remove(456, {
296
+ contact_ids: [101, 102],
297
+ });
298
+ ```
299
+
300
+ ---
301
+
302
+ ### Inboxes
303
+
304
+ #### `searchPortals(inboxId, params)`
305
+
306
+ Search the knowledge base portals for articles.
307
+
308
+ ```typescript
309
+ const articles = await client.inboxes.searchPortals(1, {
310
+ queries: ["shipping", "policy"],
311
+ });
312
+
313
+ articles.forEach((article) => {
314
+ console.log(article.title, article.content);
315
+ });
316
+ ```
317
+
318
+ #### `uploadWhatsappMedia(inboxId, params)`
319
+
320
+ Upload media file for WhatsApp messages.
321
+
322
+ ```typescript
323
+ // Upload an image
324
+ const file = new File([imageBlob], "photo.jpg", { type: "image/jpeg" });
325
+ const result = await client.inboxes.uploadWhatsappMedia(123, {
326
+ file: file,
327
+ type: "image/jpeg",
328
+ filename: "photo.jpg",
329
+ for_template: false,
330
+ });
331
+ console.log("Media ID:", result.media_id);
332
+
333
+ // Upload a document for template
334
+ const docFile = new File([pdfBlob], "invoice.pdf", { type: "application/pdf" });
335
+ const docResult = await client.inboxes.uploadWhatsappMedia(123, {
336
+ file: docFile,
337
+ type: "application/pdf",
338
+ filename: "invoice.pdf",
339
+ for_template: true,
340
+ });
341
+ ```
342
+
343
+ ---
344
+
345
+ ### Orders
346
+
347
+ #### `list(params?)`
348
+
349
+ List all orders with pagination and filtering.
350
+
351
+ ```typescript
352
+ // List with default pagination
353
+ const response = await client.orders.list();
354
+ console.log(response.data); // Array of orders
355
+ console.log(response.meta); // Pagination metadata
356
+
357
+ // With date filtering
358
+ const response = await client.orders.list({
359
+ page: 1,
360
+ per_page: 50,
361
+ since: "2024-01-01",
362
+ until: "2024-12-31",
363
+ sort: "-created_at",
364
+ });
365
+
366
+ // With advanced filtering
367
+ const response = await client.orders.list({
368
+ payload: [{ field: "financial_status", operator: "eq", value: "paid" }],
369
+ });
370
+ ```
371
+
372
+ #### `upsert(params)`
373
+
374
+ Create or update an order based on `source` and `source_id`. If an order with the same source and source_id exists, it will be updated.
375
+
376
+ ```typescript
377
+ const result = await client.orders.upsert({
378
+ name: "ORD-12345",
379
+ company_id: 101,
380
+ total_amount: 150,
381
+ currency_code: "USD",
382
+ financial_status: "paid",
383
+ fulfillment_status: "fulfilled",
384
+ source: "shopify",
385
+ source_id: "789456123",
386
+ order_url: "https://mystore.myshopify.com/admin/orders/789456123",
387
+ notes: "Customer requested gift wrapping",
388
+ metadata: {
389
+ line_items: [
390
+ {
391
+ part_number: "SKU-001",
392
+ quantity: 2,
393
+ description: "Widget",
394
+ line_total: 75,
395
+ },
396
+ ],
397
+ },
398
+ });
399
+ console.log(result.payload); // The created/updated order
400
+ ```
401
+
402
+ ---
403
+
404
+ ### Webhooks
405
+
406
+ Parse and validate incoming webhook events using the `webhookEvent` utility.
407
+
408
+ ```typescript
409
+ import { webhookEvent } from "@voltade/envoy-sdk";
410
+
411
+ // In your webhook handler
412
+ app.post("/webhook", (req, res) => {
413
+ // Throws ZodError if invalid
414
+ const event = webhookEvent.parse(req.body);
415
+
416
+ if (event.event === "message_created") {
417
+ console.log("New message:", event.content);
418
+ console.log("Conversation:", event.conversation.id);
419
+ console.log("Sender:", event.sender.name);
420
+ }
421
+
422
+ res.sendStatus(200);
423
+ });
424
+
425
+ // Or use safeParse for graceful handling
426
+ const event = webhookEvent.safeParse(req.body);
427
+ if (event) {
428
+ // Handle valid event
429
+ } else {
430
+ // Invalid payload
431
+ }
432
+ ```
433
+
434
+ **Supported webhook events:**
435
+
436
+ - `message_created` - New message in a conversation
437
+ - `message_updated` - Message was updated
438
+
439
+ ---
440
+
84
441
  ## Error Handling
85
442
 
86
443
  The SDK provides structured error types:
@@ -93,85 +450,200 @@ import {
93
450
  NotFoundError,
94
451
  RateLimitError,
95
452
  ServerError,
96
- NetworkError
97
- } from '@voltade/envoy-sdk';
453
+ NetworkError,
454
+ ValidationError,
455
+ } from "@voltade/envoy-sdk";
98
456
 
99
457
  try {
100
- await client.conversations.createMessage(123, { content: 'Hello' });
458
+ await client.conversations.createMessage(123, { content: "Hello" });
101
459
  } catch (error) {
102
460
  if (error instanceof AuthenticationError) {
103
- console.error('Invalid API key');
461
+ console.error("Invalid API key");
104
462
  } else if (error instanceof NotFoundError) {
105
- console.error('Conversation not found');
463
+ console.error("Conversation not found");
106
464
  } else if (error instanceof RateLimitError) {
107
- console.error('Rate limit exceeded');
465
+ console.error("Rate limit exceeded, retry after:", error.retryAfter);
466
+ } else if (error instanceof BadRequestError) {
467
+ console.error("Bad request:", error.response);
468
+ } else if (error instanceof ValidationError) {
469
+ console.error("Validation failed:", error.errors);
470
+ } else if (error instanceof ServerError) {
471
+ console.error("Server error:", error.statusCode);
472
+ } else if (error instanceof NetworkError) {
473
+ console.error("Network error:", error.originalError);
108
474
  }
109
475
  }
110
476
  ```
111
477
 
478
+ ---
479
+
112
480
  ## Types
113
481
 
114
- All TypeScript types are exported and available for use:
482
+ All TypeScript types are exported:
115
483
 
116
484
  ```typescript
117
485
  import type {
486
+ // Conversations
118
487
  Message,
119
488
  Conversation,
489
+ ConversationStatus,
120
490
  CreateMessageParams,
121
491
  EscalationResponse,
492
+ EscalationType,
122
493
  MessageType,
123
494
  ContentType,
124
- ConversationStatus
125
- } from '@voltade/envoy-sdk';
495
+ MessagesResponse,
496
+ MessagesResponseMeta,
497
+ TemplateParams,
498
+ Agent,
499
+ Assignee,
500
+ Team,
501
+ Priority,
502
+ Contact,
503
+ ContactInbox,
504
+ ConversationMeta,
505
+
506
+ // Contacts
507
+ ContactCreateParams,
508
+ ContactUpdateParams,
509
+ ListContactsParams,
510
+ ListContactsResponse,
511
+ SearchContactsParams,
512
+
513
+ // Companies
514
+ Company,
515
+ CreateCompanyParams,
516
+ CreateCompanyResponse,
517
+ GetCompanyResponse,
518
+ ListCompaniesParams,
519
+ ListCompaniesResponse,
520
+ UpdateCompanyParams,
521
+ UpdateCompanyResponse,
522
+ SearchCompaniesResponse,
523
+
524
+ // Company Members
525
+ AddCompanyMembersParams,
526
+ AddCompanyMembersResponse,
527
+ ListCompanyMembersResponse,
528
+ RemoveCompanyMembersParams,
529
+
530
+ // Inboxes
531
+ Article,
532
+ SearchParams,
533
+ SearchResponse,
534
+ UploadWhatsappMediaParams,
535
+ UploadWhatsappMediaResponse,
536
+
537
+ // Orders
538
+ Order,
539
+ OrdersMeta,
540
+ ListOrdersParams,
541
+ ListOrdersResponse,
542
+ UpsertOrderParams,
543
+ UpsertOrderRequest,
544
+ UpsertOrderResponse,
545
+ UpsertOrderResponsePayload,
546
+
547
+ // Webhooks
548
+ WebhookEvent,
549
+ MessageCreatedEvent,
550
+ MessageUpdatedEvent,
551
+ WebhookConversation,
552
+ WebhookMessage,
553
+ WebhookSender,
554
+
555
+ // Client
556
+ EnvoyClientConfig,
557
+ } from "@voltade/envoy-sdk";
126
558
  ```
127
559
 
560
+ ---
561
+
128
562
  ## Zod Schemas
129
563
 
130
564
  The SDK exposes Zod schemas for runtime validation. All types are derived from these schemas using `z.infer`:
131
565
 
132
566
  ```typescript
133
567
  import {
568
+ // Conversations
134
569
  MessageSchema,
570
+ ConversationSchema,
571
+ ConversationStatusSchema,
135
572
  CreateMessageParamsSchema,
136
573
  EscalationResponseSchema,
137
- ConversationSchema
138
- } from '@voltade/envoy-sdk';
574
+ EscalationTypeSchema,
575
+ MessageTypeSchema,
576
+ ContentTypeSchema,
577
+ MessagesResponseSchema,
578
+ MessagesResponseMetaSchema,
579
+ TemplateParamsSchema,
580
+ AgentSchema,
581
+ AssigneeSchema,
582
+ TeamSchema,
583
+ PrioritySchema,
584
+ ContactSchema,
585
+ ContactInboxSchema,
586
+ ConversationMetaSchema,
587
+
588
+ // Contacts
589
+ ContactCreateParamsSchema,
590
+ ContactUpdateParamsSchema,
591
+ ListContactsParamsSchema,
592
+ ListContactsResponseSchema,
593
+ SearchContactsParamsSchema,
594
+
595
+ // Companies
596
+ CompanySchema,
597
+ CreateCompanyParamsSchema,
598
+ CreateCompanyResponseSchema,
599
+ GetCompanyResponseSchema,
600
+ ListCompaniesParamsSchema,
601
+ ListCompaniesResponseSchema,
602
+ UpdateCompanyParamsSchema,
603
+ UpdateCompanyResponseSchema,
604
+ SearchCompaniesResponseSchema,
605
+
606
+ // Company Members
607
+ AddCompanyMembersParamsSchema,
608
+ AddCompanyMembersResponseSchema,
609
+ ListCompanyMembersResponseSchema,
610
+ RemoveCompanyMembersParamsSchema,
611
+
612
+ // Inboxes
613
+ ArticleSchema,
614
+ SearchParamsSchema,
615
+ SearchResponseSchema,
616
+ UploadWhatsappMediaParamsSchema,
617
+ UploadWhatsappMediaResponseSchema,
618
+
619
+ // Orders
620
+ OrderSchema,
621
+ OrdersMetaSchema,
622
+ ListOrdersParamsSchema,
623
+ ListOrdersResponseSchema,
624
+ UpsertOrderParamsSchema,
625
+ UpsertOrderRequestSchema,
626
+ UpsertOrderResponseSchema,
627
+ UpsertOrderResponsePayloadSchema,
628
+
629
+ // Webhooks
630
+ WebhookEventSchema,
631
+ MessageCreatedEventSchema,
632
+ MessageUpdatedEventSchema,
633
+ WebhookConversationSchema,
634
+ WebhookMessageSchema,
635
+ WebhookSenderSchema,
636
+ } from "@voltade/envoy-sdk";
139
637
 
140
638
  // Validate data at runtime
141
- const messageData = {
142
- id: 123,
143
- content: 'Hello',
144
- message_type: 'outgoing',
145
- // ... other fields
146
- };
147
-
148
639
  const validatedMessage = MessageSchema.parse(messageData);
149
640
 
150
641
  // Validate user input
151
- const userInput = {
152
- content: 'Hello, world!',
153
- message_type: 'outgoing',
154
- private: false
155
- };
156
-
157
642
  const validatedParams = CreateMessageParamsSchema.parse(userInput);
158
643
  await client.conversations.createMessage(123, validatedParams);
159
644
  ```
160
645
 
161
- ### Available Schemas
162
-
163
- All schemas are exported from the SDK:
164
- - `MessageTypeSchema`
165
- - `ContentTypeSchema`
166
- - `CreateMessageParamsSchema`
167
- - `MessageSchema`
168
- - `EscalationTypeSchema`
169
- - `PrioritySchema`
170
- - `TeamSchema`
171
- - `AgentSchema`
172
- - `EscalationResponseSchema`
173
- - `ConversationStatusSchema`
174
- - `ConversationSchema`
646
+ ---
175
647
 
176
648
  ## Development
177
649
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@voltade/envoy-sdk",
3
- "version": "1.3.0",
3
+ "version": "1.3.1",
4
4
  "type": "module",
5
5
  "description": "A comprehensive TypeScript SDK for the Envoy API with built-in error handling and resource-based architecture",
6
6
  "main": "./dist/index.js",