@heymantle/core-api-client 0.2.0 → 0.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 +92 -1752
- package/dist/index.d.mts +12907 -10579
- package/dist/index.d.ts +12907 -10579
- package/dist/index.js +604 -752
- package/dist/index.mjs +604 -752
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -16,1590 +16,161 @@ import { MantleCoreClient } from '@heymantle/core-api-client';
|
|
|
16
16
|
const client = new MantleCoreClient({
|
|
17
17
|
apiKey: 'your-api-key',
|
|
18
18
|
});
|
|
19
|
-
|
|
20
|
-
// List customers
|
|
21
|
-
const { customers, hasNextPage } = await client.customers.list({ take: 25 });
|
|
22
|
-
|
|
23
|
-
// Get a specific customer
|
|
24
|
-
const { customer } = await client.customers.retrieve('cust_123');
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
## Authentication
|
|
28
|
-
|
|
29
|
-
The client supports two authentication methods:
|
|
30
|
-
|
|
31
|
-
```typescript
|
|
32
|
-
// API Key (for server-side use)
|
|
33
|
-
const client = new MantleCoreClient({
|
|
34
|
-
apiKey: 'your-api-key',
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
// OAuth Access Token
|
|
38
|
-
const client = new MantleCoreClient({
|
|
39
|
-
accessToken: 'your-oauth-token',
|
|
40
|
-
});
|
|
41
|
-
```
|
|
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
|
-
|
|
137
|
-
## Resources
|
|
138
|
-
|
|
139
|
-
### Customers
|
|
140
|
-
|
|
141
|
-
```typescript
|
|
142
|
-
// List customers with filters
|
|
143
|
-
const { customers, hasNextPage, total } = await client.customers.list({
|
|
144
|
-
take: 25,
|
|
145
|
-
search: 'acme',
|
|
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,
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
// Create a customer
|
|
162
|
-
const { customer } = await client.customers.create({
|
|
163
|
-
name: 'Acme Inc',
|
|
164
|
-
email: 'contact@acme.com',
|
|
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
|
-
],
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
// Update a customer
|
|
180
|
-
const { customer } = await client.customers.update('cust_123', {
|
|
181
|
-
name: 'Acme Corporation',
|
|
182
|
-
tags: ['enterprise', 'vip'],
|
|
183
|
-
});
|
|
184
|
-
|
|
185
|
-
// Add/remove tags
|
|
186
|
-
await client.customers.addTags('cust_123', ['premium', 'partner']);
|
|
187
|
-
await client.customers.removeTags('cust_123', ['trial']);
|
|
188
|
-
|
|
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');
|
|
223
|
-
```
|
|
224
|
-
|
|
225
|
-
### Contacts
|
|
226
|
-
|
|
227
|
-
```typescript
|
|
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 or update a contact (upsert by email)
|
|
237
|
-
// If a contact with the same email exists, it will be updated
|
|
238
|
-
const { contact, created } = await client.contacts.create({
|
|
239
|
-
name: 'John Doe',
|
|
240
|
-
email: 'john@acme.com',
|
|
241
|
-
phone: '+1-555-123-4567',
|
|
242
|
-
jobTitle: 'CTO',
|
|
243
|
-
notes: 'Primary technical contact',
|
|
244
|
-
tags: ['decision-maker', 'technical'],
|
|
245
|
-
customers: ['cust_123', 'cust_456'],
|
|
246
|
-
socialProfiles: [
|
|
247
|
-
{ key: 'linkedin', value: 'https://linkedin.com/in/johndoe' },
|
|
248
|
-
{ key: 'x', value: 'https://x.com/johndoe' },
|
|
249
|
-
{ key: 'website', value: 'https://johndoe.com' },
|
|
250
|
-
],
|
|
251
|
-
});
|
|
252
|
-
console.log(created ? 'New contact created' : 'Existing contact updated');
|
|
253
|
-
|
|
254
|
-
// Update a contact
|
|
255
|
-
const { contact } = await client.contacts.update('contact_123', {
|
|
256
|
-
jobTitle: 'VP of Engineering',
|
|
257
|
-
socialProfiles: [
|
|
258
|
-
{ key: 'linkedin', value: 'https://linkedin.com/in/johndoe-updated' },
|
|
259
|
-
],
|
|
260
|
-
});
|
|
261
|
-
|
|
262
|
-
// Retrieve a contact
|
|
263
|
-
const { contact } = await client.contacts.retrieve('contact_123');
|
|
264
|
-
|
|
265
|
-
// Delete a contact
|
|
266
|
-
await client.contacts.del('contact_123');
|
|
267
|
-
|
|
268
|
-
// Add/remove tags
|
|
269
|
-
await client.contacts.addTags('contact_123', ['vip', 'decision-maker']);
|
|
270
|
-
await client.contacts.removeTags('contact_123', ['trial']);
|
|
271
|
-
```
|
|
272
|
-
|
|
273
|
-
### Subscriptions
|
|
274
|
-
|
|
275
|
-
```typescript
|
|
276
|
-
// List subscriptions
|
|
277
|
-
const { subscriptions, hasNextPage } = await client.subscriptions.list({
|
|
278
|
-
appId: 'app_123',
|
|
279
|
-
customerId: 'cust_123',
|
|
280
|
-
active: true,
|
|
281
|
-
ids: ['sub_123', 'sub_456'],
|
|
282
|
-
startDate: '2024-01-01',
|
|
283
|
-
endDate: '2024-12-31',
|
|
284
|
-
});
|
|
285
|
-
|
|
286
|
-
// Retrieve a subscription
|
|
287
|
-
const { subscription } = await client.subscriptions.retrieve('sub_123');
|
|
288
|
-
```
|
|
289
|
-
|
|
290
|
-
### Deals
|
|
291
|
-
|
|
292
|
-
Deals support multiple ways to link customers and contacts:
|
|
293
|
-
|
|
294
|
-
```typescript
|
|
295
|
-
// List deals with filters
|
|
296
|
-
const { deals, hasNextPage, total } = await client.deals.list({
|
|
297
|
-
customerId: 'cust_123',
|
|
298
|
-
appId: 'app_123',
|
|
299
|
-
planId: 'plan_123',
|
|
300
|
-
dealStageId: 'stage_123',
|
|
301
|
-
dealFlowId: 'flow_123',
|
|
302
|
-
affiliateId: 'aff_123',
|
|
303
|
-
partnershipId: 'partner_123',
|
|
304
|
-
acquirerId: 'user_123',
|
|
305
|
-
ownerId: 'user_456',
|
|
306
|
-
contactId: 'contact_123',
|
|
307
|
-
stage: 'negotiation',
|
|
308
|
-
minAmount: 1000,
|
|
309
|
-
maxAmount: 50000,
|
|
310
|
-
acquisitionChannel: 'inbound',
|
|
311
|
-
acquisitionSource: 'website',
|
|
312
|
-
includeArchived: false,
|
|
313
|
-
});
|
|
314
|
-
|
|
315
|
-
// Create a deal - Option 1: Link existing customer
|
|
316
|
-
const { deal } = await client.deals.create({
|
|
317
|
-
name: 'Enterprise Deal',
|
|
318
|
-
amount: 50000,
|
|
319
|
-
amountCurrencyCode: 'USD',
|
|
320
|
-
customerId: 'cust_123',
|
|
321
|
-
contactIds: ['contact_123', 'contact_456'],
|
|
322
|
-
dealFlowId: 'flow_123',
|
|
323
|
-
dealStageId: 'stage_123',
|
|
324
|
-
appId: 'app_123',
|
|
325
|
-
planId: 'plan_456',
|
|
326
|
-
ownerIds: ['user_123'],
|
|
327
|
-
acquisitionChannel: 'outbound',
|
|
328
|
-
acquisitionSource: 'sales_call',
|
|
329
|
-
firstInteractionAt: '2024-01-15T10:00:00Z',
|
|
330
|
-
closingAt: '2024-03-01T00:00:00Z',
|
|
331
|
-
notes: 'High priority enterprise deal',
|
|
332
|
-
});
|
|
333
|
-
|
|
334
|
-
// Create a deal - Option 2: Create/update customer inline
|
|
335
|
-
const { deal } = await client.deals.create({
|
|
336
|
-
name: 'New Prospect Deal',
|
|
337
|
-
amount: 25000,
|
|
338
|
-
// Customer will be matched by domain or created if not found
|
|
339
|
-
customer: {
|
|
340
|
-
name: 'Acme Corp',
|
|
341
|
-
email: 'info@acme.com',
|
|
342
|
-
domain: 'acme.com',
|
|
343
|
-
shopifyDomain: 'acme.myshopify.com',
|
|
344
|
-
shopifyShopId: '12345',
|
|
345
|
-
tags: ['prospect'],
|
|
346
|
-
countryCode: 'US',
|
|
347
|
-
preferredCurrency: 'USD',
|
|
348
|
-
},
|
|
349
|
-
// Contacts will be matched by email or created if not found
|
|
350
|
-
contacts: [
|
|
351
|
-
{
|
|
352
|
-
email: 'john@acme.com',
|
|
353
|
-
name: 'John Doe',
|
|
354
|
-
phone: '+1-555-123-4567',
|
|
355
|
-
jobTitle: 'CEO',
|
|
356
|
-
label: 'primary',
|
|
357
|
-
notes: 'Decision maker',
|
|
358
|
-
tags: ['executive'],
|
|
359
|
-
},
|
|
360
|
-
{
|
|
361
|
-
email: 'jane@acme.com',
|
|
362
|
-
name: 'Jane Smith',
|
|
363
|
-
jobTitle: 'CTO',
|
|
364
|
-
label: 'technical',
|
|
365
|
-
},
|
|
366
|
-
],
|
|
367
|
-
dealFlowId: 'flow_123',
|
|
368
|
-
dealStageId: 'stage_123',
|
|
369
|
-
});
|
|
370
|
-
|
|
371
|
-
// Create a deal - Option 3: Find/create customer by domain
|
|
372
|
-
const { deal } = await client.deals.create({
|
|
373
|
-
name: 'Domain-based Deal',
|
|
374
|
-
shopifyDomain: 'newstore.myshopify.com',
|
|
375
|
-
dealFlowId: 'flow_123',
|
|
376
|
-
dealStageId: 'stage_123',
|
|
377
|
-
});
|
|
378
|
-
|
|
379
|
-
// Update a deal
|
|
380
|
-
const { deal } = await client.deals.update('deal_123', {
|
|
381
|
-
amount: 75000,
|
|
382
|
-
dealStageId: 'stage_456',
|
|
383
|
-
closedAt: '2024-02-15T00:00:00Z',
|
|
384
|
-
notes: 'Deal closed successfully!',
|
|
385
|
-
});
|
|
386
|
-
|
|
387
|
-
// Archive a deal
|
|
388
|
-
await client.deals.del('deal_123');
|
|
389
|
-
|
|
390
|
-
// Get deal timeline
|
|
391
|
-
const { events } = await client.deals.timeline('deal_123');
|
|
392
|
-
|
|
393
|
-
// Get deal events
|
|
394
|
-
const { events } = await client.deals.listEvents('deal_123');
|
|
395
|
-
|
|
396
|
-
// Create a deal event
|
|
397
|
-
const { event } = await client.deals.createEvent('deal_123', {
|
|
398
|
-
type: 'note',
|
|
399
|
-
description: 'Called the customer to discuss pricing',
|
|
400
|
-
});
|
|
401
|
-
```
|
|
402
|
-
|
|
403
|
-
### Deal Flows
|
|
404
|
-
|
|
405
|
-
Manage deal pipelines and stages:
|
|
406
|
-
|
|
407
|
-
```typescript
|
|
408
|
-
// List deal flows
|
|
409
|
-
const { dealFlows } = await client.dealFlows.list();
|
|
410
|
-
|
|
411
|
-
// Retrieve a deal flow with stages
|
|
412
|
-
const { dealFlow } = await client.dealFlows.retrieve('flow_123');
|
|
413
|
-
// dealFlow.stages contains the ordered stages
|
|
414
|
-
|
|
415
|
-
// Create a deal flow
|
|
416
|
-
const { dealFlow } = await client.dealFlows.create({
|
|
417
|
-
name: 'Enterprise Sales Pipeline',
|
|
418
|
-
description: 'For deals over $10k',
|
|
419
|
-
});
|
|
420
|
-
|
|
421
|
-
// Update a deal flow
|
|
422
|
-
const { dealFlow } = await client.dealFlows.update('flow_123', {
|
|
423
|
-
name: 'Enterprise Sales Pipeline v2',
|
|
424
|
-
});
|
|
425
|
-
|
|
426
|
-
// Delete a deal flow
|
|
427
|
-
await client.dealFlows.del('flow_123');
|
|
428
|
-
```
|
|
429
|
-
|
|
430
|
-
### Deal Activities
|
|
431
|
-
|
|
432
|
-
Track activities within deal flows:
|
|
433
|
-
|
|
434
|
-
```typescript
|
|
435
|
-
// List deal activities
|
|
436
|
-
const { dealActivities } = await client.dealActivities.list();
|
|
437
|
-
|
|
438
|
-
// Retrieve a deal activity
|
|
439
|
-
const { dealActivity } = await client.dealActivities.retrieve('activity_123');
|
|
440
|
-
|
|
441
|
-
// Create a deal activity
|
|
442
|
-
const { dealActivity } = await client.dealActivities.create({
|
|
443
|
-
name: 'Initial Call',
|
|
444
|
-
dealFlowId: 'flow_123',
|
|
445
|
-
description: 'First discovery call with prospect',
|
|
446
|
-
order: 1,
|
|
447
|
-
});
|
|
448
|
-
|
|
449
|
-
// Update a deal activity
|
|
450
|
-
const { dealActivity } = await client.dealActivities.update('activity_123', {
|
|
451
|
-
name: 'Discovery Call',
|
|
452
|
-
description: 'Updated description',
|
|
453
|
-
});
|
|
454
|
-
|
|
455
|
-
// Delete a deal activity
|
|
456
|
-
await client.dealActivities.del('activity_123');
|
|
457
|
-
```
|
|
458
|
-
|
|
459
|
-
### Apps
|
|
460
|
-
|
|
461
|
-
```typescript
|
|
462
|
-
// List apps
|
|
463
|
-
const { apps } = await client.apps.list({
|
|
464
|
-
minUpdatedAt: '2024-01-01T00:00:00Z',
|
|
465
|
-
maxUpdatedAt: '2024-12-31T23:59:59Z',
|
|
466
|
-
});
|
|
467
|
-
|
|
468
|
-
// Retrieve an app
|
|
469
|
-
const { app } = await client.apps.retrieve('app_123');
|
|
470
|
-
```
|
|
471
|
-
|
|
472
|
-
### Plans
|
|
473
|
-
|
|
474
|
-
```typescript
|
|
475
|
-
// List plans for an app
|
|
476
|
-
const { plans, total, hasMore } = await client.apps.listPlans('app_123', {
|
|
477
|
-
public: true,
|
|
478
|
-
page: 0,
|
|
479
|
-
perPage: 25,
|
|
480
|
-
search: 'pro',
|
|
481
|
-
});
|
|
482
|
-
|
|
483
|
-
// Retrieve a plan
|
|
484
|
-
const { plan } = await client.apps.retrievePlan('app_123', 'plan_123');
|
|
485
|
-
|
|
486
|
-
// Create a plan with usage charges and features
|
|
487
|
-
const { plan } = await client.apps.createPlan('app_123', {
|
|
488
|
-
name: 'Pro Plan',
|
|
489
|
-
description: 'For growing businesses',
|
|
490
|
-
amount: 4900, // $49.00
|
|
491
|
-
currencyCode: 'USD',
|
|
492
|
-
interval: 'month', // 'month' | 'year' | 'one_time'
|
|
493
|
-
trialDays: 14,
|
|
494
|
-
public: true,
|
|
495
|
-
visible: true,
|
|
496
|
-
customerTags: ['premium'],
|
|
497
|
-
customerExcludeTags: ['churned'],
|
|
498
|
-
shopifyPlans: ['shopify', 'advanced'],
|
|
499
|
-
flexBilling: true,
|
|
500
|
-
flexBillingTerms: 'Charged at end of billing period',
|
|
501
|
-
// Usage-based pricing
|
|
502
|
-
planUsageCharges: [
|
|
503
|
-
{
|
|
504
|
-
usageMetricId: 'metric_123',
|
|
505
|
-
cappedAmount: 10000, // $100 cap
|
|
506
|
-
terms: '$0.01 per API call',
|
|
507
|
-
interval: 'month',
|
|
508
|
-
},
|
|
509
|
-
],
|
|
510
|
-
// Feature flags
|
|
511
|
-
features: [
|
|
512
|
-
{ featureId: 'feature_api', value: true },
|
|
513
|
-
{ featureId: 'feature_seats', value: 10 },
|
|
514
|
-
],
|
|
515
|
-
customFields: { tier: 'mid' },
|
|
516
|
-
});
|
|
517
|
-
|
|
518
|
-
// Update a plan
|
|
519
|
-
const { plan } = await client.apps.updatePlan('app_123', 'plan_123', {
|
|
520
|
-
amount: 5900,
|
|
521
|
-
description: 'Updated description',
|
|
522
|
-
});
|
|
523
|
-
|
|
524
|
-
// Archive/unarchive a plan
|
|
525
|
-
await client.apps.archivePlan('app_123', 'plan_123');
|
|
526
|
-
await client.apps.unarchivePlan('app_123', 'plan_123');
|
|
527
|
-
```
|
|
528
|
-
|
|
529
|
-
### Features
|
|
530
|
-
|
|
531
|
-
```typescript
|
|
532
|
-
// List features
|
|
533
|
-
const { features } = await client.apps.listFeatures('app_123');
|
|
534
|
-
|
|
535
|
-
// Retrieve a feature
|
|
536
|
-
const { feature } = await client.apps.retrieveFeature('app_123', 'feature_123');
|
|
537
|
-
|
|
538
|
-
// Create a feature
|
|
539
|
-
const { feature } = await client.apps.createFeature('app_123', {
|
|
540
|
-
name: 'API Access',
|
|
541
|
-
type: 'boolean', // 'boolean' | 'limit' | 'unlimited'
|
|
542
|
-
description: 'Access to REST API',
|
|
543
|
-
usageMetricId: 'metric_123', // Link to usage tracking
|
|
544
|
-
});
|
|
545
|
-
|
|
546
|
-
// Update a feature
|
|
547
|
-
const { feature } = await client.apps.updateFeature('app_123', 'feature_123', {
|
|
548
|
-
name: 'API Access v2',
|
|
549
|
-
description: 'Updated description',
|
|
550
|
-
});
|
|
551
|
-
|
|
552
|
-
// Delete a feature
|
|
553
|
-
await client.apps.deleteFeature('app_123', 'feature_123');
|
|
554
|
-
```
|
|
555
|
-
|
|
556
|
-
### Usage Metrics
|
|
557
|
-
|
|
558
|
-
```typescript
|
|
559
|
-
// List usage metrics
|
|
560
|
-
const { usageMetrics } = await client.apps.listUsageMetrics('app_123');
|
|
561
|
-
|
|
562
|
-
// Retrieve a usage metric
|
|
563
|
-
const { usageMetric } = await client.apps.retrieveUsageMetric('app_123', 'metric_123');
|
|
564
|
-
|
|
565
|
-
// Create a usage metric
|
|
566
|
-
const { usageMetric } = await client.apps.createUsageMetric('app_123', {
|
|
567
|
-
name: 'API Calls',
|
|
568
|
-
description: 'Number of API requests',
|
|
569
|
-
eventName: 'api_call',
|
|
570
|
-
aggregationType: 'count',
|
|
571
|
-
});
|
|
572
|
-
|
|
573
|
-
// Update a usage metric
|
|
574
|
-
const { usageMetric } = await client.apps.updateUsageMetric('app_123', 'metric_123', {
|
|
575
|
-
name: 'API Requests',
|
|
576
|
-
});
|
|
577
|
-
|
|
578
|
-
// Delete a usage metric
|
|
579
|
-
await client.apps.deleteUsageMetric('app_123', 'metric_123');
|
|
580
|
-
|
|
581
|
-
// Get event names for an app
|
|
582
|
-
const { eventNames } = await client.apps.listEventNames('app_123');
|
|
583
|
-
|
|
584
|
-
// Get property keys for an event
|
|
585
|
-
const { propertyKeys } = await client.apps.listPropertyKeys('app_123', 'api_call');
|
|
586
|
-
```
|
|
587
|
-
|
|
588
|
-
### App Events
|
|
589
|
-
|
|
590
|
-
```typescript
|
|
591
|
-
// List app events
|
|
592
|
-
const { appEvents, hasNextPage } = await client.apps.listAppEvents('app_123', {
|
|
593
|
-
customerId: 'cust_123',
|
|
594
|
-
take: 50,
|
|
595
|
-
});
|
|
596
|
-
```
|
|
597
|
-
|
|
598
|
-
### Reviews
|
|
599
|
-
|
|
600
|
-
```typescript
|
|
601
|
-
// List reviews
|
|
602
|
-
const { reviews } = await client.apps.listReviews('app_123');
|
|
603
|
-
|
|
604
|
-
// Retrieve a review
|
|
605
|
-
const { review } = await client.apps.retrieveReview('app_123', 'review_123');
|
|
606
|
-
|
|
607
|
-
// Create a review
|
|
608
|
-
const { review } = await client.apps.createReview('app_123', {
|
|
609
|
-
rating: 5,
|
|
610
|
-
title: 'Excellent app!',
|
|
611
|
-
body: 'This app transformed our workflow.',
|
|
612
|
-
});
|
|
613
|
-
|
|
614
|
-
// Update a review
|
|
615
|
-
const { review } = await client.apps.updateReview('app_123', 'review_123', {
|
|
616
|
-
rating: 4,
|
|
617
|
-
body: 'Updated review text',
|
|
618
|
-
});
|
|
619
|
-
|
|
620
|
-
// Delete a review
|
|
621
|
-
await client.apps.deleteReview('app_123', 'review_123');
|
|
622
|
-
```
|
|
623
|
-
|
|
624
|
-
### Tickets
|
|
625
|
-
|
|
626
|
-
```typescript
|
|
627
|
-
// List tickets with filters
|
|
628
|
-
const { tickets, hasNextPage, total } = await client.tickets.list({
|
|
629
|
-
status: 'open', // 'open' | 'pending' | 'resolved' | 'closed'
|
|
630
|
-
priority: 'high', // 'low' | 'medium' | 'high' | 'urgent'
|
|
631
|
-
assignedToId: 'user_123',
|
|
632
|
-
appId: 'app_123',
|
|
633
|
-
customerId: 'cust_123',
|
|
634
|
-
contactId: 'contact_123',
|
|
635
|
-
channelId: 'channel_123',
|
|
636
|
-
tags: ['billing', 'urgent'],
|
|
637
|
-
take: 25,
|
|
638
|
-
});
|
|
639
|
-
|
|
640
|
-
// Retrieve a ticket
|
|
641
|
-
const { ticket } = await client.tickets.retrieve('ticket_123');
|
|
642
|
-
|
|
643
|
-
// Create a ticket - Option 1: Link existing contact
|
|
644
|
-
const { ticket } = await client.tickets.create({
|
|
645
|
-
subject: 'Need help with integration',
|
|
646
|
-
status: 'open',
|
|
647
|
-
priority: 'medium',
|
|
648
|
-
customerId: 'cust_123',
|
|
649
|
-
contactId: 'contact_123',
|
|
650
|
-
appId: 'app_123',
|
|
651
|
-
channelId: 'channel_123',
|
|
652
|
-
assignedToId: 'user_123',
|
|
653
|
-
tags: ['integration', 'api'],
|
|
654
|
-
});
|
|
655
|
-
|
|
656
|
-
// Create a ticket - Option 2: Create contact inline
|
|
657
|
-
const { ticket } = await client.tickets.create({
|
|
658
|
-
subject: 'Billing question',
|
|
659
|
-
priority: 'high',
|
|
660
|
-
customerId: 'cust_123',
|
|
661
|
-
contact: {
|
|
662
|
-
email: 'support-requester@acme.com',
|
|
663
|
-
name: 'Support User',
|
|
664
|
-
},
|
|
665
|
-
});
|
|
666
|
-
|
|
667
|
-
// Update a ticket
|
|
668
|
-
const { ticket } = await client.tickets.update('ticket_123', {
|
|
669
|
-
status: 'pending',
|
|
670
|
-
priority: 'urgent',
|
|
671
|
-
assignedToId: 'user_456',
|
|
672
|
-
tags: ['escalated'],
|
|
673
|
-
});
|
|
674
|
-
|
|
675
|
-
// Delete a ticket
|
|
676
|
-
await client.tickets.del('ticket_123');
|
|
677
|
-
|
|
678
|
-
// List messages for a ticket
|
|
679
|
-
const { messages } = await client.tickets.listMessages('ticket_123');
|
|
680
|
-
|
|
681
|
-
// Retrieve a message
|
|
682
|
-
const { message } = await client.tickets.retrieveMessage('ticket_123', 'message_123');
|
|
683
|
-
|
|
684
|
-
// Create a message with attachments
|
|
685
|
-
const { message } = await client.tickets.createMessage('ticket_123', {
|
|
686
|
-
body: 'Here is the solution to your problem...',
|
|
687
|
-
from: 'agent', // 'customer' | 'agent'
|
|
688
|
-
attachments: [
|
|
689
|
-
{
|
|
690
|
-
filename: 'solution.pdf',
|
|
691
|
-
url: 'https://storage.example.com/solution.pdf',
|
|
692
|
-
contentType: 'application/pdf',
|
|
693
|
-
size: 102400,
|
|
694
|
-
},
|
|
695
|
-
],
|
|
696
|
-
});
|
|
697
|
-
|
|
698
|
-
// Update a message
|
|
699
|
-
const { message } = await client.tickets.updateMessage('ticket_123', 'message_123', {
|
|
700
|
-
body: 'Updated message content',
|
|
701
|
-
});
|
|
702
|
-
|
|
703
|
-
// Delete a message
|
|
704
|
-
await client.tickets.deleteMessage('ticket_123', 'message_123');
|
|
705
|
-
```
|
|
706
|
-
|
|
707
|
-
### Channels
|
|
708
|
-
|
|
709
|
-
Manage CX channels for tickets:
|
|
710
|
-
|
|
711
|
-
```typescript
|
|
712
|
-
// List channels
|
|
713
|
-
const { channels } = await client.channels.list({
|
|
714
|
-
type: 'email', // 'email' | 'chat'
|
|
715
|
-
});
|
|
716
|
-
|
|
717
|
-
// Create a channel
|
|
718
|
-
const { channel } = await client.channels.create({
|
|
719
|
-
type: 'email',
|
|
720
|
-
name: 'Support Email',
|
|
721
|
-
});
|
|
722
|
-
```
|
|
723
|
-
|
|
724
|
-
### Agents
|
|
725
|
-
|
|
726
|
-
Manage support agents:
|
|
727
|
-
|
|
728
|
-
```typescript
|
|
729
|
-
// List agents
|
|
730
|
-
const { agents } = await client.agents.list();
|
|
731
|
-
|
|
732
|
-
// Retrieve an agent
|
|
733
|
-
const { agent } = await client.agents.retrieve('agent_123');
|
|
734
|
-
|
|
735
|
-
// Create an agent
|
|
736
|
-
const { agent } = await client.agents.create({
|
|
737
|
-
email: 'agent@company.com',
|
|
738
|
-
name: 'Support Agent',
|
|
739
|
-
});
|
|
740
|
-
|
|
741
|
-
// Find or create an agent (upsert by email)
|
|
742
|
-
const { agent } = await client.agents.findOrCreate({
|
|
743
|
-
email: 'agent@company.com',
|
|
744
|
-
name: 'Support Agent',
|
|
745
|
-
});
|
|
746
|
-
```
|
|
747
|
-
|
|
748
|
-
### Metrics
|
|
749
|
-
|
|
750
|
-
Retrieve analytics and business metrics:
|
|
751
|
-
|
|
752
|
-
```typescript
|
|
753
|
-
import type { DateRangeType } from '@heymantle/core-api-client';
|
|
754
|
-
|
|
755
|
-
// Date range options:
|
|
756
|
-
// 'last_30_minutes' | 'last_60_minutes' | 'last_12_hours' | 'last_24_hours'
|
|
757
|
-
// 'last_7_days' | 'last_14_days' | 'last_30_days' | 'last_90_days'
|
|
758
|
-
// 'last_12_months' | 'last_24_months'
|
|
759
|
-
// 'today' | 'yesterday' | 'last_month'
|
|
760
|
-
// 'month_to_date' | 'quarter_to_date' | 'year_to_date'
|
|
761
|
-
// 'all_time' | 'custom'
|
|
762
|
-
|
|
763
|
-
// Monthly Recurring Revenue
|
|
764
|
-
const mrr = await client.metrics.mrr({
|
|
765
|
-
appId: 'app_123',
|
|
766
|
-
dateRange: 'last_30_days',
|
|
767
|
-
});
|
|
768
|
-
console.log(mrr.total, mrr.formattedTotal); // 50000, "$500.00"
|
|
769
|
-
console.log(mrr.change, mrr.changePercentage); // 5000, 10
|
|
770
|
-
|
|
771
|
-
// Annual Recurring Revenue
|
|
772
|
-
const arr = await client.metrics.arr({ appId: 'app_123' });
|
|
773
|
-
|
|
774
|
-
// Average Revenue Per User
|
|
775
|
-
const arpu = await client.metrics.arpu({ appId: 'app_123' });
|
|
776
|
-
|
|
777
|
-
// Customer Lifetime Value
|
|
778
|
-
const ltv = await client.metrics.ltv({ appId: 'app_123' });
|
|
779
|
-
|
|
780
|
-
// Predicted LTV
|
|
781
|
-
const predictedLtv = await client.metrics.predictedLtv({ appId: 'app_123' });
|
|
782
|
-
|
|
783
|
-
// Revenue Churn
|
|
784
|
-
const revenueChurn = await client.metrics.revenueChurn({ appId: 'app_123' });
|
|
785
|
-
|
|
786
|
-
// Logo (Customer) Churn
|
|
787
|
-
const logoChurn = await client.metrics.logoChurn({ appId: 'app_123' });
|
|
788
|
-
|
|
789
|
-
// Revenue Retention
|
|
790
|
-
const revenueRetention = await client.metrics.revenueRetention({ appId: 'app_123' });
|
|
791
|
-
|
|
792
|
-
// Net Revenue Retention
|
|
793
|
-
const nrr = await client.metrics.netRevenueRetention({ appId: 'app_123' });
|
|
794
|
-
|
|
795
|
-
// Net Revenue
|
|
796
|
-
const netRevenue = await client.metrics.netRevenue({ appId: 'app_123' });
|
|
797
|
-
|
|
798
|
-
// Active Subscriptions
|
|
799
|
-
const activeSubs = await client.metrics.activeSubscriptions({ appId: 'app_123' });
|
|
800
|
-
|
|
801
|
-
// Active Installs
|
|
802
|
-
const activeInstalls = await client.metrics.activeInstalls({ appId: 'app_123' });
|
|
803
|
-
|
|
804
|
-
// Net Installs
|
|
805
|
-
const netInstalls = await client.metrics.netInstalls({ appId: 'app_123' });
|
|
806
|
-
|
|
807
|
-
// Charges
|
|
808
|
-
const charges = await client.metrics.charges({ appId: 'app_123' });
|
|
809
|
-
|
|
810
|
-
// Payout
|
|
811
|
-
const payout = await client.metrics.payout({ appId: 'app_123' });
|
|
812
|
-
|
|
813
|
-
// Usage event metrics
|
|
814
|
-
const usageMetrics = await client.metrics.usageEvent({
|
|
815
|
-
appId: 'app_123',
|
|
816
|
-
eventName: 'api_call',
|
|
817
|
-
propertyKey: 'endpoint',
|
|
818
|
-
aggregation: 'count', // 'count' | 'sum' | 'avg' | 'min' | 'max'
|
|
819
|
-
dateRange: 'last_7_days',
|
|
820
|
-
});
|
|
821
|
-
|
|
822
|
-
// Usage metric by ID
|
|
823
|
-
const metricData = await client.metrics.usageMetric({
|
|
824
|
-
appId: 'app_123',
|
|
825
|
-
metricId: 'metric_123',
|
|
826
|
-
dateRange: 'last_30_days',
|
|
827
|
-
});
|
|
828
|
-
|
|
829
|
-
// Sales metrics
|
|
830
|
-
const salesData = await client.metrics.sales({
|
|
831
|
-
appId: 'app_123',
|
|
832
|
-
dateRange: 'last_30_days',
|
|
833
|
-
});
|
|
834
|
-
|
|
835
|
-
// Custom metric query
|
|
836
|
-
const data = await client.metrics.fetch({
|
|
837
|
-
metric: 'PlatformApp.activeInstalls',
|
|
838
|
-
appId: 'app_123',
|
|
839
|
-
dateRange: 'last_90_days',
|
|
840
|
-
startDate: '2024-01-01',
|
|
841
|
-
endDate: '2024-03-31',
|
|
842
|
-
includes: ['includeTotal'],
|
|
843
|
-
appEventsForMrr: true,
|
|
844
|
-
});
|
|
845
|
-
```
|
|
846
|
-
|
|
847
|
-
### Usage Events
|
|
848
|
-
|
|
849
|
-
Track customer usage for billing:
|
|
850
|
-
|
|
851
|
-
```typescript
|
|
852
|
-
// List usage events
|
|
853
|
-
const { usageEvents, hasNextPage } = await client.usageEvents.list({
|
|
854
|
-
appId: 'app_123',
|
|
855
|
-
customerId: 'cust_123',
|
|
856
|
-
eventName: 'api_call',
|
|
857
|
-
billingStatus: 'unbilled',
|
|
858
|
-
countryCode: 'US',
|
|
859
|
-
startDate: '2024-01-01',
|
|
860
|
-
endDate: '2024-01-31',
|
|
861
|
-
propertiesFilters: { endpoint: '/users' },
|
|
862
|
-
});
|
|
863
|
-
|
|
864
|
-
// Track a single event
|
|
865
|
-
await client.usageEvents.create({
|
|
866
|
-
eventName: 'api_call',
|
|
867
|
-
customerId: 'cust_123',
|
|
868
|
-
appId: 'app_123',
|
|
869
|
-
timestamp: new Date().toISOString(),
|
|
870
|
-
eventId: 'unique-event-id', // For deduplication
|
|
871
|
-
properties: { endpoint: '/users', method: 'GET', responseTime: 150 },
|
|
872
|
-
private: false,
|
|
873
|
-
});
|
|
874
|
-
|
|
875
|
-
// Track multiple events
|
|
876
|
-
await client.usageEvents.create({
|
|
877
|
-
events: [
|
|
878
|
-
{ eventName: 'api_call', customerId: 'cust_123', appId: 'app_123' },
|
|
879
|
-
{ eventName: 'api_call', customerId: 'cust_456', appId: 'app_123' },
|
|
880
|
-
{ eventName: 'file_upload', customerId: 'cust_123', appId: 'app_123', properties: { size: 1024 } },
|
|
881
|
-
],
|
|
882
|
-
});
|
|
883
|
-
```
|
|
884
|
-
|
|
885
|
-
### Webhooks
|
|
886
|
-
|
|
887
|
-
```typescript
|
|
888
|
-
// List webhooks
|
|
889
|
-
const { webhooks } = await client.webhooks.list();
|
|
890
|
-
|
|
891
|
-
// Retrieve a webhook
|
|
892
|
-
const { webhook } = await client.webhooks.retrieve('webhook_123');
|
|
893
|
-
|
|
894
|
-
// Create a webhook
|
|
895
|
-
const { webhook } = await client.webhooks.create({
|
|
896
|
-
topic: 'customer.created',
|
|
897
|
-
address: 'https://your-app.com/webhooks',
|
|
898
|
-
});
|
|
899
|
-
|
|
900
|
-
// Update a webhook
|
|
901
|
-
const { webhook } = await client.webhooks.update('webhook_123', {
|
|
902
|
-
address: 'https://your-app.com/webhooks/v2',
|
|
903
|
-
});
|
|
904
|
-
|
|
905
|
-
// Delete a webhook
|
|
906
|
-
await client.webhooks.del('webhook_123');
|
|
907
|
-
```
|
|
908
|
-
|
|
909
|
-
### Affiliates
|
|
910
|
-
|
|
911
|
-
```typescript
|
|
912
|
-
// List affiliates
|
|
913
|
-
const { affiliates, hasNextPage } = await client.affiliates.list({
|
|
914
|
-
affiliateProgramId: 'program_123',
|
|
915
|
-
status: 'active', // 'pending' | 'active' | 'rejected' | 'suspended'
|
|
916
|
-
appId: 'app_123',
|
|
917
|
-
email: 'affiliate@example.com',
|
|
918
|
-
});
|
|
919
|
-
|
|
920
|
-
// Retrieve an affiliate
|
|
921
|
-
const { affiliate } = await client.affiliates.retrieve('affiliate_123');
|
|
922
|
-
|
|
923
|
-
// Update an affiliate
|
|
924
|
-
const { affiliate } = await client.affiliates.update('affiliate_123', {
|
|
925
|
-
status: 'active',
|
|
926
|
-
commissionRate: 0.25, // 25%
|
|
927
|
-
});
|
|
928
|
-
```
|
|
929
|
-
|
|
930
|
-
### Affiliate Programs
|
|
931
|
-
|
|
932
|
-
```typescript
|
|
933
|
-
// List affiliate programs
|
|
934
|
-
const { affiliatePrograms } = await client.affiliatePrograms.list();
|
|
935
|
-
|
|
936
|
-
// Retrieve an affiliate program
|
|
937
|
-
const { affiliateProgram } = await client.affiliatePrograms.retrieve('program_123');
|
|
938
|
-
|
|
939
|
-
// Create an affiliate program
|
|
940
|
-
const { affiliateProgram } = await client.affiliatePrograms.create({
|
|
941
|
-
name: 'Partner Program',
|
|
942
|
-
description: 'Earn 20% commission on referrals',
|
|
943
|
-
commissionType: 'percentage', // 'percentage' | 'fixed'
|
|
944
|
-
commissionValue: 20,
|
|
945
|
-
commissionDurationMonths: 12,
|
|
946
|
-
cookieDurationDays: 30,
|
|
947
|
-
minimumPayoutAmount: 5000, // $50.00
|
|
948
|
-
payoutCurrency: 'USD',
|
|
949
|
-
active: true,
|
|
950
|
-
});
|
|
951
|
-
|
|
952
|
-
// Update an affiliate program
|
|
953
|
-
const { affiliateProgram } = await client.affiliatePrograms.update('program_123', {
|
|
954
|
-
commissionValue: 25,
|
|
955
|
-
});
|
|
956
|
-
|
|
957
|
-
// Delete an affiliate program
|
|
958
|
-
await client.affiliatePrograms.del('program_123');
|
|
959
|
-
```
|
|
960
|
-
|
|
961
|
-
### Affiliate Commissions
|
|
962
|
-
|
|
963
|
-
```typescript
|
|
964
|
-
// List commissions
|
|
965
|
-
const { commissions, hasNextPage } = await client.affiliateCommissions.list({
|
|
966
|
-
affiliateId: 'affiliate_123',
|
|
967
|
-
status: 'pending', // 'pending' | 'approved' | 'paid' | 'rejected'
|
|
968
|
-
});
|
|
969
|
-
|
|
970
|
-
// Retrieve a commission
|
|
971
|
-
const { commission } = await client.affiliateCommissions.retrieve('commission_123');
|
|
972
|
-
```
|
|
973
|
-
|
|
974
|
-
### Affiliate Payouts
|
|
975
|
-
|
|
976
|
-
```typescript
|
|
977
|
-
// List payouts
|
|
978
|
-
const { payouts, hasNextPage } = await client.affiliatePayouts.list({
|
|
979
|
-
affiliateId: 'affiliate_123',
|
|
980
|
-
status: 'completed', // 'pending' | 'processing' | 'completed' | 'failed'
|
|
981
|
-
});
|
|
982
|
-
|
|
983
|
-
// Retrieve a payout
|
|
984
|
-
const { payout } = await client.affiliatePayouts.retrieve('payout_123');
|
|
985
|
-
```
|
|
986
|
-
|
|
987
|
-
### Affiliate Referrals
|
|
988
|
-
|
|
989
|
-
```typescript
|
|
990
|
-
// List referrals
|
|
991
|
-
const { referrals, hasNextPage } = await client.affiliateReferrals.list({
|
|
992
|
-
affiliateId: 'affiliate_123',
|
|
993
|
-
status: 'converted', // 'pending' | 'converted' | 'expired'
|
|
994
|
-
});
|
|
995
|
-
|
|
996
|
-
// Retrieve a referral
|
|
997
|
-
const { referral } = await client.affiliateReferrals.retrieve('referral_123');
|
|
998
|
-
```
|
|
999
|
-
|
|
1000
|
-
### Companies
|
|
1001
|
-
|
|
1002
|
-
```typescript
|
|
1003
|
-
// List companies
|
|
1004
|
-
const { companies, hasNextPage } = await client.companies.list({
|
|
1005
|
-
take: 25,
|
|
1006
|
-
search: 'acme',
|
|
1007
|
-
});
|
|
1008
|
-
|
|
1009
|
-
// Retrieve a company
|
|
1010
|
-
const { company } = await client.companies.retrieve('company_123');
|
|
1011
|
-
|
|
1012
|
-
// Create a company
|
|
1013
|
-
const { company } = await client.companies.create({
|
|
1014
|
-
name: 'Acme Holdings',
|
|
1015
|
-
domain: 'acme.com',
|
|
1016
|
-
});
|
|
1017
|
-
|
|
1018
|
-
// Update a company
|
|
1019
|
-
const { company } = await client.companies.update('company_123', {
|
|
1020
|
-
name: 'Acme Holdings Inc',
|
|
1021
|
-
});
|
|
1022
|
-
|
|
1023
|
-
// Delete a company
|
|
1024
|
-
await client.companies.del('company_123');
|
|
1025
|
-
```
|
|
1026
|
-
|
|
1027
|
-
### Customer Segments
|
|
1028
|
-
|
|
1029
|
-
```typescript
|
|
1030
|
-
// List customer segments
|
|
1031
|
-
const { customerSegments } = await client.customerSegments.list();
|
|
1032
|
-
|
|
1033
|
-
// Retrieve a segment
|
|
1034
|
-
const { customerSegment } = await client.customerSegments.retrieve('segment_123');
|
|
1035
|
-
```
|
|
1036
|
-
|
|
1037
|
-
### Tasks
|
|
1038
|
-
|
|
1039
|
-
Tasks support todo items as a nested sub-resource. Updating a task's status can trigger deal progression if the task is linked to a deal activity.
|
|
1040
|
-
|
|
1041
|
-
```typescript
|
|
1042
|
-
// List tasks
|
|
1043
|
-
const { tasks, hasNextPage } = await client.tasks.list({
|
|
1044
|
-
status: 'new', // 'new' | 'in_progress' | 'complete'
|
|
1045
|
-
priority: 'high', // 'low' | 'medium' | 'high'
|
|
1046
|
-
assigneeId: 'user_123',
|
|
1047
|
-
customerId: 'cust_123',
|
|
1048
|
-
dealId: 'deal_123',
|
|
1049
|
-
});
|
|
1050
|
-
|
|
1051
|
-
// Retrieve a task
|
|
1052
|
-
const { task } = await client.tasks.retrieve('task_123');
|
|
1053
|
-
|
|
1054
|
-
// Create a task with todo items
|
|
1055
|
-
const task = await client.tasks.create({
|
|
1056
|
-
title: 'Follow up with customer',
|
|
1057
|
-
description: 'Discuss renewal options',
|
|
1058
|
-
priority: 'high',
|
|
1059
|
-
dueDate: '2024-02-15',
|
|
1060
|
-
assigneeId: 'user_123',
|
|
1061
|
-
customerId: 'cust_123',
|
|
1062
|
-
dealId: 'deal_123',
|
|
1063
|
-
dealActivityId: 'activity_123',
|
|
1064
|
-
tags: ['follow-up'],
|
|
1065
|
-
todoItems: [
|
|
1066
|
-
{ content: 'Prepare pricing proposal', completed: false },
|
|
1067
|
-
{ content: 'Review contract terms', completed: false },
|
|
1068
|
-
],
|
|
1069
|
-
});
|
|
1070
|
-
|
|
1071
|
-
// Update a task (may trigger deal progression)
|
|
1072
|
-
const { task, dealProgressed, dealProgression } = await client.tasks.update('task_123', {
|
|
1073
|
-
status: 'complete',
|
|
1074
|
-
});
|
|
1075
|
-
if (dealProgressed) {
|
|
1076
|
-
console.log(`Deal "${dealProgression.dealName}" moved to stage "${dealProgression.nextStage.name}"`);
|
|
1077
|
-
}
|
|
1078
|
-
|
|
1079
|
-
// Delete a task
|
|
1080
|
-
await client.tasks.del('task_123');
|
|
1081
|
-
|
|
1082
|
-
// --- Todo Items ---
|
|
1083
|
-
|
|
1084
|
-
// List todo items for a task
|
|
1085
|
-
const { items, total } = await client.tasks.listTodoItems('task_123');
|
|
1086
|
-
|
|
1087
|
-
// Retrieve a todo item
|
|
1088
|
-
const { item } = await client.tasks.retrieveTodoItem('task_123', 'item_123');
|
|
1089
|
-
|
|
1090
|
-
// Create a todo item
|
|
1091
|
-
const { item } = await client.tasks.createTodoItem('task_123', {
|
|
1092
|
-
content: 'Send follow-up email',
|
|
1093
|
-
completed: false,
|
|
1094
|
-
displayOrder: 3,
|
|
1095
|
-
});
|
|
1096
|
-
|
|
1097
|
-
// Update a todo item
|
|
1098
|
-
const { item } = await client.tasks.updateTodoItem('task_123', 'item_123', {
|
|
1099
|
-
completed: true,
|
|
1100
|
-
});
|
|
1101
|
-
|
|
1102
|
-
// Delete a todo item
|
|
1103
|
-
await client.tasks.deleteTodoItem('task_123', 'item_123');
|
|
1104
19
|
```
|
|
1105
20
|
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
```typescript
|
|
1109
|
-
// List flows
|
|
1110
|
-
const { flows } = await client.flows.list();
|
|
1111
|
-
|
|
1112
|
-
// Retrieve a flow
|
|
1113
|
-
const { flow } = await client.flows.retrieve('flow_123');
|
|
1114
|
-
|
|
1115
|
-
// Create a flow
|
|
1116
|
-
const { flow } = await client.flows.create({
|
|
1117
|
-
name: 'Onboarding Flow',
|
|
1118
|
-
trigger: 'customer.created',
|
|
1119
|
-
actions: [
|
|
1120
|
-
{ type: 'email', template: 'welcome' },
|
|
1121
|
-
],
|
|
1122
|
-
});
|
|
1123
|
-
|
|
1124
|
-
// Update a flow
|
|
1125
|
-
const { flow } = await client.flows.update('flow_123', {
|
|
1126
|
-
name: 'Updated Onboarding Flow',
|
|
1127
|
-
enabled: true,
|
|
1128
|
-
});
|
|
1129
|
-
|
|
1130
|
-
// Delete a flow
|
|
1131
|
-
await client.flows.del('flow_123');
|
|
1132
|
-
```
|
|
21
|
+
## Authentication
|
|
1133
22
|
|
|
1134
|
-
|
|
23
|
+
The client supports two authentication methods:
|
|
1135
24
|
|
|
1136
25
|
```typescript
|
|
1137
|
-
//
|
|
1138
|
-
const
|
|
1139
|
-
|
|
1140
|
-
appId: 'app_123',
|
|
26
|
+
// API Key (for server-side use)
|
|
27
|
+
const client = new MantleCoreClient({
|
|
28
|
+
apiKey: 'your-api-key',
|
|
1141
29
|
});
|
|
1142
30
|
|
|
1143
|
-
//
|
|
1144
|
-
const
|
|
1145
|
-
|
|
1146
|
-
// List charges
|
|
1147
|
-
const { charges, hasNextPage } = await client.charges.list({
|
|
1148
|
-
customerId: 'cust_123',
|
|
1149
|
-
appId: 'app_123',
|
|
31
|
+
// OAuth Access Token
|
|
32
|
+
const client = new MantleCoreClient({
|
|
33
|
+
accessToken: 'your-oauth-token',
|
|
1150
34
|
});
|
|
1151
35
|
```
|
|
1152
36
|
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
```typescript
|
|
1156
|
-
// List users in the organization
|
|
1157
|
-
const { users } = await client.users.list();
|
|
1158
|
-
|
|
1159
|
-
// Retrieve a user
|
|
1160
|
-
const { user } = await client.users.retrieve('user_123');
|
|
1161
|
-
```
|
|
1162
|
-
|
|
1163
|
-
### Me & Organization
|
|
1164
|
-
|
|
1165
|
-
```typescript
|
|
1166
|
-
// Get current user and organization
|
|
1167
|
-
const { user, organization } = await client.me.retrieve();
|
|
1168
|
-
|
|
1169
|
-
// Get organization details
|
|
1170
|
-
const { organization } = await client.organization.retrieve();
|
|
1171
|
-
```
|
|
1172
|
-
|
|
1173
|
-
### Documentation
|
|
1174
|
-
|
|
1175
|
-
Manage documentation collections, groups, pages, repositories, and the doc tree:
|
|
1176
|
-
|
|
1177
|
-
```typescript
|
|
1178
|
-
// --- Collections ---
|
|
1179
|
-
const { collections } = await client.docs.listCollections();
|
|
1180
|
-
const { collection } = await client.docs.retrieveCollection('collection_123');
|
|
1181
|
-
const { collection } = await client.docs.createCollection({
|
|
1182
|
-
name: 'API Docs',
|
|
1183
|
-
slug: 'api-docs',
|
|
1184
|
-
description: 'API documentation',
|
|
1185
|
-
});
|
|
1186
|
-
const { collection } = await client.docs.updateCollection('collection_123', {
|
|
1187
|
-
name: 'Updated API Docs',
|
|
1188
|
-
});
|
|
1189
|
-
await client.docs.deleteCollection('collection_123');
|
|
1190
|
-
|
|
1191
|
-
// --- Groups ---
|
|
1192
|
-
const { groups } = await client.docs.listGroups();
|
|
1193
|
-
const { group } = await client.docs.retrieveGroup('group_123');
|
|
1194
|
-
const { group } = await client.docs.createGroup({ name: 'Guides' });
|
|
1195
|
-
const { group } = await client.docs.updateGroup('group_123', { name: 'Updated Guides' });
|
|
1196
|
-
await client.docs.deleteGroup('group_123');
|
|
1197
|
-
|
|
1198
|
-
// --- Pages ---
|
|
1199
|
-
const { pages } = await client.docs.listPages({
|
|
1200
|
-
collectionId: 'collection_123',
|
|
1201
|
-
});
|
|
1202
|
-
const { page } = await client.docs.retrievePage('page_123');
|
|
1203
|
-
const { page } = await client.docs.createPage({
|
|
1204
|
-
title: 'Getting Started',
|
|
1205
|
-
content: '# Getting Started\n\nWelcome to our docs...',
|
|
1206
|
-
collectionId: 'collection_123',
|
|
1207
|
-
});
|
|
1208
|
-
const { page } = await client.docs.updatePage('page_123', {
|
|
1209
|
-
content: 'Updated content',
|
|
1210
|
-
});
|
|
1211
|
-
const { page } = await client.docs.publishPage('page_123');
|
|
1212
|
-
const { page } = await client.docs.archivePage('page_123');
|
|
1213
|
-
await client.docs.deletePage('page_123');
|
|
1214
|
-
|
|
1215
|
-
// --- Tree ---
|
|
1216
|
-
const { tree } = await client.docs.getTree();
|
|
1217
|
-
|
|
1218
|
-
// --- Repositories ---
|
|
1219
|
-
const { repositories } = await client.docs.listRepositories();
|
|
1220
|
-
const { repository } = await client.docs.retrieveRepository('repo_123');
|
|
1221
|
-
```
|
|
37
|
+
## Resources
|
|
1222
38
|
|
|
1223
|
-
|
|
39
|
+
For full documentation on all available resources and their parameters, see the [Mantle Core API Reference](https://coreapi.heymantle.dev/reference).
|
|
1224
40
|
|
|
1225
|
-
|
|
41
|
+
### Customers
|
|
1226
42
|
|
|
1227
43
|
```typescript
|
|
1228
|
-
//
|
|
1229
|
-
const {
|
|
1230
|
-
search: 'acme',
|
|
44
|
+
// List customers
|
|
45
|
+
const { customers, hasNextPage, total } = await client.customers.list({
|
|
1231
46
|
take: 25,
|
|
47
|
+
search: 'acme',
|
|
48
|
+
sort: 'createdAt',
|
|
49
|
+
sortDirection: 'desc',
|
|
1232
50
|
});
|
|
1233
51
|
|
|
1234
|
-
//
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
} else if (entity._type === 'contact') {
|
|
1239
|
-
console.log('Contact:', entity.name, entity.email);
|
|
1240
|
-
}
|
|
1241
|
-
});
|
|
1242
|
-
```
|
|
1243
|
-
|
|
1244
|
-
### Meetings
|
|
1245
|
-
|
|
1246
|
-
Record, transcribe, and analyze meetings with AI enrichment:
|
|
1247
|
-
|
|
1248
|
-
```typescript
|
|
1249
|
-
// List meetings
|
|
1250
|
-
const { meetings, hasNextPage } = await client.meetings.list({
|
|
1251
|
-
dealId: 'deal_123',
|
|
1252
|
-
customerId: 'cust_123',
|
|
1253
|
-
platform: 'google_meet', // 'google_meet' | 'zoom' | 'teams'
|
|
1254
|
-
startTimeFrom: '2024-01-01T00:00:00Z',
|
|
1255
|
-
startTimeTo: '2024-12-31T23:59:59Z',
|
|
1256
|
-
search: 'quarterly review',
|
|
1257
|
-
includeArchived: false,
|
|
1258
|
-
});
|
|
1259
|
-
|
|
1260
|
-
// Retrieve a meeting (includes attendees, transcript, AI insights)
|
|
1261
|
-
const meeting = await client.meetings.retrieve('meeting_123');
|
|
1262
|
-
|
|
1263
|
-
// Create a meeting with attendees and transcript
|
|
1264
|
-
const meeting = await client.meetings.create({
|
|
1265
|
-
meetingData: {
|
|
1266
|
-
title: 'Q1 Review',
|
|
1267
|
-
platform: 'zoom',
|
|
1268
|
-
startTime: '2024-01-15T14:00:00Z',
|
|
1269
|
-
endTime: '2024-01-15T15:00:00Z',
|
|
1270
|
-
duration: 3600,
|
|
1271
|
-
dealId: 'deal_123',
|
|
1272
|
-
customerId: 'cust_123',
|
|
1273
|
-
},
|
|
1274
|
-
attendees: [
|
|
1275
|
-
{ name: 'John Doe', email: 'john@acme.com', externalId: 'A' },
|
|
1276
|
-
{ name: 'Jane Smith', email: 'jane@company.com', externalId: 'B' },
|
|
1277
|
-
],
|
|
1278
|
-
transcript: {
|
|
1279
|
-
language: 'en',
|
|
1280
|
-
utterances: [
|
|
1281
|
-
{ attendeeId: 'A', text: 'Welcome to the review.', startTime: 0, endTime: 3000, sequence: 1 },
|
|
1282
|
-
{ attendeeId: 'B', text: 'Thanks for having me.', startTime: 3500, endTime: 6000, sequence: 2 },
|
|
1283
|
-
],
|
|
1284
|
-
},
|
|
1285
|
-
});
|
|
1286
|
-
|
|
1287
|
-
// Update a meeting
|
|
1288
|
-
const meeting = await client.meetings.update('meeting_123', {
|
|
1289
|
-
title: 'Q1 Business Review',
|
|
1290
|
-
dealId: 'deal_456',
|
|
1291
|
-
});
|
|
1292
|
-
|
|
1293
|
-
// Delete a meeting
|
|
1294
|
-
await client.meetings.del('meeting_123');
|
|
1295
|
-
|
|
1296
|
-
// --- Recording Upload & Transcription Workflow ---
|
|
1297
|
-
|
|
1298
|
-
// Step 1: Get a signed upload URL
|
|
1299
|
-
const { uploadUrl, recordingKey, expiresIn } = await client.meetings.getUploadUrl('meeting_123', 'recording.webm');
|
|
1300
|
-
|
|
1301
|
-
// Step 2: Upload the file to the signed URL (use fetch/axios)
|
|
1302
|
-
await fetch(uploadUrl, { method: 'PUT', body: recordingFile });
|
|
1303
|
-
|
|
1304
|
-
// Step 3: Start transcription
|
|
1305
|
-
const meeting = await client.meetings.startTranscription('meeting_123', { recordingKey });
|
|
1306
|
-
|
|
1307
|
-
// Step 4: Check transcription status
|
|
1308
|
-
const status = await client.meetings.getTranscriptionStatus('meeting_123');
|
|
1309
|
-
console.log(status.recordingStatus); // 'pending' | 'processing' | 'ready' | 'failed'
|
|
1310
|
-
|
|
1311
|
-
// Get a signed recording playback URL
|
|
1312
|
-
const { recordingUrl, expiresIn } = await client.meetings.getRecordingUrl('meeting_123');
|
|
1313
|
-
|
|
1314
|
-
// --- Attendee Management ---
|
|
1315
|
-
|
|
1316
|
-
// Update an attendee (link to a contact, etc.)
|
|
1317
|
-
const { attendee } = await client.meetings.updateAttendee('meeting_123', 'attendee_123', {
|
|
1318
|
-
name: 'John Doe',
|
|
1319
|
-
email: 'john@acme.com',
|
|
1320
|
-
contactId: 'contact_123',
|
|
1321
|
-
});
|
|
1322
|
-
|
|
1323
|
-
// Update by external ID instead of attendee ID
|
|
1324
|
-
const { attendee } = await client.meetings.updateAttendee('meeting_123', 'A', {
|
|
1325
|
-
contactId: 'contact_123',
|
|
1326
|
-
}, { useExternalId: true });
|
|
1327
|
-
|
|
1328
|
-
// --- AI Task Suggestions ---
|
|
1329
|
-
|
|
1330
|
-
// Accept an AI-generated task suggestion (with optional overrides)
|
|
1331
|
-
const { task, suggestion } = await client.meetings.acceptTaskSuggestion('meeting_123', 'suggestion_123', {
|
|
1332
|
-
title: 'Custom task title',
|
|
1333
|
-
assigneeId: 'user_123',
|
|
1334
|
-
priority: 'high',
|
|
1335
|
-
});
|
|
1336
|
-
|
|
1337
|
-
// Dismiss a task suggestion
|
|
1338
|
-
await client.meetings.dismissTaskSuggestion('meeting_123', 'suggestion_123');
|
|
1339
|
-
```
|
|
1340
|
-
|
|
1341
|
-
### AI Agent Runs
|
|
1342
|
-
|
|
1343
|
-
Execute AI agents and poll for results:
|
|
1344
|
-
|
|
1345
|
-
```typescript
|
|
1346
|
-
// Create an agent run (returns immediately with 202 Accepted)
|
|
1347
|
-
const { run } = await client.aiAgentRuns.create('agent_123', {
|
|
1348
|
-
input: { customerId: 'cust_123' },
|
|
1349
|
-
context: 'Analyze this customer for churn risk',
|
|
1350
|
-
variables: { tone: 'professional' },
|
|
1351
|
-
});
|
|
1352
|
-
console.log(run.status); // 'pending'
|
|
1353
|
-
|
|
1354
|
-
// Check the run status
|
|
1355
|
-
const { run } = await client.aiAgentRuns.retrieve('agent_123', run.id);
|
|
1356
|
-
console.log(run.status); // 'pending' | 'running' | 'completed' | 'error'
|
|
1357
|
-
|
|
1358
|
-
// Convenience: create and wait for completion (polls automatically)
|
|
1359
|
-
const completedRun = await client.aiAgentRuns.createAndWait('agent_123', {
|
|
1360
|
-
input: { query: 'Summarize recent activity' },
|
|
1361
|
-
}, {
|
|
1362
|
-
timeout: 60000, // Max wait time in ms (default: 30000)
|
|
1363
|
-
pollInterval: 2000, // Polling interval in ms (default: 1000)
|
|
1364
|
-
});
|
|
1365
|
-
console.log(completedRun.response);
|
|
1366
|
-
console.log(completedRun.structuredResponse);
|
|
1367
|
-
console.log(completedRun.tokenUsage);
|
|
1368
|
-
```
|
|
1369
|
-
|
|
1370
|
-
### Custom Data
|
|
1371
|
-
|
|
1372
|
-
Set and retrieve custom data fields on resources:
|
|
1373
|
-
|
|
1374
|
-
```typescript
|
|
1375
|
-
// Supported resource types: 'ticket' | 'customer' | 'contact' | 'deal' | 'conversation'
|
|
52
|
+
// Cursor-based pagination
|
|
53
|
+
if (hasNextPage) {
|
|
54
|
+
const nextPage = await client.customers.list({ take: 25, cursor });
|
|
55
|
+
}
|
|
1376
56
|
|
|
1377
|
-
//
|
|
1378
|
-
await client.
|
|
1379
|
-
resourceId: 'cust_123',
|
|
1380
|
-
resourceType: 'customer',
|
|
1381
|
-
key: 'industry',
|
|
1382
|
-
value: 'Technology',
|
|
1383
|
-
});
|
|
57
|
+
// Get a customer
|
|
58
|
+
const { customer } = await client.customers.retrieve('cust_123');
|
|
1384
59
|
|
|
1385
|
-
//
|
|
1386
|
-
const
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
key: 'industry',
|
|
60
|
+
// Update a customer
|
|
61
|
+
const { customer } = await client.customers.update('cust_123', {
|
|
62
|
+
name: 'Acme Corporation',
|
|
63
|
+
tags: ['enterprise', 'vip'],
|
|
1390
64
|
});
|
|
1391
|
-
console.log(data.value); // 'Technology'
|
|
1392
65
|
|
|
1393
|
-
// Delete a
|
|
1394
|
-
await client.
|
|
1395
|
-
resourceId: 'cust_123',
|
|
1396
|
-
resourceType: 'customer',
|
|
1397
|
-
key: 'industry',
|
|
1398
|
-
});
|
|
66
|
+
// Delete a customer
|
|
67
|
+
await client.customers.del('cust_123');
|
|
1399
68
|
```
|
|
1400
69
|
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
Organize customers and contacts into lists:
|
|
70
|
+
## Configuration Options
|
|
1404
71
|
|
|
1405
72
|
```typescript
|
|
1406
|
-
|
|
1407
|
-
const { lists, hasNextPage } = await client.lists.list({
|
|
1408
|
-
all: true, // Include all lists without pagination
|
|
1409
|
-
});
|
|
1410
|
-
|
|
1411
|
-
// Retrieve a list with its entities
|
|
1412
|
-
const { list, entities, hasNextPage } = await client.lists.retrieve('list_123', {
|
|
1413
|
-
page: 0,
|
|
1414
|
-
take: 25,
|
|
1415
|
-
type: 'customer', // Filter by entity type: 'customer' | 'contact'
|
|
1416
|
-
search: 'acme',
|
|
1417
|
-
sort: 'name',
|
|
1418
|
-
sortDirection: 'asc',
|
|
1419
|
-
});
|
|
73
|
+
import { MantleCoreClient } from '@heymantle/core-api-client';
|
|
1420
74
|
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
description: 'Top-tier enterprise customers',
|
|
1425
|
-
});
|
|
75
|
+
const client = new MantleCoreClient({
|
|
76
|
+
// Required: one of apiKey or accessToken
|
|
77
|
+
apiKey: 'your-api-key',
|
|
1426
78
|
|
|
1427
|
-
//
|
|
1428
|
-
|
|
1429
|
-
name: 'Updated Name',
|
|
1430
|
-
});
|
|
79
|
+
// Optional: custom base URL (defaults to https://api.heymantle.com/v1)
|
|
80
|
+
baseURL: 'https://api.heymantle.com/v1',
|
|
1431
81
|
|
|
1432
|
-
//
|
|
1433
|
-
|
|
82
|
+
// Optional: request timeout in ms (defaults to 30000)
|
|
83
|
+
timeout: 30000,
|
|
1434
84
|
|
|
1435
|
-
//
|
|
1436
|
-
|
|
1437
|
-
customerIds: ['cust_123', 'cust_456'],
|
|
1438
|
-
contactIds: ['contact_123'],
|
|
85
|
+
// Optional: override the fetch implementation
|
|
86
|
+
fetchFn: customFetch,
|
|
1439
87
|
});
|
|
1440
88
|
|
|
1441
|
-
//
|
|
1442
|
-
|
|
1443
|
-
customerIds: ['cust_456'],
|
|
1444
|
-
});
|
|
89
|
+
// Update authentication at runtime
|
|
90
|
+
client.updateAuth({ accessToken: 'new-token' });
|
|
1445
91
|
```
|
|
1446
92
|
|
|
1447
|
-
###
|
|
93
|
+
### Custom fetch — JWT sessions with `@heymantle/app-bridge-react`
|
|
1448
94
|
|
|
1449
|
-
|
|
95
|
+
If you're building a Mantle app and want API calls to be authenticated via JWT session rather than an API key, you can pass the `authenticatedFetch` function from [`@heymantle/app-bridge-react`](https://www.npmjs.com/package/@heymantle/app-bridge-react) as the `fetchFn` override:
|
|
1450
96
|
|
|
1451
97
|
```typescript
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
customerId: 'cust_123',
|
|
1455
|
-
// or contactId: 'contact_123',
|
|
1456
|
-
});
|
|
1457
|
-
|
|
1458
|
-
// Retrieve a comment
|
|
1459
|
-
const { timelineComment } = await client.timelineComments.retrieve('comment_123');
|
|
1460
|
-
|
|
1461
|
-
// Create a comment with attachments and tagged users
|
|
1462
|
-
const { timelineComment } = await client.timelineComments.create({
|
|
1463
|
-
customerId: 'cust_123',
|
|
1464
|
-
body: 'Discussed renewal terms with @John',
|
|
1465
|
-
attachments: [
|
|
1466
|
-
{ filename: 'notes.pdf', url: 'https://storage.example.com/notes.pdf' },
|
|
1467
|
-
],
|
|
1468
|
-
taggedUsers: [
|
|
1469
|
-
{ userId: 'user_123' },
|
|
1470
|
-
],
|
|
1471
|
-
});
|
|
98
|
+
import { MantleCoreClient } from '@heymantle/core-api-client';
|
|
99
|
+
import { useAuthenticatedFetch } from '@heymantle/app-bridge-react';
|
|
1472
100
|
|
|
1473
|
-
|
|
1474
|
-
const
|
|
1475
|
-
body: 'Updated comment text',
|
|
1476
|
-
});
|
|
101
|
+
function useClient() {
|
|
102
|
+
const authenticatedFetch = useAuthenticatedFetch();
|
|
1477
103
|
|
|
1478
|
-
|
|
1479
|
-
|
|
104
|
+
return new MantleCoreClient({
|
|
105
|
+
fetchFn: authenticatedFetch,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
1480
108
|
```
|
|
1481
109
|
|
|
1482
|
-
|
|
110
|
+
This ensures every request made by the SDK is routed through the app bridge's authenticated fetch, automatically attaching the session token.
|
|
1483
111
|
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
```typescript
|
|
1487
|
-
// List journal entries
|
|
1488
|
-
const { journalEntries, hasNextPage } = await client.journalEntries.list({
|
|
1489
|
-
appId: 'app_123',
|
|
1490
|
-
startDate: '2024-01-01',
|
|
1491
|
-
endDate: '2024-12-31',
|
|
1492
|
-
tags: ['release', 'update'],
|
|
1493
|
-
});
|
|
1494
|
-
|
|
1495
|
-
// Retrieve a journal entry
|
|
1496
|
-
const { journalEntry } = await client.journalEntries.retrieve('entry_123');
|
|
1497
|
-
|
|
1498
|
-
// Create a journal entry
|
|
1499
|
-
const { journalEntry } = await client.journalEntries.create({
|
|
1500
|
-
date: '2024-01-15',
|
|
1501
|
-
title: 'v2.0 Release',
|
|
1502
|
-
description: 'Major release with new billing features',
|
|
1503
|
-
appId: 'app_123',
|
|
1504
|
-
tags: ['release'],
|
|
1505
|
-
url: 'https://changelog.example.com/v2',
|
|
1506
|
-
emoji: '🚀',
|
|
1507
|
-
});
|
|
1508
|
-
|
|
1509
|
-
// Update a journal entry
|
|
1510
|
-
const { journalEntry } = await client.journalEntries.update('entry_123', {
|
|
1511
|
-
description: 'Updated description',
|
|
1512
|
-
});
|
|
1513
|
-
|
|
1514
|
-
// Delete a journal entry
|
|
1515
|
-
await client.journalEntries.del('entry_123');
|
|
1516
|
-
```
|
|
112
|
+
## Middleware
|
|
1517
113
|
|
|
1518
|
-
|
|
114
|
+
The client supports Koa-style middleware for intercepting requests and responses. Middleware can be used for logging, authentication refresh, retry logic, and more.
|
|
1519
115
|
|
|
1520
|
-
|
|
116
|
+
### Creating Custom Middleware
|
|
1521
117
|
|
|
1522
118
|
```typescript
|
|
1523
|
-
|
|
1524
|
-
const { unsubscribeGroups } = await client.emailUnsubscribeGroups.list();
|
|
1525
|
-
|
|
1526
|
-
// Retrieve an unsubscribe group
|
|
1527
|
-
const { unsubscribeGroup } = await client.emailUnsubscribeGroups.retrieve('group_123');
|
|
119
|
+
import { MantleCoreClient, type Middleware } from '@heymantle/core-api-client';
|
|
1528
120
|
|
|
1529
|
-
|
|
1530
|
-
const
|
|
121
|
+
const loggingMiddleware: Middleware = async (ctx, next) => {
|
|
122
|
+
const start = Date.now();
|
|
123
|
+
console.log(`[Request] ${ctx.request.method} ${ctx.request.url}`);
|
|
1531
124
|
|
|
1532
|
-
|
|
1533
|
-
const result = await client.emailUnsubscribeGroups.addMembers('group_123', {
|
|
1534
|
-
emails: ['user1@example.com', 'user2@example.com'],
|
|
1535
|
-
});
|
|
125
|
+
await next();
|
|
1536
126
|
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
});
|
|
127
|
+
const duration = Date.now() - start;
|
|
128
|
+
console.log(`[Response] ${ctx.response?.status} (${duration}ms)`);
|
|
129
|
+
};
|
|
1541
130
|
|
|
1542
|
-
|
|
1543
|
-
|
|
131
|
+
const client = new MantleCoreClient({ apiKey: 'your-api-key' });
|
|
132
|
+
client.use(loggingMiddleware, { name: 'logging', priority: 10 });
|
|
1544
133
|
```
|
|
1545
134
|
|
|
1546
|
-
###
|
|
135
|
+
### Auth Refresh Middleware
|
|
1547
136
|
|
|
1548
|
-
|
|
137
|
+
Automatically refresh expired access tokens:
|
|
1549
138
|
|
|
1550
139
|
```typescript
|
|
1551
|
-
|
|
1552
|
-
const { actions, hasNextPage } = await client.flowExtensions.listActions({
|
|
1553
|
-
enabled: true,
|
|
1554
|
-
});
|
|
1555
|
-
|
|
1556
|
-
// Retrieve an action
|
|
1557
|
-
const { action } = await client.flowExtensions.retrieveAction('action_123');
|
|
1558
|
-
|
|
1559
|
-
// Create a custom action
|
|
1560
|
-
const { action } = await client.flowExtensions.createAction({
|
|
1561
|
-
name: 'Send Slack Notification',
|
|
1562
|
-
description: 'Posts a message to a Slack channel',
|
|
1563
|
-
key: 'send_slack_notification',
|
|
1564
|
-
schema: {
|
|
1565
|
-
channel: { type: 'string', required: true },
|
|
1566
|
-
message: { type: 'string', required: true },
|
|
1567
|
-
},
|
|
1568
|
-
callbackUrl: 'https://your-app.com/flow-actions/slack',
|
|
1569
|
-
enabled: true,
|
|
1570
|
-
});
|
|
1571
|
-
|
|
1572
|
-
// Update an action
|
|
1573
|
-
const { action } = await client.flowExtensions.updateAction('action_123', {
|
|
1574
|
-
description: 'Updated description',
|
|
1575
|
-
enabled: false,
|
|
1576
|
-
});
|
|
140
|
+
import { MantleCoreClient, createAuthRefreshMiddleware } from '@heymantle/core-api-client';
|
|
1577
141
|
|
|
1578
|
-
|
|
1579
|
-
await client.flowExtensions.deleteAction('action_123');
|
|
142
|
+
const client = new MantleCoreClient({ accessToken: 'initial-token' });
|
|
1580
143
|
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
144
|
+
client.use(
|
|
145
|
+
createAuthRefreshMiddleware({
|
|
146
|
+
refreshToken: async () => {
|
|
147
|
+
const response = await fetch('/api/refresh', { method: 'POST' });
|
|
148
|
+
const data = await response.json();
|
|
149
|
+
return data.accessToken;
|
|
150
|
+
},
|
|
151
|
+
onRefreshSuccess: (newToken) => {
|
|
152
|
+
localStorage.setItem('accessToken', newToken);
|
|
153
|
+
},
|
|
154
|
+
onRefreshFailed: (error) => {
|
|
155
|
+
window.location.href = '/login';
|
|
156
|
+
},
|
|
157
|
+
}),
|
|
158
|
+
{ name: 'auth-refresh' }
|
|
159
|
+
);
|
|
1586
160
|
```
|
|
1587
161
|
|
|
1588
|
-
|
|
162
|
+
### Rate Limit Middleware
|
|
1589
163
|
|
|
1590
|
-
|
|
164
|
+
The API enforces rate limits: 1,000 requests/minute and 5,000 requests/5 minutes. Use the built-in middleware:
|
|
1591
165
|
|
|
1592
166
|
```typescript
|
|
1593
|
-
|
|
1594
|
-
await client.customers.list({ take: 25 });
|
|
167
|
+
import { createRateLimitMiddleware } from '@heymantle/core-api-client';
|
|
1595
168
|
|
|
1596
|
-
//
|
|
1597
|
-
|
|
1598
|
-
const nextPage = await client.customers.list({ take: 25, cursor });
|
|
1599
|
-
}
|
|
169
|
+
// Auto-retry on 429 responses
|
|
170
|
+
client.use(createRateLimitMiddleware({ enableRetry: true }));
|
|
1600
171
|
|
|
1601
|
-
//
|
|
1602
|
-
|
|
172
|
+
// Preemptive throttling to avoid hitting limits
|
|
173
|
+
client.use(createRateLimitMiddleware({ enableThrottle: true }));
|
|
1603
174
|
```
|
|
1604
175
|
|
|
1605
176
|
## Error Handling
|
|
@@ -1618,252 +189,21 @@ try {
|
|
|
1618
189
|
await client.customers.retrieve('invalid_id');
|
|
1619
190
|
} catch (error) {
|
|
1620
191
|
if (error instanceof MantleAuthenticationError) {
|
|
1621
|
-
// Handle authentication error (401)
|
|
1622
192
|
console.log('Please re-authenticate');
|
|
1623
193
|
} else if (error instanceof MantlePermissionError) {
|
|
1624
|
-
// Handle permission error (403)
|
|
1625
194
|
console.log('Access denied');
|
|
1626
195
|
} else if (error instanceof MantleNotFoundError) {
|
|
1627
|
-
// Handle not found error (404)
|
|
1628
196
|
console.log('Resource not found');
|
|
1629
197
|
} else if (error instanceof MantleValidationError) {
|
|
1630
|
-
// Handle validation error (422)
|
|
1631
198
|
console.log('Validation failed:', error.details);
|
|
1632
199
|
} else if (error instanceof MantleRateLimitError) {
|
|
1633
|
-
// Handle rate limit (429)
|
|
1634
200
|
console.log(`Rate limited. Retry after: ${error.retryAfter}s`);
|
|
1635
201
|
} else if (error instanceof MantleAPIError) {
|
|
1636
|
-
// Handle other API errors
|
|
1637
202
|
console.log(`Error ${error.statusCode}: ${error.message}`);
|
|
1638
203
|
}
|
|
1639
204
|
}
|
|
1640
205
|
```
|
|
1641
206
|
|
|
1642
|
-
## TypeScript Support
|
|
1643
|
-
|
|
1644
|
-
All types are exported for use in your application:
|
|
1645
|
-
|
|
1646
|
-
```typescript
|
|
1647
|
-
import type {
|
|
1648
|
-
// Client config
|
|
1649
|
-
MantleCoreClientConfig,
|
|
1650
|
-
PaginatedResponse,
|
|
1651
|
-
ListParams,
|
|
1652
|
-
DeleteResponse,
|
|
1653
|
-
|
|
1654
|
-
// Customers
|
|
1655
|
-
Customer,
|
|
1656
|
-
CustomerListParams,
|
|
1657
|
-
CustomerListResponse,
|
|
1658
|
-
CustomerCreateParams,
|
|
1659
|
-
CustomerUpdateParams,
|
|
1660
|
-
AccountOwner,
|
|
1661
|
-
CustomField,
|
|
1662
|
-
|
|
1663
|
-
// Contacts
|
|
1664
|
-
Contact,
|
|
1665
|
-
ContactCreateParams,
|
|
1666
|
-
ContactCreateResponse,
|
|
1667
|
-
SocialProfile,
|
|
1668
|
-
SocialProfileType,
|
|
1669
|
-
|
|
1670
|
-
// Deals
|
|
1671
|
-
Deal,
|
|
1672
|
-
DealListParams,
|
|
1673
|
-
DealListResponse,
|
|
1674
|
-
DealCreateParams,
|
|
1675
|
-
DealUpdateParams,
|
|
1676
|
-
DealCustomerInput,
|
|
1677
|
-
DealContactInput,
|
|
1678
|
-
DealFlow,
|
|
1679
|
-
DealStage,
|
|
1680
|
-
DealActivity,
|
|
1681
|
-
DealEvent,
|
|
1682
|
-
DealEventCreateParams,
|
|
1683
|
-
|
|
1684
|
-
// Subscriptions
|
|
1685
|
-
Subscription,
|
|
1686
|
-
|
|
1687
|
-
// Tickets
|
|
1688
|
-
Ticket,
|
|
1689
|
-
TicketMessage,
|
|
1690
|
-
TicketCreateParams,
|
|
1691
|
-
Channel,
|
|
1692
|
-
|
|
1693
|
-
// Apps
|
|
1694
|
-
App,
|
|
1695
|
-
Plan,
|
|
1696
|
-
PlanCreateParams,
|
|
1697
|
-
Feature,
|
|
1698
|
-
UsageMetric,
|
|
1699
|
-
Review,
|
|
1700
|
-
AppEvent,
|
|
1701
|
-
|
|
1702
|
-
// Affiliates
|
|
1703
|
-
Affiliate,
|
|
1704
|
-
AffiliateProgram,
|
|
1705
|
-
AffiliateCommission,
|
|
1706
|
-
AffiliatePayout,
|
|
1707
|
-
AffiliateReferral,
|
|
1708
|
-
|
|
1709
|
-
// Meetings
|
|
1710
|
-
Meeting,
|
|
1711
|
-
MeetingAttendee,
|
|
1712
|
-
MeetingTranscript,
|
|
1713
|
-
MeetingUtterance,
|
|
1714
|
-
MeetingCreateParams,
|
|
1715
|
-
MeetingUpdateParams,
|
|
1716
|
-
MeetingUploadUrlResponse,
|
|
1717
|
-
MeetingTranscriptionStatusResponse,
|
|
1718
|
-
MeetingKeyPoint,
|
|
1719
|
-
MeetingDecision,
|
|
1720
|
-
MeetingOpenQuestion,
|
|
1721
|
-
MeetingTopic,
|
|
1722
|
-
SentimentDataPoint,
|
|
1723
|
-
MeetingDealInsights,
|
|
1724
|
-
MeetingTaskSuggestion,
|
|
1725
|
-
AcceptTaskSuggestionParams,
|
|
1726
|
-
AcceptTaskSuggestionResponse,
|
|
1727
|
-
|
|
1728
|
-
// AI Agents
|
|
1729
|
-
AgentRun,
|
|
1730
|
-
AgentRunStatus,
|
|
1731
|
-
AgentRunTokenUsage,
|
|
1732
|
-
AgentRunCreateParams,
|
|
1733
|
-
|
|
1734
|
-
// Tasks
|
|
1735
|
-
Task,
|
|
1736
|
-
TaskStatus,
|
|
1737
|
-
TaskPriority,
|
|
1738
|
-
TaskCreateParams,
|
|
1739
|
-
TaskUpdateResponse,
|
|
1740
|
-
DealProgression,
|
|
1741
|
-
TodoItem,
|
|
1742
|
-
TodoItemCreateParams,
|
|
1743
|
-
TodoItemUpdateParams,
|
|
1744
|
-
|
|
1745
|
-
// Lists
|
|
1746
|
-
List,
|
|
1747
|
-
ListEntity,
|
|
1748
|
-
ListCreateParams,
|
|
1749
|
-
ListAddEntitiesParams,
|
|
1750
|
-
ListRemoveEntitiesParams,
|
|
1751
|
-
|
|
1752
|
-
// Timeline Comments
|
|
1753
|
-
TimelineComment,
|
|
1754
|
-
TimelineCommentCreateParams,
|
|
1755
|
-
TimelineCommentAttachmentInput,
|
|
1756
|
-
TimelineCommentTaggedUserInput,
|
|
1757
|
-
|
|
1758
|
-
// Journal Entries
|
|
1759
|
-
JournalEntry,
|
|
1760
|
-
JournalEntryCreateParams,
|
|
1761
|
-
|
|
1762
|
-
// Documentation
|
|
1763
|
-
DocCollection,
|
|
1764
|
-
DocGroup,
|
|
1765
|
-
DocPage,
|
|
1766
|
-
DocPageStatus,
|
|
1767
|
-
DocTreeNode,
|
|
1768
|
-
DocTreeResponse,
|
|
1769
|
-
DocRepository,
|
|
1770
|
-
|
|
1771
|
-
// Entities (unified search)
|
|
1772
|
-
Entity,
|
|
1773
|
-
EntityType,
|
|
1774
|
-
ContactEntity,
|
|
1775
|
-
CustomerEntity,
|
|
1776
|
-
EntitiesSearchParams,
|
|
1777
|
-
|
|
1778
|
-
// Custom Data
|
|
1779
|
-
CustomDataResourceType,
|
|
1780
|
-
CustomDataSetParams,
|
|
1781
|
-
CustomDataResponse,
|
|
1782
|
-
|
|
1783
|
-
// Email
|
|
1784
|
-
EmailUnsubscribeGroup,
|
|
1785
|
-
EmailUnsubscribeGroupMember,
|
|
1786
|
-
|
|
1787
|
-
// Flow Extensions
|
|
1788
|
-
FlowExtensionAction,
|
|
1789
|
-
FlowActionRun,
|
|
1790
|
-
FlowActionRunStatus,
|
|
1791
|
-
|
|
1792
|
-
// Flows
|
|
1793
|
-
Flow,
|
|
1794
|
-
FlowStatus,
|
|
1795
|
-
|
|
1796
|
-
// Metrics
|
|
1797
|
-
DateRangeType,
|
|
1798
|
-
MetricType,
|
|
1799
|
-
MetricsResponse,
|
|
1800
|
-
SalesMetrics,
|
|
1801
|
-
SalesMetricsResponse,
|
|
1802
|
-
|
|
1803
|
-
// Organizations & Users
|
|
1804
|
-
Organization,
|
|
1805
|
-
User,
|
|
1806
|
-
Agent,
|
|
1807
|
-
|
|
1808
|
-
// Companies
|
|
1809
|
-
Company,
|
|
1810
|
-
|
|
1811
|
-
// Customer Segments
|
|
1812
|
-
CustomerSegment,
|
|
1813
|
-
|
|
1814
|
-
// Webhooks
|
|
1815
|
-
Webhook,
|
|
1816
|
-
WebhookTopic,
|
|
1817
|
-
|
|
1818
|
-
// Usage Events
|
|
1819
|
-
UsageEvent,
|
|
1820
|
-
UsageEventCreateParams,
|
|
1821
|
-
|
|
1822
|
-
// Transactions & Charges
|
|
1823
|
-
Transaction,
|
|
1824
|
-
Charge,
|
|
1825
|
-
|
|
1826
|
-
// Middleware
|
|
1827
|
-
Middleware,
|
|
1828
|
-
MiddlewareContext,
|
|
1829
|
-
MiddlewareOptions,
|
|
1830
|
-
} from '@heymantle/core-api-client';
|
|
1831
|
-
```
|
|
1832
|
-
|
|
1833
|
-
## Configuration Options
|
|
1834
|
-
|
|
1835
|
-
```typescript
|
|
1836
|
-
import { MantleCoreClient, type Middleware } from '@heymantle/core-api-client';
|
|
1837
|
-
|
|
1838
|
-
const client = new MantleCoreClient({
|
|
1839
|
-
// Required: one of apiKey or accessToken
|
|
1840
|
-
apiKey: 'your-api-key',
|
|
1841
|
-
// OR
|
|
1842
|
-
accessToken: 'your-oauth-token',
|
|
1843
|
-
|
|
1844
|
-
// Optional: custom base URL (defaults to https://api.heymantle.com/v1)
|
|
1845
|
-
baseURL: 'https://api.heymantle.com/v1',
|
|
1846
|
-
|
|
1847
|
-
// Optional: request timeout in ms (defaults to 30000)
|
|
1848
|
-
timeout: 30000,
|
|
1849
|
-
|
|
1850
|
-
// Optional: middleware to register on instantiation
|
|
1851
|
-
middleware: [
|
|
1852
|
-
loggingMiddleware,
|
|
1853
|
-
[authRefreshMiddleware, { name: 'auth', priority: 1 }],
|
|
1854
|
-
],
|
|
1855
|
-
});
|
|
1856
|
-
|
|
1857
|
-
// Update authentication at runtime
|
|
1858
|
-
client.updateAuth({ accessToken: 'new-token' });
|
|
1859
|
-
|
|
1860
|
-
// Add middleware at runtime
|
|
1861
|
-
client.use(newMiddleware, { name: 'custom', priority: 50 });
|
|
1862
|
-
|
|
1863
|
-
// Remove middleware by name
|
|
1864
|
-
client.removeMiddleware('custom');
|
|
1865
|
-
```
|
|
1866
|
-
|
|
1867
207
|
## License
|
|
1868
208
|
|
|
1869
209
|
MIT
|