@heymantle/core-api-client 0.1.6 → 0.1.7
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 +1056 -61
- package/dist/index.d.mts +5 -2
- package/dist/index.d.ts +5 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -40,153 +40,800 @@ const client = new MantleCoreClient({
|
|
|
40
40
|
});
|
|
41
41
|
```
|
|
42
42
|
|
|
43
|
+
## Middleware
|
|
44
|
+
|
|
45
|
+
The client supports Koa-style middleware for intercepting requests and responses. Middleware can be used for logging, authentication refresh, retry logic, and more.
|
|
46
|
+
|
|
47
|
+
### Creating Custom Middleware
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
import { MantleCoreClient, type Middleware } from '@heymantle/core-api-client';
|
|
51
|
+
|
|
52
|
+
// Logging middleware
|
|
53
|
+
const loggingMiddleware: Middleware = async (ctx, next) => {
|
|
54
|
+
const start = Date.now();
|
|
55
|
+
console.log(`[Request] ${ctx.request.method} ${ctx.request.url}`);
|
|
56
|
+
|
|
57
|
+
await next();
|
|
58
|
+
|
|
59
|
+
const duration = Date.now() - start;
|
|
60
|
+
console.log(`[Response] ${ctx.response?.status} (${duration}ms)`);
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
// Register middleware
|
|
64
|
+
const client = new MantleCoreClient({ apiKey: 'your-api-key' });
|
|
65
|
+
client.use(loggingMiddleware, { name: 'logging', priority: 10 });
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Auth Refresh Middleware
|
|
69
|
+
|
|
70
|
+
Automatically refresh expired access tokens:
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
import { MantleCoreClient, createAuthRefreshMiddleware } from '@heymantle/core-api-client';
|
|
74
|
+
|
|
75
|
+
const client = new MantleCoreClient({
|
|
76
|
+
accessToken: 'initial-token',
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
client.use(
|
|
80
|
+
createAuthRefreshMiddleware({
|
|
81
|
+
refreshToken: async () => {
|
|
82
|
+
// Call your token refresh endpoint
|
|
83
|
+
const response = await fetch('/api/refresh', { method: 'POST' });
|
|
84
|
+
const data = await response.json();
|
|
85
|
+
return data.accessToken;
|
|
86
|
+
},
|
|
87
|
+
onRefreshSuccess: (newToken) => {
|
|
88
|
+
// Persist the new token
|
|
89
|
+
localStorage.setItem('accessToken', newToken);
|
|
90
|
+
},
|
|
91
|
+
onRefreshFailed: (error) => {
|
|
92
|
+
// Redirect to login
|
|
93
|
+
window.location.href = '/login';
|
|
94
|
+
},
|
|
95
|
+
maxRefreshAttempts: 1,
|
|
96
|
+
}),
|
|
97
|
+
{ name: 'auth-refresh' }
|
|
98
|
+
);
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Middleware at Construction
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
const client = new MantleCoreClient({
|
|
105
|
+
apiKey: 'your-api-key',
|
|
106
|
+
middleware: [
|
|
107
|
+
loggingMiddleware,
|
|
108
|
+
[retryMiddleware, { name: 'retry', priority: 5 }],
|
|
109
|
+
],
|
|
110
|
+
});
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Middleware Context
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
interface MiddlewareContext<T = unknown> {
|
|
117
|
+
request: {
|
|
118
|
+
url: string;
|
|
119
|
+
method: 'GET' | 'POST' | 'PUT' | 'DELETE';
|
|
120
|
+
headers: Record<string, string>;
|
|
121
|
+
body?: string;
|
|
122
|
+
endpoint: string;
|
|
123
|
+
};
|
|
124
|
+
response?: {
|
|
125
|
+
data: T;
|
|
126
|
+
status: number;
|
|
127
|
+
headers: Headers;
|
|
128
|
+
};
|
|
129
|
+
error?: Error;
|
|
130
|
+
retry: boolean; // Set to true to retry the request
|
|
131
|
+
retryCount: number;
|
|
132
|
+
maxRetries: number;
|
|
133
|
+
updateAuth: (credentials: { apiKey?: string; accessToken?: string }) => void;
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
43
137
|
## Resources
|
|
44
138
|
|
|
45
139
|
### Customers
|
|
46
140
|
|
|
47
141
|
```typescript
|
|
48
142
|
// List customers with filters
|
|
49
|
-
const { customers } = await client.customers.list({
|
|
143
|
+
const { customers, hasNextPage, total } = await client.customers.list({
|
|
50
144
|
take: 25,
|
|
51
145
|
search: 'acme',
|
|
52
146
|
appIds: ['app_123'],
|
|
147
|
+
shopifyShopDomain: 'store.myshopify.com',
|
|
148
|
+
shopifyShopId: '12345',
|
|
149
|
+
includeUsageMetrics: true,
|
|
150
|
+
includeContactCount: true,
|
|
151
|
+
sort: 'createdAt',
|
|
152
|
+
sortDirection: 'desc',
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
// Retrieve a customer
|
|
156
|
+
const { customer } = await client.customers.retrieve('cust_123', {
|
|
157
|
+
includeContactCount: true,
|
|
158
|
+
includeCurrentInvoice: true,
|
|
53
159
|
});
|
|
54
160
|
|
|
55
161
|
// Create a customer
|
|
56
162
|
const { customer } = await client.customers.create({
|
|
57
163
|
name: 'Acme Inc',
|
|
58
164
|
email: 'contact@acme.com',
|
|
59
|
-
|
|
165
|
+
domain: 'acme.com',
|
|
166
|
+
shopifyDomain: 'acme.myshopify.com',
|
|
167
|
+
shopifyShopId: '12345',
|
|
168
|
+
countryCode: 'US',
|
|
169
|
+
preferredCurrency: 'USD',
|
|
170
|
+
description: 'Enterprise customer',
|
|
171
|
+
tags: ['enterprise', 'priority'],
|
|
172
|
+
customFields: { industry: 'Technology', employees: 500 },
|
|
173
|
+
companyId: 'company_123',
|
|
174
|
+
appInstallations: [
|
|
175
|
+
{ appId: 'app_123', installedAt: '2024-01-15T00:00:00Z', test: false },
|
|
176
|
+
],
|
|
60
177
|
});
|
|
61
178
|
|
|
62
179
|
// Update a customer
|
|
63
180
|
const { customer } = await client.customers.update('cust_123', {
|
|
64
181
|
name: 'Acme Corporation',
|
|
182
|
+
tags: ['enterprise', 'vip'],
|
|
65
183
|
});
|
|
66
184
|
|
|
67
185
|
// Add/remove tags
|
|
68
|
-
await client.customers.addTags('cust_123', ['premium']);
|
|
186
|
+
await client.customers.addTags('cust_123', ['premium', 'partner']);
|
|
69
187
|
await client.customers.removeTags('cust_123', ['trial']);
|
|
70
188
|
|
|
71
|
-
//
|
|
72
|
-
const { events } = await client.customers.getTimeline('cust_123'
|
|
189
|
+
// Timeline events
|
|
190
|
+
const { events, hasNextPage } = await client.customers.getTimeline('cust_123', {
|
|
191
|
+
appId: 'app_123',
|
|
192
|
+
type: 'subscription.created',
|
|
193
|
+
limit: 50,
|
|
194
|
+
cursor: 'cursor_abc',
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
// Account owners
|
|
198
|
+
const { accountOwners } = await client.customers.listAccountOwners('cust_123');
|
|
199
|
+
const { accountOwner } = await client.customers.addAccountOwner('cust_123', {
|
|
200
|
+
email: 'owner@acme.com',
|
|
201
|
+
name: 'John Owner',
|
|
202
|
+
});
|
|
203
|
+
await client.customers.removeAccountOwner('cust_123', 'owner_123');
|
|
204
|
+
|
|
205
|
+
// Custom fields
|
|
206
|
+
const { customFields } = await client.customers.listCustomFields({ appId: 'app_123' });
|
|
207
|
+
const { customField } = await client.customers.createCustomField({
|
|
208
|
+
appId: 'app_123',
|
|
209
|
+
name: 'Industry',
|
|
210
|
+
type: 'select', // 'string' | 'number' | 'boolean' | 'date' | 'select'
|
|
211
|
+
options: ['Technology', 'Healthcare', 'Finance', 'Retail'],
|
|
212
|
+
defaultValue: 'Technology',
|
|
213
|
+
showOnCustomerDetail: true,
|
|
214
|
+
filterable: true,
|
|
215
|
+
private: false,
|
|
216
|
+
});
|
|
217
|
+
const { customField } = await client.customers.retrieveCustomField('field_123');
|
|
218
|
+
const { customField } = await client.customers.updateCustomField('field_123', {
|
|
219
|
+
name: 'Industry Type',
|
|
220
|
+
options: ['Technology', 'Healthcare', 'Finance', 'Retail', 'Other'],
|
|
221
|
+
});
|
|
222
|
+
await client.customers.deleteCustomField('field_123');
|
|
73
223
|
```
|
|
74
224
|
|
|
75
225
|
### Contacts
|
|
76
226
|
|
|
77
227
|
```typescript
|
|
78
|
-
|
|
228
|
+
// List contacts
|
|
229
|
+
const { contacts, hasNextPage } = await client.contacts.list({
|
|
230
|
+
take: 25,
|
|
231
|
+
search: 'john',
|
|
232
|
+
socialProfileType: 'linkedin', // 'linkedin' | 'x' | 'facebook' | 'instagram' | 'website'
|
|
233
|
+
socialProfileUrl: 'https://linkedin.com/in/johndoe',
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
// Create a contact with social profiles
|
|
79
237
|
const { contact } = await client.contacts.create({
|
|
80
238
|
name: 'John Doe',
|
|
81
|
-
email: 'john@
|
|
239
|
+
email: 'john@acme.com',
|
|
240
|
+
phone: '+1-555-123-4567',
|
|
241
|
+
jobTitle: 'CTO',
|
|
242
|
+
notes: 'Primary technical contact',
|
|
243
|
+
tags: ['decision-maker', 'technical'],
|
|
244
|
+
customers: ['cust_123', 'cust_456'],
|
|
245
|
+
socialProfiles: [
|
|
246
|
+
{ key: 'linkedin', value: 'https://linkedin.com/in/johndoe' },
|
|
247
|
+
{ key: 'x', value: 'https://x.com/johndoe' },
|
|
248
|
+
{ key: 'website', value: 'https://johndoe.com' },
|
|
249
|
+
],
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
// Update a contact
|
|
253
|
+
const { contact } = await client.contacts.update('contact_123', {
|
|
254
|
+
jobTitle: 'VP of Engineering',
|
|
255
|
+
socialProfiles: [
|
|
256
|
+
{ key: 'linkedin', value: 'https://linkedin.com/in/johndoe-updated' },
|
|
257
|
+
],
|
|
82
258
|
});
|
|
259
|
+
|
|
260
|
+
// Retrieve a contact
|
|
261
|
+
const { contact } = await client.contacts.retrieve('contact_123');
|
|
83
262
|
```
|
|
84
263
|
|
|
85
264
|
### Subscriptions
|
|
86
265
|
|
|
87
266
|
```typescript
|
|
88
|
-
|
|
267
|
+
// List subscriptions
|
|
268
|
+
const { subscriptions, hasNextPage } = await client.subscriptions.list({
|
|
89
269
|
appId: 'app_123',
|
|
270
|
+
customerId: 'cust_123',
|
|
90
271
|
active: true,
|
|
272
|
+
ids: ['sub_123', 'sub_456'],
|
|
273
|
+
startDate: '2024-01-01',
|
|
274
|
+
endDate: '2024-12-31',
|
|
91
275
|
});
|
|
276
|
+
|
|
277
|
+
// Retrieve a subscription
|
|
92
278
|
const { subscription } = await client.subscriptions.retrieve('sub_123');
|
|
93
279
|
```
|
|
94
280
|
|
|
95
|
-
###
|
|
281
|
+
### Deals
|
|
282
|
+
|
|
283
|
+
Deals support multiple ways to link customers and contacts:
|
|
284
|
+
|
|
285
|
+
```typescript
|
|
286
|
+
// List deals with filters
|
|
287
|
+
const { deals, hasNextPage, total } = await client.deals.list({
|
|
288
|
+
customerId: 'cust_123',
|
|
289
|
+
appId: 'app_123',
|
|
290
|
+
planId: 'plan_123',
|
|
291
|
+
dealStageId: 'stage_123',
|
|
292
|
+
dealFlowId: 'flow_123',
|
|
293
|
+
affiliateId: 'aff_123',
|
|
294
|
+
partnershipId: 'partner_123',
|
|
295
|
+
acquirerId: 'user_123',
|
|
296
|
+
ownerId: 'user_456',
|
|
297
|
+
contactId: 'contact_123',
|
|
298
|
+
stage: 'negotiation',
|
|
299
|
+
minAmount: 1000,
|
|
300
|
+
maxAmount: 50000,
|
|
301
|
+
acquisitionChannel: 'inbound',
|
|
302
|
+
acquisitionSource: 'website',
|
|
303
|
+
includeArchived: false,
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
// Create a deal - Option 1: Link existing customer
|
|
307
|
+
const { deal } = await client.deals.create({
|
|
308
|
+
name: 'Enterprise Deal',
|
|
309
|
+
amount: 50000,
|
|
310
|
+
amountCurrencyCode: 'USD',
|
|
311
|
+
customerId: 'cust_123',
|
|
312
|
+
contactIds: ['contact_123', 'contact_456'],
|
|
313
|
+
dealFlowId: 'flow_123',
|
|
314
|
+
dealStageId: 'stage_123',
|
|
315
|
+
appId: 'app_123',
|
|
316
|
+
planId: 'plan_456',
|
|
317
|
+
ownerIds: ['user_123'],
|
|
318
|
+
acquisitionChannel: 'outbound',
|
|
319
|
+
acquisitionSource: 'sales_call',
|
|
320
|
+
firstInteractionAt: '2024-01-15T10:00:00Z',
|
|
321
|
+
closingAt: '2024-03-01T00:00:00Z',
|
|
322
|
+
notes: 'High priority enterprise deal',
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
// Create a deal - Option 2: Create/update customer inline
|
|
326
|
+
const { deal } = await client.deals.create({
|
|
327
|
+
name: 'New Prospect Deal',
|
|
328
|
+
amount: 25000,
|
|
329
|
+
// Customer will be matched by domain or created if not found
|
|
330
|
+
customer: {
|
|
331
|
+
name: 'Acme Corp',
|
|
332
|
+
email: 'info@acme.com',
|
|
333
|
+
domain: 'acme.com',
|
|
334
|
+
shopifyDomain: 'acme.myshopify.com',
|
|
335
|
+
shopifyShopId: '12345',
|
|
336
|
+
tags: ['prospect'],
|
|
337
|
+
countryCode: 'US',
|
|
338
|
+
preferredCurrency: 'USD',
|
|
339
|
+
},
|
|
340
|
+
// Contacts will be matched by email or created if not found
|
|
341
|
+
contacts: [
|
|
342
|
+
{
|
|
343
|
+
email: 'john@acme.com',
|
|
344
|
+
name: 'John Doe',
|
|
345
|
+
phone: '+1-555-123-4567',
|
|
346
|
+
jobTitle: 'CEO',
|
|
347
|
+
label: 'primary',
|
|
348
|
+
notes: 'Decision maker',
|
|
349
|
+
tags: ['executive'],
|
|
350
|
+
},
|
|
351
|
+
{
|
|
352
|
+
email: 'jane@acme.com',
|
|
353
|
+
name: 'Jane Smith',
|
|
354
|
+
jobTitle: 'CTO',
|
|
355
|
+
label: 'technical',
|
|
356
|
+
},
|
|
357
|
+
],
|
|
358
|
+
dealFlowId: 'flow_123',
|
|
359
|
+
dealStageId: 'stage_123',
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
// Create a deal - Option 3: Find/create customer by domain
|
|
363
|
+
const { deal } = await client.deals.create({
|
|
364
|
+
name: 'Domain-based Deal',
|
|
365
|
+
shopifyDomain: 'newstore.myshopify.com',
|
|
366
|
+
dealFlowId: 'flow_123',
|
|
367
|
+
dealStageId: 'stage_123',
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
// Update a deal
|
|
371
|
+
const { deal } = await client.deals.update('deal_123', {
|
|
372
|
+
amount: 75000,
|
|
373
|
+
dealStageId: 'stage_456',
|
|
374
|
+
closedAt: '2024-02-15T00:00:00Z',
|
|
375
|
+
notes: 'Deal closed successfully!',
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
// Archive a deal
|
|
379
|
+
await client.deals.del('deal_123');
|
|
380
|
+
|
|
381
|
+
// Get deal timeline
|
|
382
|
+
const { events } = await client.deals.getTimeline('deal_123');
|
|
383
|
+
|
|
384
|
+
// Get deal events
|
|
385
|
+
const { events } = await client.deals.getEvents('deal_123');
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
### Deal Flows
|
|
389
|
+
|
|
390
|
+
Manage deal pipelines and stages:
|
|
391
|
+
|
|
392
|
+
```typescript
|
|
393
|
+
// List deal flows
|
|
394
|
+
const { dealFlows } = await client.dealFlows.list();
|
|
395
|
+
|
|
396
|
+
// Retrieve a deal flow with stages
|
|
397
|
+
const { dealFlow } = await client.dealFlows.retrieve('flow_123');
|
|
398
|
+
// dealFlow.stages contains the ordered stages
|
|
399
|
+
|
|
400
|
+
// Create a deal flow
|
|
401
|
+
const { dealFlow } = await client.dealFlows.create({
|
|
402
|
+
name: 'Enterprise Sales Pipeline',
|
|
403
|
+
description: 'For deals over $10k',
|
|
404
|
+
});
|
|
405
|
+
|
|
406
|
+
// Update a deal flow
|
|
407
|
+
const { dealFlow } = await client.dealFlows.update('flow_123', {
|
|
408
|
+
name: 'Enterprise Sales Pipeline v2',
|
|
409
|
+
});
|
|
410
|
+
|
|
411
|
+
// Delete a deal flow
|
|
412
|
+
await client.dealFlows.del('flow_123');
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
### Deal Activities
|
|
416
|
+
|
|
417
|
+
Track activities within deal flows:
|
|
418
|
+
|
|
419
|
+
```typescript
|
|
420
|
+
// List deal activities
|
|
421
|
+
const { dealActivities } = await client.dealActivities.list();
|
|
422
|
+
|
|
423
|
+
// Retrieve a deal activity
|
|
424
|
+
const { dealActivity } = await client.dealActivities.retrieve('activity_123');
|
|
425
|
+
|
|
426
|
+
// Create a deal activity
|
|
427
|
+
const { dealActivity } = await client.dealActivities.create({
|
|
428
|
+
name: 'Initial Call',
|
|
429
|
+
dealFlowId: 'flow_123',
|
|
430
|
+
description: 'First discovery call with prospect',
|
|
431
|
+
order: 1,
|
|
432
|
+
});
|
|
433
|
+
|
|
434
|
+
// Update a deal activity
|
|
435
|
+
const { dealActivity } = await client.dealActivities.update('activity_123', {
|
|
436
|
+
name: 'Discovery Call',
|
|
437
|
+
description: 'Updated description',
|
|
438
|
+
});
|
|
439
|
+
|
|
440
|
+
// Delete a deal activity
|
|
441
|
+
await client.dealActivities.del('activity_123');
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
### Apps
|
|
96
445
|
|
|
97
446
|
```typescript
|
|
98
447
|
// List apps
|
|
99
|
-
const { apps } = await client.apps.list(
|
|
448
|
+
const { apps } = await client.apps.list({
|
|
449
|
+
minUpdatedAt: '2024-01-01T00:00:00Z',
|
|
450
|
+
maxUpdatedAt: '2024-12-31T23:59:59Z',
|
|
451
|
+
});
|
|
452
|
+
|
|
453
|
+
// Retrieve an app
|
|
454
|
+
const { app } = await client.apps.retrieve('app_123');
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
### Plans
|
|
100
458
|
|
|
459
|
+
```typescript
|
|
101
460
|
// List plans for an app
|
|
102
|
-
const { plans } = await client.apps.listPlans('app_123'
|
|
461
|
+
const { plans, total, hasMore } = await client.apps.listPlans('app_123', {
|
|
462
|
+
public: true,
|
|
463
|
+
page: 0,
|
|
464
|
+
perPage: 25,
|
|
465
|
+
search: 'pro',
|
|
466
|
+
});
|
|
467
|
+
|
|
468
|
+
// Retrieve a plan
|
|
469
|
+
const { plan } = await client.apps.retrievePlan('app_123', 'plan_123');
|
|
103
470
|
|
|
104
|
-
// Create a plan
|
|
471
|
+
// Create a plan with usage charges and features
|
|
105
472
|
const { plan } = await client.apps.createPlan('app_123', {
|
|
106
473
|
name: 'Pro Plan',
|
|
107
|
-
|
|
474
|
+
description: 'For growing businesses',
|
|
475
|
+
amount: 4900, // $49.00
|
|
108
476
|
currencyCode: 'USD',
|
|
109
|
-
interval: 'month',
|
|
477
|
+
interval: 'month', // 'month' | 'year' | 'one_time'
|
|
478
|
+
trialDays: 14,
|
|
479
|
+
public: true,
|
|
480
|
+
visible: true,
|
|
481
|
+
customerTags: ['premium'],
|
|
482
|
+
customerExcludeTags: ['churned'],
|
|
483
|
+
shopifyPlans: ['shopify', 'advanced'],
|
|
484
|
+
flexBilling: true,
|
|
485
|
+
flexBillingTerms: 'Charged at end of billing period',
|
|
486
|
+
// Usage-based pricing
|
|
487
|
+
planUsageCharges: [
|
|
488
|
+
{
|
|
489
|
+
usageMetricId: 'metric_123',
|
|
490
|
+
cappedAmount: 10000, // $100 cap
|
|
491
|
+
terms: '$0.01 per API call',
|
|
492
|
+
interval: 'month',
|
|
493
|
+
},
|
|
494
|
+
],
|
|
495
|
+
// Feature flags
|
|
496
|
+
features: [
|
|
497
|
+
{ featureId: 'feature_api', value: true },
|
|
498
|
+
{ featureId: 'feature_seats', value: 10 },
|
|
499
|
+
],
|
|
500
|
+
customFields: { tier: 'mid' },
|
|
110
501
|
});
|
|
111
502
|
|
|
112
|
-
//
|
|
503
|
+
// Update a plan
|
|
504
|
+
const { plan } = await client.apps.updatePlan('app_123', 'plan_123', {
|
|
505
|
+
amount: 5900,
|
|
506
|
+
description: 'Updated description',
|
|
507
|
+
});
|
|
508
|
+
|
|
509
|
+
// Archive/unarchive a plan
|
|
510
|
+
await client.apps.archivePlan('app_123', 'plan_123');
|
|
511
|
+
await client.apps.unarchivePlan('app_123', 'plan_123');
|
|
512
|
+
```
|
|
513
|
+
|
|
514
|
+
### Features
|
|
515
|
+
|
|
516
|
+
```typescript
|
|
517
|
+
// List features
|
|
113
518
|
const { features } = await client.apps.listFeatures('app_123');
|
|
519
|
+
|
|
520
|
+
// Retrieve a feature
|
|
521
|
+
const { feature } = await client.apps.retrieveFeature('app_123', 'feature_123');
|
|
522
|
+
|
|
523
|
+
// Create a feature
|
|
114
524
|
const { feature } = await client.apps.createFeature('app_123', {
|
|
115
525
|
name: 'API Access',
|
|
116
|
-
type: 'boolean',
|
|
526
|
+
type: 'boolean', // 'boolean' | 'limit' | 'unlimited'
|
|
527
|
+
description: 'Access to REST API',
|
|
528
|
+
usageMetricId: 'metric_123', // Link to usage tracking
|
|
529
|
+
});
|
|
530
|
+
|
|
531
|
+
// Update a feature
|
|
532
|
+
const { feature } = await client.apps.updateFeature('app_123', 'feature_123', {
|
|
533
|
+
name: 'API Access v2',
|
|
534
|
+
description: 'Updated description',
|
|
117
535
|
});
|
|
536
|
+
|
|
537
|
+
// Delete a feature
|
|
538
|
+
await client.apps.deleteFeature('app_123', 'feature_123');
|
|
118
539
|
```
|
|
119
540
|
|
|
120
|
-
###
|
|
541
|
+
### Usage Metrics
|
|
121
542
|
|
|
122
543
|
```typescript
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
544
|
+
// List usage metrics
|
|
545
|
+
const { usageMetrics } = await client.apps.listUsageMetrics('app_123');
|
|
546
|
+
|
|
547
|
+
// Retrieve a usage metric
|
|
548
|
+
const { usageMetric } = await client.apps.retrieveUsageMetric('app_123', 'metric_123');
|
|
549
|
+
|
|
550
|
+
// Create a usage metric
|
|
551
|
+
const { usageMetric } = await client.apps.createUsageMetric('app_123', {
|
|
552
|
+
name: 'API Calls',
|
|
553
|
+
description: 'Number of API requests',
|
|
554
|
+
eventName: 'api_call',
|
|
555
|
+
aggregationType: 'count',
|
|
126
556
|
});
|
|
127
557
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
558
|
+
// Update a usage metric
|
|
559
|
+
const { usageMetric } = await client.apps.updateUsageMetric('app_123', 'metric_123', {
|
|
560
|
+
name: 'API Requests',
|
|
561
|
+
});
|
|
562
|
+
|
|
563
|
+
// Delete a usage metric
|
|
564
|
+
await client.apps.deleteUsageMetric('app_123', 'metric_123');
|
|
565
|
+
|
|
566
|
+
// Get event names for an app
|
|
567
|
+
const { eventNames } = await client.apps.listEventNames('app_123');
|
|
568
|
+
|
|
569
|
+
// Get property keys for an event
|
|
570
|
+
const { propertyKeys } = await client.apps.listPropertyKeys('app_123', 'api_call');
|
|
571
|
+
```
|
|
572
|
+
|
|
573
|
+
### App Events
|
|
574
|
+
|
|
575
|
+
```typescript
|
|
576
|
+
// List app events
|
|
577
|
+
const { appEvents, hasNextPage } = await client.apps.listAppEvents('app_123', {
|
|
131
578
|
customerId: 'cust_123',
|
|
579
|
+
take: 50,
|
|
580
|
+
});
|
|
581
|
+
```
|
|
582
|
+
|
|
583
|
+
### Reviews
|
|
584
|
+
|
|
585
|
+
```typescript
|
|
586
|
+
// List reviews
|
|
587
|
+
const { reviews } = await client.apps.listReviews('app_123');
|
|
588
|
+
|
|
589
|
+
// Retrieve a review
|
|
590
|
+
const { review } = await client.apps.retrieveReview('app_123', 'review_123');
|
|
591
|
+
|
|
592
|
+
// Create a review
|
|
593
|
+
const { review } = await client.apps.createReview('app_123', {
|
|
594
|
+
rating: 5,
|
|
595
|
+
title: 'Excellent app!',
|
|
596
|
+
body: 'This app transformed our workflow.',
|
|
597
|
+
});
|
|
598
|
+
|
|
599
|
+
// Update a review
|
|
600
|
+
const { review } = await client.apps.updateReview('app_123', 'review_123', {
|
|
601
|
+
rating: 4,
|
|
602
|
+
body: 'Updated review text',
|
|
132
603
|
});
|
|
604
|
+
|
|
605
|
+
// Delete a review
|
|
606
|
+
await client.apps.deleteReview('app_123', 'review_123');
|
|
133
607
|
```
|
|
134
608
|
|
|
135
609
|
### Tickets
|
|
136
610
|
|
|
137
611
|
```typescript
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
612
|
+
// List tickets with filters
|
|
613
|
+
const { tickets, hasNextPage, total } = await client.tickets.list({
|
|
614
|
+
status: 'open', // 'open' | 'pending' | 'resolved' | 'closed'
|
|
615
|
+
priority: 'high', // 'low' | 'medium' | 'high' | 'urgent'
|
|
616
|
+
assignedToId: 'user_123',
|
|
617
|
+
appId: 'app_123',
|
|
618
|
+
customerId: 'cust_123',
|
|
619
|
+
contactId: 'contact_123',
|
|
620
|
+
channelId: 'channel_123',
|
|
621
|
+
tags: ['billing', 'urgent'],
|
|
622
|
+
take: 25,
|
|
141
623
|
});
|
|
142
624
|
|
|
625
|
+
// Retrieve a ticket
|
|
626
|
+
const { ticket } = await client.tickets.retrieve('ticket_123');
|
|
627
|
+
|
|
628
|
+
// Create a ticket - Option 1: Link existing contact
|
|
143
629
|
const { ticket } = await client.tickets.create({
|
|
144
630
|
subject: 'Need help with integration',
|
|
631
|
+
status: 'open',
|
|
632
|
+
priority: 'medium',
|
|
145
633
|
customerId: 'cust_123',
|
|
634
|
+
contactId: 'contact_123',
|
|
635
|
+
appId: 'app_123',
|
|
636
|
+
channelId: 'channel_123',
|
|
637
|
+
assignedToId: 'user_123',
|
|
638
|
+
tags: ['integration', 'api'],
|
|
639
|
+
});
|
|
640
|
+
|
|
641
|
+
// Create a ticket - Option 2: Create contact inline
|
|
642
|
+
const { ticket } = await client.tickets.create({
|
|
643
|
+
subject: 'Billing question',
|
|
644
|
+
priority: 'high',
|
|
645
|
+
customerId: 'cust_123',
|
|
646
|
+
contact: {
|
|
647
|
+
email: 'support-requester@acme.com',
|
|
648
|
+
name: 'Support User',
|
|
649
|
+
},
|
|
146
650
|
});
|
|
147
651
|
|
|
148
|
-
//
|
|
652
|
+
// Update a ticket
|
|
653
|
+
const { ticket } = await client.tickets.update('ticket_123', {
|
|
654
|
+
status: 'pending',
|
|
655
|
+
priority: 'urgent',
|
|
656
|
+
assignedToId: 'user_456',
|
|
657
|
+
tags: ['escalated'],
|
|
658
|
+
});
|
|
659
|
+
|
|
660
|
+
// Delete a ticket
|
|
661
|
+
await client.tickets.del('ticket_123');
|
|
662
|
+
|
|
663
|
+
// List messages for a ticket
|
|
664
|
+
const { messages } = await client.tickets.listMessages('ticket_123');
|
|
665
|
+
|
|
666
|
+
// Retrieve a message
|
|
667
|
+
const { message } = await client.tickets.retrieveMessage('ticket_123', 'message_123');
|
|
668
|
+
|
|
669
|
+
// Create a message with attachments
|
|
149
670
|
const { message } = await client.tickets.createMessage('ticket_123', {
|
|
150
|
-
body: 'Here is the solution...',
|
|
151
|
-
from: 'agent',
|
|
671
|
+
body: 'Here is the solution to your problem...',
|
|
672
|
+
from: 'agent', // 'customer' | 'agent'
|
|
673
|
+
attachments: [
|
|
674
|
+
{
|
|
675
|
+
filename: 'solution.pdf',
|
|
676
|
+
url: 'https://storage.example.com/solution.pdf',
|
|
677
|
+
contentType: 'application/pdf',
|
|
678
|
+
size: 102400,
|
|
679
|
+
},
|
|
680
|
+
],
|
|
681
|
+
});
|
|
682
|
+
|
|
683
|
+
// Update a message
|
|
684
|
+
const { message } = await client.tickets.updateMessage('ticket_123', 'message_123', {
|
|
685
|
+
body: 'Updated message content',
|
|
686
|
+
});
|
|
687
|
+
|
|
688
|
+
// Delete a message
|
|
689
|
+
await client.tickets.deleteMessage('ticket_123', 'message_123');
|
|
690
|
+
```
|
|
691
|
+
|
|
692
|
+
### Channels
|
|
693
|
+
|
|
694
|
+
Manage CX channels for tickets:
|
|
695
|
+
|
|
696
|
+
```typescript
|
|
697
|
+
// List channels
|
|
698
|
+
const { channels } = await client.channels.list({
|
|
699
|
+
type: 'email', // 'email' | 'chat'
|
|
700
|
+
});
|
|
701
|
+
|
|
702
|
+
// Create a channel
|
|
703
|
+
const { channel } = await client.channels.create({
|
|
704
|
+
type: 'email',
|
|
705
|
+
name: 'Support Email',
|
|
152
706
|
});
|
|
153
707
|
```
|
|
154
708
|
|
|
709
|
+
### Agents
|
|
710
|
+
|
|
711
|
+
List support agents:
|
|
712
|
+
|
|
713
|
+
```typescript
|
|
714
|
+
// List agents
|
|
715
|
+
const { agents } = await client.agents.list();
|
|
716
|
+
```
|
|
717
|
+
|
|
155
718
|
### Metrics
|
|
156
719
|
|
|
720
|
+
Retrieve analytics and business metrics:
|
|
721
|
+
|
|
157
722
|
```typescript
|
|
158
|
-
|
|
723
|
+
import type { DateRangeType } from '@heymantle/core-api-client';
|
|
724
|
+
|
|
725
|
+
// Date range options:
|
|
726
|
+
// 'last_30_minutes' | 'last_60_minutes' | 'last_12_hours' | 'last_24_hours'
|
|
727
|
+
// 'last_7_days' | 'last_14_days' | 'last_30_days' | 'last_90_days'
|
|
728
|
+
// 'last_12_months' | 'last_24_months'
|
|
729
|
+
// 'today' | 'yesterday' | 'last_month'
|
|
730
|
+
// 'month_to_date' | 'quarter_to_date' | 'year_to_date'
|
|
731
|
+
// 'all_time' | 'custom'
|
|
732
|
+
|
|
733
|
+
// Monthly Recurring Revenue
|
|
159
734
|
const mrr = await client.metrics.mrr({
|
|
160
735
|
appId: 'app_123',
|
|
161
736
|
dateRange: 'last_30_days',
|
|
162
737
|
});
|
|
738
|
+
console.log(mrr.total, mrr.formattedTotal); // 50000, "$500.00"
|
|
739
|
+
console.log(mrr.change, mrr.changePercentage); // 5000, 10
|
|
163
740
|
|
|
164
|
-
//
|
|
741
|
+
// Annual Recurring Revenue
|
|
165
742
|
const arr = await client.metrics.arr({ appId: 'app_123' });
|
|
166
743
|
|
|
167
|
-
//
|
|
744
|
+
// Average Revenue Per User
|
|
168
745
|
const arpu = await client.metrics.arpu({ appId: 'app_123' });
|
|
169
|
-
|
|
746
|
+
|
|
747
|
+
// Customer Lifetime Value
|
|
170
748
|
const ltv = await client.metrics.ltv({ appId: 'app_123' });
|
|
749
|
+
|
|
750
|
+
// Predicted LTV
|
|
751
|
+
const predictedLtv = await client.metrics.predictedLtv({ appId: 'app_123' });
|
|
752
|
+
|
|
753
|
+
// Revenue Churn
|
|
754
|
+
const revenueChurn = await client.metrics.revenueChurn({ appId: 'app_123' });
|
|
755
|
+
|
|
756
|
+
// Logo (Customer) Churn
|
|
757
|
+
const logoChurn = await client.metrics.logoChurn({ appId: 'app_123' });
|
|
758
|
+
|
|
759
|
+
// Revenue Retention
|
|
760
|
+
const revenueRetention = await client.metrics.revenueRetention({ appId: 'app_123' });
|
|
761
|
+
|
|
762
|
+
// Net Revenue Retention
|
|
171
763
|
const nrr = await client.metrics.netRevenueRetention({ appId: 'app_123' });
|
|
172
764
|
|
|
765
|
+
// Net Revenue
|
|
766
|
+
const netRevenue = await client.metrics.netRevenue({ appId: 'app_123' });
|
|
767
|
+
|
|
768
|
+
// Active Subscriptions
|
|
769
|
+
const activeSubs = await client.metrics.activeSubscriptions({ appId: 'app_123' });
|
|
770
|
+
|
|
771
|
+
// Active Installs
|
|
772
|
+
const activeInstalls = await client.metrics.activeInstalls({ appId: 'app_123' });
|
|
773
|
+
|
|
774
|
+
// Net Installs
|
|
775
|
+
const netInstalls = await client.metrics.netInstalls({ appId: 'app_123' });
|
|
776
|
+
|
|
777
|
+
// Charges
|
|
778
|
+
const charges = await client.metrics.charges({ appId: 'app_123' });
|
|
779
|
+
|
|
780
|
+
// Payout
|
|
781
|
+
const payout = await client.metrics.payout({ appId: 'app_123' });
|
|
782
|
+
|
|
783
|
+
// Usage event metrics
|
|
784
|
+
const usageMetrics = await client.metrics.usageEvent({
|
|
785
|
+
appId: 'app_123',
|
|
786
|
+
eventName: 'api_call',
|
|
787
|
+
propertyKey: 'endpoint',
|
|
788
|
+
aggregation: 'count', // 'count' | 'sum' | 'avg' | 'min' | 'max'
|
|
789
|
+
dateRange: 'last_7_days',
|
|
790
|
+
});
|
|
791
|
+
|
|
792
|
+
// Usage metric by ID
|
|
793
|
+
const metricData = await client.metrics.usageMetric({
|
|
794
|
+
appId: 'app_123',
|
|
795
|
+
metricId: 'metric_123',
|
|
796
|
+
dateRange: 'last_30_days',
|
|
797
|
+
});
|
|
798
|
+
|
|
173
799
|
// Custom metric query
|
|
174
800
|
const data = await client.metrics.fetch({
|
|
175
801
|
metric: 'PlatformApp.activeInstalls',
|
|
176
802
|
appId: 'app_123',
|
|
177
803
|
dateRange: 'last_90_days',
|
|
804
|
+
startDate: '2024-01-01',
|
|
805
|
+
endDate: '2024-03-31',
|
|
806
|
+
includes: ['includeTotal'],
|
|
807
|
+
appEventsForMrr: true,
|
|
178
808
|
});
|
|
179
809
|
```
|
|
180
810
|
|
|
181
811
|
### Usage Events
|
|
182
812
|
|
|
813
|
+
Track customer usage for billing:
|
|
814
|
+
|
|
183
815
|
```typescript
|
|
816
|
+
// List usage events
|
|
817
|
+
const { usageEvents, hasNextPage } = await client.usageEvents.list({
|
|
818
|
+
appId: 'app_123',
|
|
819
|
+
customerId: 'cust_123',
|
|
820
|
+
eventName: 'api_call',
|
|
821
|
+
billingStatus: 'unbilled',
|
|
822
|
+
countryCode: 'US',
|
|
823
|
+
startDate: '2024-01-01',
|
|
824
|
+
endDate: '2024-01-31',
|
|
825
|
+
propertiesFilters: { endpoint: '/users' },
|
|
826
|
+
});
|
|
827
|
+
|
|
184
828
|
// Track a single event
|
|
185
829
|
await client.usageEvents.create({
|
|
186
830
|
eventName: 'api_call',
|
|
187
831
|
customerId: 'cust_123',
|
|
188
832
|
appId: 'app_123',
|
|
189
|
-
|
|
833
|
+
timestamp: new Date().toISOString(),
|
|
834
|
+
eventId: 'unique-event-id', // For deduplication
|
|
835
|
+
properties: { endpoint: '/users', method: 'GET', responseTime: 150 },
|
|
836
|
+
private: false,
|
|
190
837
|
});
|
|
191
838
|
|
|
192
839
|
// Track multiple events
|
|
@@ -194,6 +841,7 @@ await client.usageEvents.create({
|
|
|
194
841
|
events: [
|
|
195
842
|
{ eventName: 'api_call', customerId: 'cust_123', appId: 'app_123' },
|
|
196
843
|
{ eventName: 'api_call', customerId: 'cust_456', appId: 'app_123' },
|
|
844
|
+
{ eventName: 'file_upload', customerId: 'cust_123', appId: 'app_123', properties: { size: 1024 } },
|
|
197
845
|
],
|
|
198
846
|
});
|
|
199
847
|
```
|
|
@@ -201,56 +849,341 @@ await client.usageEvents.create({
|
|
|
201
849
|
### Webhooks
|
|
202
850
|
|
|
203
851
|
```typescript
|
|
852
|
+
// List webhooks
|
|
204
853
|
const { webhooks } = await client.webhooks.list();
|
|
205
854
|
|
|
855
|
+
// Retrieve a webhook
|
|
856
|
+
const { webhook } = await client.webhooks.retrieve('webhook_123');
|
|
857
|
+
|
|
858
|
+
// Create a webhook
|
|
206
859
|
const { webhook } = await client.webhooks.create({
|
|
207
860
|
topic: 'customer.created',
|
|
208
861
|
address: 'https://your-app.com/webhooks',
|
|
209
862
|
});
|
|
863
|
+
|
|
864
|
+
// Update a webhook
|
|
865
|
+
const { webhook } = await client.webhooks.update('webhook_123', {
|
|
866
|
+
address: 'https://your-app.com/webhooks/v2',
|
|
867
|
+
});
|
|
868
|
+
|
|
869
|
+
// Delete a webhook
|
|
870
|
+
await client.webhooks.del('webhook_123');
|
|
210
871
|
```
|
|
211
872
|
|
|
212
873
|
### Affiliates
|
|
213
874
|
|
|
214
875
|
```typescript
|
|
215
|
-
|
|
876
|
+
// List affiliates
|
|
877
|
+
const { affiliates, hasNextPage } = await client.affiliates.list({
|
|
878
|
+
affiliateProgramId: 'program_123',
|
|
879
|
+
status: 'active', // 'pending' | 'active' | 'rejected' | 'suspended'
|
|
880
|
+
appId: 'app_123',
|
|
881
|
+
email: 'affiliate@example.com',
|
|
882
|
+
});
|
|
883
|
+
|
|
884
|
+
// Retrieve an affiliate
|
|
885
|
+
const { affiliate } = await client.affiliates.retrieve('affiliate_123');
|
|
886
|
+
|
|
887
|
+
// Update an affiliate
|
|
888
|
+
const { affiliate } = await client.affiliates.update('affiliate_123', {
|
|
216
889
|
status: 'active',
|
|
890
|
+
commissionRate: 0.25, // 25%
|
|
217
891
|
});
|
|
892
|
+
```
|
|
893
|
+
|
|
894
|
+
### Affiliate Programs
|
|
218
895
|
|
|
896
|
+
```typescript
|
|
897
|
+
// List affiliate programs
|
|
219
898
|
const { affiliatePrograms } = await client.affiliatePrograms.list();
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
const {
|
|
899
|
+
|
|
900
|
+
// Retrieve an affiliate program
|
|
901
|
+
const { affiliateProgram } = await client.affiliatePrograms.retrieve('program_123');
|
|
902
|
+
|
|
903
|
+
// Create an affiliate program
|
|
904
|
+
const { affiliateProgram } = await client.affiliatePrograms.create({
|
|
905
|
+
name: 'Partner Program',
|
|
906
|
+
description: 'Earn 20% commission on referrals',
|
|
907
|
+
commissionType: 'percentage', // 'percentage' | 'fixed'
|
|
908
|
+
commissionValue: 20,
|
|
909
|
+
commissionDurationMonths: 12,
|
|
910
|
+
cookieDurationDays: 30,
|
|
911
|
+
minimumPayoutAmount: 5000, // $50.00
|
|
912
|
+
payoutCurrency: 'USD',
|
|
913
|
+
active: true,
|
|
914
|
+
});
|
|
915
|
+
|
|
916
|
+
// Update an affiliate program
|
|
917
|
+
const { affiliateProgram } = await client.affiliatePrograms.update('program_123', {
|
|
918
|
+
commissionValue: 25,
|
|
919
|
+
});
|
|
920
|
+
|
|
921
|
+
// Delete an affiliate program
|
|
922
|
+
await client.affiliatePrograms.del('program_123');
|
|
223
923
|
```
|
|
224
924
|
|
|
225
|
-
###
|
|
925
|
+
### Affiliate Commissions
|
|
226
926
|
|
|
227
927
|
```typescript
|
|
228
|
-
//
|
|
229
|
-
const {
|
|
230
|
-
|
|
928
|
+
// List commissions
|
|
929
|
+
const { commissions, hasNextPage } = await client.affiliateCommissions.list({
|
|
930
|
+
affiliateId: 'affiliate_123',
|
|
931
|
+
status: 'pending', // 'pending' | 'approved' | 'paid' | 'rejected'
|
|
932
|
+
});
|
|
231
933
|
|
|
232
|
-
//
|
|
233
|
-
const {
|
|
934
|
+
// Retrieve a commission
|
|
935
|
+
const { commission } = await client.affiliateCommissions.retrieve('commission_123');
|
|
936
|
+
|
|
937
|
+
// Update a commission
|
|
938
|
+
const { commission } = await client.affiliateCommissions.update('commission_123', {
|
|
939
|
+
status: 'approved',
|
|
940
|
+
});
|
|
941
|
+
```
|
|
942
|
+
|
|
943
|
+
### Affiliate Payouts
|
|
944
|
+
|
|
945
|
+
```typescript
|
|
946
|
+
// List payouts
|
|
947
|
+
const { payouts, hasNextPage } = await client.affiliatePayouts.list({
|
|
948
|
+
affiliateId: 'affiliate_123',
|
|
949
|
+
status: 'completed', // 'pending' | 'processing' | 'completed' | 'failed'
|
|
950
|
+
});
|
|
951
|
+
|
|
952
|
+
// Retrieve a payout
|
|
953
|
+
const { payout } = await client.affiliatePayouts.retrieve('payout_123');
|
|
954
|
+
|
|
955
|
+
// Create a payout
|
|
956
|
+
const { payout } = await client.affiliatePayouts.create({
|
|
957
|
+
affiliateId: 'affiliate_123',
|
|
958
|
+
amount: 10000, // $100.00
|
|
959
|
+
currencyCode: 'USD',
|
|
960
|
+
});
|
|
961
|
+
```
|
|
962
|
+
|
|
963
|
+
### Affiliate Referrals
|
|
964
|
+
|
|
965
|
+
```typescript
|
|
966
|
+
// List referrals
|
|
967
|
+
const { referrals, hasNextPage } = await client.affiliateReferrals.list({
|
|
968
|
+
affiliateId: 'affiliate_123',
|
|
969
|
+
status: 'converted', // 'pending' | 'converted' | 'expired'
|
|
970
|
+
});
|
|
971
|
+
|
|
972
|
+
// Retrieve a referral
|
|
973
|
+
const { referral } = await client.affiliateReferrals.retrieve('referral_123');
|
|
974
|
+
```
|
|
975
|
+
|
|
976
|
+
### Companies
|
|
977
|
+
|
|
978
|
+
```typescript
|
|
979
|
+
// List companies
|
|
980
|
+
const { companies, hasNextPage } = await client.companies.list({
|
|
981
|
+
take: 25,
|
|
982
|
+
search: 'acme',
|
|
983
|
+
});
|
|
984
|
+
|
|
985
|
+
// Retrieve a company
|
|
986
|
+
const { company } = await client.companies.retrieve('company_123');
|
|
234
987
|
|
|
235
|
-
//
|
|
236
|
-
const {
|
|
988
|
+
// Create a company
|
|
989
|
+
const { company } = await client.companies.create({
|
|
990
|
+
name: 'Acme Holdings',
|
|
991
|
+
domain: 'acme.com',
|
|
992
|
+
});
|
|
993
|
+
|
|
994
|
+
// Update a company
|
|
995
|
+
const { company } = await client.companies.update('company_123', {
|
|
996
|
+
name: 'Acme Holdings Inc',
|
|
997
|
+
});
|
|
237
998
|
|
|
238
|
-
//
|
|
999
|
+
// Delete a company
|
|
1000
|
+
await client.companies.del('company_123');
|
|
1001
|
+
```
|
|
1002
|
+
|
|
1003
|
+
### Customer Segments
|
|
1004
|
+
|
|
1005
|
+
```typescript
|
|
1006
|
+
// List customer segments
|
|
239
1007
|
const { customerSegments } = await client.customerSegments.list();
|
|
240
1008
|
|
|
241
|
-
//
|
|
242
|
-
const {
|
|
1009
|
+
// Retrieve a segment
|
|
1010
|
+
const { customerSegment } = await client.customerSegments.retrieve('segment_123');
|
|
1011
|
+
|
|
1012
|
+
// Create a segment
|
|
1013
|
+
const { customerSegment } = await client.customerSegments.create({
|
|
1014
|
+
name: 'Enterprise Customers',
|
|
1015
|
+
filters: { lifetimeValue: { gte: 10000 } },
|
|
1016
|
+
});
|
|
1017
|
+
|
|
1018
|
+
// Update a segment
|
|
1019
|
+
const { customerSegment } = await client.customerSegments.update('segment_123', {
|
|
1020
|
+
name: 'Enterprise Customers (Updated)',
|
|
1021
|
+
});
|
|
1022
|
+
|
|
1023
|
+
// Delete a segment
|
|
1024
|
+
await client.customerSegments.del('segment_123');
|
|
1025
|
+
```
|
|
1026
|
+
|
|
1027
|
+
### Tasks
|
|
243
1028
|
|
|
244
|
-
|
|
1029
|
+
```typescript
|
|
1030
|
+
// List tasks
|
|
1031
|
+
const { tasks, hasNextPage } = await client.tasks.list({
|
|
1032
|
+
status: 'pending',
|
|
1033
|
+
assignedToId: 'user_123',
|
|
1034
|
+
customerId: 'cust_123',
|
|
1035
|
+
});
|
|
1036
|
+
|
|
1037
|
+
// Retrieve a task
|
|
1038
|
+
const { task } = await client.tasks.retrieve('task_123');
|
|
1039
|
+
|
|
1040
|
+
// Create a task
|
|
1041
|
+
const { task } = await client.tasks.create({
|
|
1042
|
+
title: 'Follow up with customer',
|
|
1043
|
+
description: 'Discuss renewal options',
|
|
1044
|
+
dueAt: '2024-02-15T10:00:00Z',
|
|
1045
|
+
assignedToId: 'user_123',
|
|
1046
|
+
customerId: 'cust_123',
|
|
1047
|
+
});
|
|
1048
|
+
|
|
1049
|
+
// Update a task
|
|
1050
|
+
const { task } = await client.tasks.update('task_123', {
|
|
1051
|
+
status: 'completed',
|
|
1052
|
+
});
|
|
1053
|
+
|
|
1054
|
+
// Delete a task
|
|
1055
|
+
await client.tasks.del('task_123');
|
|
1056
|
+
```
|
|
1057
|
+
|
|
1058
|
+
### Flows (Automation)
|
|
1059
|
+
|
|
1060
|
+
```typescript
|
|
1061
|
+
// List flows
|
|
245
1062
|
const { flows } = await client.flows.list();
|
|
246
1063
|
|
|
247
|
-
//
|
|
248
|
-
const {
|
|
249
|
-
|
|
1064
|
+
// Retrieve a flow
|
|
1065
|
+
const { flow } = await client.flows.retrieve('flow_123');
|
|
1066
|
+
|
|
1067
|
+
// Create a flow
|
|
1068
|
+
const { flow } = await client.flows.create({
|
|
1069
|
+
name: 'Onboarding Flow',
|
|
1070
|
+
trigger: 'customer.created',
|
|
1071
|
+
actions: [
|
|
1072
|
+
{ type: 'email', template: 'welcome' },
|
|
1073
|
+
],
|
|
1074
|
+
});
|
|
250
1075
|
|
|
251
|
-
//
|
|
1076
|
+
// Update a flow
|
|
1077
|
+
const { flow } = await client.flows.update('flow_123', {
|
|
1078
|
+
name: 'Updated Onboarding Flow',
|
|
1079
|
+
enabled: true,
|
|
1080
|
+
});
|
|
1081
|
+
|
|
1082
|
+
// Delete a flow
|
|
1083
|
+
await client.flows.del('flow_123');
|
|
1084
|
+
```
|
|
1085
|
+
|
|
1086
|
+
### Transactions & Charges
|
|
1087
|
+
|
|
1088
|
+
```typescript
|
|
1089
|
+
// List transactions
|
|
1090
|
+
const { transactions, hasNextPage } = await client.transactions.list({
|
|
1091
|
+
customerId: 'cust_123',
|
|
1092
|
+
appId: 'app_123',
|
|
1093
|
+
});
|
|
1094
|
+
|
|
1095
|
+
// Retrieve a transaction
|
|
1096
|
+
const { transaction } = await client.transactions.retrieve('txn_123');
|
|
1097
|
+
|
|
1098
|
+
// List charges
|
|
1099
|
+
const { charges, hasNextPage } = await client.charges.list({
|
|
1100
|
+
customerId: 'cust_123',
|
|
1101
|
+
appId: 'app_123',
|
|
1102
|
+
});
|
|
1103
|
+
|
|
1104
|
+
// Retrieve a charge
|
|
1105
|
+
const { charge } = await client.charges.retrieve('charge_123');
|
|
1106
|
+
```
|
|
1107
|
+
|
|
1108
|
+
### Users
|
|
1109
|
+
|
|
1110
|
+
```typescript
|
|
1111
|
+
// List users in the organization
|
|
1112
|
+
const { users } = await client.users.list();
|
|
1113
|
+
|
|
1114
|
+
// Retrieve a user
|
|
1115
|
+
const { user } = await client.users.retrieve('user_123');
|
|
1116
|
+
```
|
|
1117
|
+
|
|
1118
|
+
### Me & Organization
|
|
1119
|
+
|
|
1120
|
+
```typescript
|
|
1121
|
+
// Get current user and organization
|
|
1122
|
+
const { user, organization } = await client.me.retrieve();
|
|
1123
|
+
|
|
1124
|
+
// Get organization details
|
|
1125
|
+
const { organization } = await client.organization.retrieve();
|
|
1126
|
+
```
|
|
1127
|
+
|
|
1128
|
+
### Documentation
|
|
1129
|
+
|
|
1130
|
+
```typescript
|
|
1131
|
+
// List documentation collections
|
|
252
1132
|
const { collections } = await client.docs.listCollections();
|
|
253
|
-
|
|
1133
|
+
|
|
1134
|
+
// Retrieve a collection
|
|
1135
|
+
const { collection } = await client.docs.retrieveCollection('collection_123');
|
|
1136
|
+
|
|
1137
|
+
// List documentation pages
|
|
1138
|
+
const { pages } = await client.docs.listPages({
|
|
1139
|
+
collectionId: 'collection_123',
|
|
1140
|
+
});
|
|
1141
|
+
|
|
1142
|
+
// Retrieve a page
|
|
1143
|
+
const { page } = await client.docs.retrievePage('page_123');
|
|
1144
|
+
|
|
1145
|
+
// Create a page
|
|
1146
|
+
const { page } = await client.docs.createPage({
|
|
1147
|
+
title: 'Getting Started',
|
|
1148
|
+
content: '# Getting Started\n\nWelcome to our docs...',
|
|
1149
|
+
collectionId: 'collection_123',
|
|
1150
|
+
});
|
|
1151
|
+
|
|
1152
|
+
// Update a page
|
|
1153
|
+
const { page } = await client.docs.updatePage('page_123', {
|
|
1154
|
+
content: 'Updated content',
|
|
1155
|
+
});
|
|
1156
|
+
|
|
1157
|
+
// Delete a page
|
|
1158
|
+
await client.docs.deletePage('page_123');
|
|
1159
|
+
```
|
|
1160
|
+
|
|
1161
|
+
### Entities
|
|
1162
|
+
|
|
1163
|
+
Generic entity management:
|
|
1164
|
+
|
|
1165
|
+
```typescript
|
|
1166
|
+
// List entities
|
|
1167
|
+
const { entities } = await client.entities.list({
|
|
1168
|
+
type: 'custom_entity',
|
|
1169
|
+
});
|
|
1170
|
+
|
|
1171
|
+
// Retrieve an entity
|
|
1172
|
+
const { entity } = await client.entities.retrieve('entity_123');
|
|
1173
|
+
|
|
1174
|
+
// Create an entity
|
|
1175
|
+
const { entity } = await client.entities.create({
|
|
1176
|
+
type: 'custom_entity',
|
|
1177
|
+
data: { field1: 'value1' },
|
|
1178
|
+
});
|
|
1179
|
+
|
|
1180
|
+
// Update an entity
|
|
1181
|
+
const { entity } = await client.entities.update('entity_123', {
|
|
1182
|
+
data: { field1: 'updated_value' },
|
|
1183
|
+
});
|
|
1184
|
+
|
|
1185
|
+
// Delete an entity
|
|
1186
|
+
await client.entities.del('entity_123');
|
|
254
1187
|
```
|
|
255
1188
|
|
|
256
1189
|
## Pagination
|
|
@@ -261,10 +1194,13 @@ All list methods return pagination metadata:
|
|
|
261
1194
|
const { customers, hasNextPage, hasPreviousPage, cursor, total } =
|
|
262
1195
|
await client.customers.list({ take: 25 });
|
|
263
1196
|
|
|
264
|
-
//
|
|
1197
|
+
// Cursor-based pagination (recommended)
|
|
265
1198
|
if (hasNextPage) {
|
|
266
1199
|
const nextPage = await client.customers.list({ take: 25, cursor });
|
|
267
1200
|
}
|
|
1201
|
+
|
|
1202
|
+
// Offset-based pagination
|
|
1203
|
+
const page2 = await client.customers.list({ take: 25, page: 1 });
|
|
268
1204
|
```
|
|
269
1205
|
|
|
270
1206
|
## Error Handling
|
|
@@ -283,17 +1219,19 @@ try {
|
|
|
283
1219
|
} catch (error) {
|
|
284
1220
|
if (error instanceof MantleAuthenticationError) {
|
|
285
1221
|
// Handle authentication error (401)
|
|
1222
|
+
console.log('Please re-authenticate');
|
|
286
1223
|
} else if (error instanceof MantlePermissionError) {
|
|
287
1224
|
// Handle permission error (403)
|
|
1225
|
+
console.log('Access denied');
|
|
288
1226
|
} else if (error instanceof MantleValidationError) {
|
|
289
1227
|
// Handle validation error (422)
|
|
290
|
-
console.log(error.details);
|
|
1228
|
+
console.log('Validation failed:', error.details);
|
|
291
1229
|
} else if (error instanceof MantleRateLimitError) {
|
|
292
1230
|
// Handle rate limit (429)
|
|
293
|
-
console.log(`Retry after: ${error.retryAfter}s`);
|
|
1231
|
+
console.log(`Rate limited. Retry after: ${error.retryAfter}s`);
|
|
294
1232
|
} else if (error instanceof MantleAPIError) {
|
|
295
1233
|
// Handle other API errors
|
|
296
|
-
console.log(error.statusCode
|
|
1234
|
+
console.log(`Error ${error.statusCode}: ${error.message}`);
|
|
297
1235
|
}
|
|
298
1236
|
}
|
|
299
1237
|
```
|
|
@@ -304,28 +1242,85 @@ All types are exported for use in your application:
|
|
|
304
1242
|
|
|
305
1243
|
```typescript
|
|
306
1244
|
import type {
|
|
1245
|
+
// Client config
|
|
1246
|
+
MantleCoreClientConfig,
|
|
1247
|
+
|
|
1248
|
+
// Entities
|
|
307
1249
|
Customer,
|
|
308
|
-
|
|
1250
|
+
Contact,
|
|
309
1251
|
Deal,
|
|
310
1252
|
Subscription,
|
|
1253
|
+
Ticket,
|
|
1254
|
+
TicketMessage,
|
|
1255
|
+
App,
|
|
1256
|
+
Plan,
|
|
1257
|
+
Feature,
|
|
1258
|
+
Affiliate,
|
|
1259
|
+
AffiliateProgram,
|
|
1260
|
+
AffiliateCommission,
|
|
1261
|
+
AffiliatePayout,
|
|
1262
|
+
AffiliateReferral,
|
|
1263
|
+
|
|
1264
|
+
// Params
|
|
1265
|
+
CustomerCreateParams,
|
|
1266
|
+
CustomerUpdateParams,
|
|
1267
|
+
CustomerListParams,
|
|
1268
|
+
DealCreateParams,
|
|
1269
|
+
DealCustomerInput,
|
|
1270
|
+
DealContactInput,
|
|
1271
|
+
TicketCreateParams,
|
|
1272
|
+
PlanCreateParams,
|
|
1273
|
+
|
|
1274
|
+
// Responses
|
|
1275
|
+
CustomerListResponse,
|
|
1276
|
+
DealListResponse,
|
|
311
1277
|
MetricsResponse,
|
|
312
|
-
|
|
1278
|
+
PaginatedResponse,
|
|
1279
|
+
|
|
1280
|
+
// Enums/Types
|
|
1281
|
+
DateRangeType,
|
|
1282
|
+
MetricType,
|
|
1283
|
+
SocialProfileType,
|
|
1284
|
+
|
|
1285
|
+
// Middleware
|
|
1286
|
+
Middleware,
|
|
1287
|
+
MiddlewareContext,
|
|
1288
|
+
MiddlewareOptions,
|
|
313
1289
|
} from '@heymantle/core-api-client';
|
|
314
1290
|
```
|
|
315
1291
|
|
|
316
1292
|
## Configuration Options
|
|
317
1293
|
|
|
318
1294
|
```typescript
|
|
1295
|
+
import { MantleCoreClient, type Middleware } from '@heymantle/core-api-client';
|
|
1296
|
+
|
|
319
1297
|
const client = new MantleCoreClient({
|
|
320
1298
|
// Required: one of apiKey or accessToken
|
|
321
1299
|
apiKey: 'your-api-key',
|
|
1300
|
+
// OR
|
|
1301
|
+
accessToken: 'your-oauth-token',
|
|
322
1302
|
|
|
323
1303
|
// Optional: custom base URL (defaults to https://api.heymantle.com/v1)
|
|
324
1304
|
baseURL: 'https://api.heymantle.com/v1',
|
|
325
1305
|
|
|
326
1306
|
// Optional: request timeout in ms (defaults to 30000)
|
|
327
1307
|
timeout: 30000,
|
|
1308
|
+
|
|
1309
|
+
// Optional: middleware to register on instantiation
|
|
1310
|
+
middleware: [
|
|
1311
|
+
loggingMiddleware,
|
|
1312
|
+
[authRefreshMiddleware, { name: 'auth', priority: 1 }],
|
|
1313
|
+
],
|
|
328
1314
|
});
|
|
1315
|
+
|
|
1316
|
+
// Update authentication at runtime
|
|
1317
|
+
client.updateAuth({ accessToken: 'new-token' });
|
|
1318
|
+
|
|
1319
|
+
// Add middleware at runtime
|
|
1320
|
+
client.use(newMiddleware, { name: 'custom', priority: 50 });
|
|
1321
|
+
|
|
1322
|
+
// Remove middleware by name
|
|
1323
|
+
client.removeMiddleware('custom');
|
|
329
1324
|
```
|
|
330
1325
|
|
|
331
1326
|
## License
|
package/dist/index.d.mts
CHANGED
|
@@ -339,7 +339,7 @@ interface CustomFieldUpdateParams extends Partial<Omit<CustomFieldCreateParams,
|
|
|
339
339
|
/**
|
|
340
340
|
* Valid social profile types
|
|
341
341
|
*/
|
|
342
|
-
type SocialProfileType =
|
|
342
|
+
type SocialProfileType = "linkedin" | "x" | "facebook" | "instagram" | "website";
|
|
343
343
|
/**
|
|
344
344
|
* Social profile for a contact
|
|
345
345
|
*/
|
|
@@ -391,7 +391,10 @@ interface ContactCreateParams {
|
|
|
391
391
|
jobTitle?: string;
|
|
392
392
|
notes?: string;
|
|
393
393
|
tags?: string[];
|
|
394
|
-
customers?: string[]
|
|
394
|
+
customers?: string[] | Array<{
|
|
395
|
+
id: string;
|
|
396
|
+
name?: string;
|
|
397
|
+
}>;
|
|
395
398
|
socialProfiles?: SocialProfile[];
|
|
396
399
|
}
|
|
397
400
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -339,7 +339,7 @@ interface CustomFieldUpdateParams extends Partial<Omit<CustomFieldCreateParams,
|
|
|
339
339
|
/**
|
|
340
340
|
* Valid social profile types
|
|
341
341
|
*/
|
|
342
|
-
type SocialProfileType =
|
|
342
|
+
type SocialProfileType = "linkedin" | "x" | "facebook" | "instagram" | "website";
|
|
343
343
|
/**
|
|
344
344
|
* Social profile for a contact
|
|
345
345
|
*/
|
|
@@ -391,7 +391,10 @@ interface ContactCreateParams {
|
|
|
391
391
|
jobTitle?: string;
|
|
392
392
|
notes?: string;
|
|
393
393
|
tags?: string[];
|
|
394
|
-
customers?: string[]
|
|
394
|
+
customers?: string[] | Array<{
|
|
395
|
+
id: string;
|
|
396
|
+
name?: string;
|
|
397
|
+
}>;
|
|
395
398
|
socialProfiles?: SocialProfile[];
|
|
396
399
|
}
|
|
397
400
|
/**
|