@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 +327 -0
- package/dist/index.cjs +923 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +1116 -0
- package/dist/index.d.ts +1116 -0
- package/dist/index.js +910 -0
- package/dist/index.js.map +1 -0
- package/package.json +46 -0
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
|