@dispatchtickets/sdk 0.1.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,327 @@
1
+ # @dispatchtickets/sdk
2
+
3
+ Official TypeScript SDK for the Dispatch Tickets API.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @dispatchtickets/sdk
9
+ ```
10
+
11
+ ## Requirements
12
+
13
+ - Node.js 18 or later
14
+
15
+ ## Quick Start
16
+
17
+ ```typescript
18
+ import { DispatchTickets } from '@dispatchtickets/sdk';
19
+
20
+ const client = new DispatchTickets({
21
+ apiKey: 'sk_live_...',
22
+ });
23
+
24
+ // List brands
25
+ const brands = await client.brands.list();
26
+
27
+ // Create a ticket
28
+ const ticket = await client.tickets.create('ws_abc123', {
29
+ title: 'Help with login',
30
+ body: 'I cannot log in to my account',
31
+ });
32
+
33
+ // Add a comment
34
+ await client.comments.create('ws_abc123', ticket.id, {
35
+ body: 'Thanks for reaching out! Let me help you with that.',
36
+ authorType: 'AGENT',
37
+ });
38
+ ```
39
+
40
+ ## Configuration
41
+
42
+ ```typescript
43
+ const client = new DispatchTickets({
44
+ apiKey: 'sk_live_...', // Required
45
+ baseUrl: 'https://...', // Optional, default: production API
46
+ timeout: 30000, // Optional, request timeout in ms
47
+ maxRetries: 3, // Optional, retry count for failed requests
48
+ debug: false, // Optional, enable debug logging
49
+ });
50
+ ```
51
+
52
+ ## Resources
53
+
54
+ ### Brands
55
+
56
+ ```typescript
57
+ // Create a brand
58
+ const brand = await client.brands.create({
59
+ name: 'Acme Support',
60
+ slug: 'acme',
61
+ });
62
+
63
+ // List all brands
64
+ const brands = await client.brands.list();
65
+
66
+ // Get a brand
67
+ const brand = await client.brands.get('ws_abc123');
68
+
69
+ // Update a brand
70
+ await client.brands.update('ws_abc123', { name: 'New Name' });
71
+
72
+ // Delete a brand
73
+ await client.brands.delete('ws_abc123');
74
+ ```
75
+
76
+ ### Tickets
77
+
78
+ ```typescript
79
+ // Create a ticket
80
+ const ticket = await client.tickets.create('ws_abc123', {
81
+ title: 'Issue with billing',
82
+ body: 'I was charged twice...',
83
+ priority: 'high',
84
+ });
85
+
86
+ // Create with idempotency key (prevents duplicates)
87
+ const ticket = await client.tickets.create(
88
+ 'ws_abc123',
89
+ { title: 'Issue' },
90
+ { idempotencyKey: 'unique-request-id' }
91
+ );
92
+
93
+ // List tickets (paginated)
94
+ for await (const ticket of client.tickets.list('ws_abc123', { status: 'open' })) {
95
+ console.log(ticket.title);
96
+ }
97
+
98
+ // Get a single page
99
+ const page = await client.tickets.listPage('ws_abc123', { limit: 50 });
100
+
101
+ // Get a ticket
102
+ const ticket = await client.tickets.get('ws_abc123', 'tkt_xyz');
103
+
104
+ // Update a ticket
105
+ await client.tickets.update('ws_abc123', 'tkt_xyz', {
106
+ status: 'resolved',
107
+ });
108
+
109
+ // Delete a ticket
110
+ await client.tickets.delete('ws_abc123', 'tkt_xyz');
111
+
112
+ // Mark as spam
113
+ await client.tickets.markAsSpam('ws_abc123', 'tkt_xyz', true);
114
+
115
+ // Merge tickets
116
+ await client.tickets.merge('ws_abc123', 'tkt_target', ['tkt_source1', 'tkt_source2']);
117
+
118
+ // Bulk actions
119
+ await client.tickets.bulk('ws_abc123', 'close', ['tkt_1', 'tkt_2']);
120
+ await client.tickets.bulk('ws_abc123', 'assign', ['tkt_1'], { assigneeId: 'user_123' });
121
+ ```
122
+
123
+ ### Comments
124
+
125
+ ```typescript
126
+ // Add a comment
127
+ const comment = await client.comments.create('ws_abc123', 'tkt_xyz', {
128
+ body: 'Thanks for your patience!',
129
+ authorType: 'AGENT',
130
+ });
131
+
132
+ // List comments
133
+ const comments = await client.comments.list('ws_abc123', 'tkt_xyz');
134
+
135
+ // Update a comment
136
+ await client.comments.update('ws_abc123', 'tkt_xyz', 'cmt_abc', {
137
+ body: 'Updated message',
138
+ });
139
+
140
+ // Delete a comment
141
+ await client.comments.delete('ws_abc123', 'tkt_xyz', 'cmt_abc');
142
+ ```
143
+
144
+ ### Attachments
145
+
146
+ ```typescript
147
+ // Simple upload (handles the full flow)
148
+ const attachment = await client.attachments.upload(
149
+ 'ws_abc123',
150
+ 'tkt_xyz',
151
+ fileBuffer,
152
+ 'document.pdf',
153
+ 'application/pdf'
154
+ );
155
+
156
+ // Manual upload flow
157
+ const { uploadUrl, attachmentId } = await client.attachments.initiateUpload(
158
+ 'ws_abc123',
159
+ 'tkt_xyz',
160
+ { filename: 'doc.pdf', contentType: 'application/pdf', size: 1024 }
161
+ );
162
+ // Upload to presigned URL...
163
+ await client.attachments.confirmUpload('ws_abc123', 'tkt_xyz', attachmentId);
164
+
165
+ // List attachments
166
+ const attachments = await client.attachments.list('ws_abc123', 'tkt_xyz');
167
+
168
+ // Get download URL
169
+ const { downloadUrl } = await client.attachments.get('ws_abc123', 'tkt_xyz', 'att_abc');
170
+ ```
171
+
172
+ ### Webhooks
173
+
174
+ ```typescript
175
+ // Create a webhook
176
+ const webhook = await client.webhooks.create('ws_abc123', {
177
+ url: 'https://example.com/webhook',
178
+ secret: 'your-secret',
179
+ events: ['ticket.created', 'ticket.updated'],
180
+ });
181
+
182
+ // List webhooks
183
+ const webhooks = await client.webhooks.list('ws_abc123');
184
+
185
+ // Get delivery history
186
+ const deliveries = await client.webhooks.getDeliveries('ws_abc123', 'whk_abc');
187
+
188
+ // Verify webhook signature
189
+ const isValid = DispatchTickets.webhooks.verifySignature(
190
+ rawBody,
191
+ req.headers['x-dispatch-signature'],
192
+ 'your-secret'
193
+ );
194
+ ```
195
+
196
+ ### Categories
197
+
198
+ ```typescript
199
+ // Create a category
200
+ await client.categories.create('ws_abc123', { name: 'Billing', color: '#ef4444' });
201
+
202
+ // List categories
203
+ const categories = await client.categories.list('ws_abc123');
204
+
205
+ // Get stats
206
+ const stats = await client.categories.getStats('ws_abc123');
207
+
208
+ // Reorder
209
+ await client.categories.reorder('ws_abc123', ['cat_1', 'cat_2', 'cat_3']);
210
+ ```
211
+
212
+ ### Tags
213
+
214
+ ```typescript
215
+ // Create a tag
216
+ await client.tags.create('ws_abc123', { name: 'urgent', color: '#f59e0b' });
217
+
218
+ // List tags
219
+ const tags = await client.tags.list('ws_abc123');
220
+
221
+ // Merge tags
222
+ await client.tags.merge('ws_abc123', 'tag_target', ['tag_source1', 'tag_source2']);
223
+ ```
224
+
225
+ ### Customers
226
+
227
+ ```typescript
228
+ // Create a customer
229
+ const customer = await client.customers.create('ws_abc123', {
230
+ email: 'user@example.com',
231
+ name: 'Jane Doe',
232
+ });
233
+
234
+ // List customers (paginated)
235
+ for await (const customer of client.customers.list('ws_abc123')) {
236
+ console.log(customer.email);
237
+ }
238
+
239
+ // Search customers
240
+ const results = await client.customers.search('ws_abc123', 'jane');
241
+ ```
242
+
243
+ ### Custom Fields
244
+
245
+ ```typescript
246
+ // Get all field definitions
247
+ const fields = await client.fields.getAll('ws_abc123');
248
+
249
+ // Get ticket fields
250
+ const ticketFields = await client.fields.list('ws_abc123', 'ticket');
251
+
252
+ // Create a field
253
+ await client.fields.create('ws_abc123', 'ticket', {
254
+ key: 'order_id',
255
+ label: 'Order ID',
256
+ type: 'text',
257
+ required: true,
258
+ });
259
+
260
+ // Update a field
261
+ await client.fields.update('ws_abc123', 'ticket', 'order_id', {
262
+ required: false,
263
+ });
264
+
265
+ // Delete a field
266
+ await client.fields.delete('ws_abc123', 'ticket', 'order_id');
267
+ ```
268
+
269
+ ## Error Handling
270
+
271
+ ```typescript
272
+ import {
273
+ DispatchTickets,
274
+ AuthenticationError,
275
+ RateLimitError,
276
+ ValidationError,
277
+ NotFoundError,
278
+ } from '@dispatchtickets/sdk';
279
+
280
+ try {
281
+ await client.tickets.get('ws_abc123', 'tkt_invalid');
282
+ } catch (error) {
283
+ if (error instanceof NotFoundError) {
284
+ console.log('Ticket not found');
285
+ } else if (error instanceof AuthenticationError) {
286
+ console.log('Invalid API key');
287
+ } else if (error instanceof RateLimitError) {
288
+ console.log(`Rate limited. Retry after ${error.retryAfter} seconds`);
289
+ } else if (error instanceof ValidationError) {
290
+ console.log('Validation errors:', error.errors);
291
+ }
292
+ }
293
+ ```
294
+
295
+ ## Webhook Verification
296
+
297
+ ```typescript
298
+ import express from 'express';
299
+ import { DispatchTickets } from '@dispatchtickets/sdk';
300
+
301
+ const app = express();
302
+
303
+ // Use raw body for signature verification
304
+ app.use('/webhooks', express.raw({ type: 'application/json' }));
305
+
306
+ app.post('/webhooks', (req, res) => {
307
+ const signature = req.headers['x-dispatch-signature'] as string;
308
+ const isValid = DispatchTickets.webhooks.verifySignature(
309
+ req.body.toString(),
310
+ signature,
311
+ process.env.WEBHOOK_SECRET!
312
+ );
313
+
314
+ if (!isValid) {
315
+ return res.status(401).send('Invalid signature');
316
+ }
317
+
318
+ const event = JSON.parse(req.body.toString());
319
+ console.log('Received event:', event.type);
320
+
321
+ res.status(200).send('OK');
322
+ });
323
+ ```
324
+
325
+ ## License
326
+
327
+ MIT