@heymantle/core-api-client 0.2.1 → 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.
Files changed (2) hide show
  1. package/README.md +92 -1752
  2. 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
- ### Flows (Automation)
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
- ### Transactions & Charges
23
+ The client supports two authentication methods:
1135
24
 
1136
25
  ```typescript
1137
- // List transactions
1138
- const { transactions, hasNextPage } = await client.transactions.list({
1139
- customerId: 'cust_123',
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
- // Retrieve a transaction
1144
- const { transaction } = await client.transactions.retrieve('txn_123');
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
- ### Users
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
- ### Entities
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
- Unified search across contacts and customers:
41
+ ### Customers
1226
42
 
1227
43
  ```typescript
1228
- // Search entities (returns contacts and customers in a single result set)
1229
- const { entities, hasNextPage } = await client.entities.search({
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
- // Each entity has a _type discriminator
1235
- entities.forEach((entity) => {
1236
- if (entity._type === 'customer') {
1237
- console.log('Customer:', entity.name, entity.domain);
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
- // Set a custom data value
1378
- await client.customData.set({
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
- // Get a custom data value
1386
- const data = await client.customData.getValue({
1387
- resourceId: 'cust_123',
1388
- resourceType: 'customer',
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 custom data value
1394
- await client.customData.del({
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
- ### Lists
1402
-
1403
- Organize customers and contacts into lists:
70
+ ## Configuration Options
1404
71
 
1405
72
  ```typescript
1406
- // List all lists
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
- // Create a list
1422
- const { list } = await client.lists.create({
1423
- name: 'Enterprise Accounts',
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
- // Update a list
1428
- const { list } = await client.lists.update('list_123', {
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
- // Delete a list
1433
- await client.lists.del('list_123');
82
+ // Optional: request timeout in ms (defaults to 30000)
83
+ timeout: 30000,
1434
84
 
1435
- // Add entities to a list
1436
- const { added, skipped } = await client.lists.addEntities('list_123', {
1437
- customerIds: ['cust_123', 'cust_456'],
1438
- contactIds: ['contact_123'],
85
+ // Optional: override the fetch implementation
86
+ fetchFn: customFetch,
1439
87
  });
1440
88
 
1441
- // Remove entities from a list
1442
- const { removed } = await client.lists.removeEntities('list_123', {
1443
- customerIds: ['cust_456'],
1444
- });
89
+ // Update authentication at runtime
90
+ client.updateAuth({ accessToken: 'new-token' });
1445
91
  ```
1446
92
 
1447
- ### Timeline Comments
93
+ ### Custom fetch — JWT sessions with `@heymantle/app-bridge-react`
1448
94
 
1449
- Add comments to customer and contact timelines:
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
- // List timeline comments
1453
- const { timelineComments, hasNextPage } = await client.timelineComments.list({
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
- // Update a comment
1474
- const { timelineComment } = await client.timelineComments.update('comment_123', {
1475
- body: 'Updated comment text',
1476
- });
101
+ function useClient() {
102
+ const authenticatedFetch = useAuthenticatedFetch();
1477
103
 
1478
- // Delete a comment
1479
- await client.timelineComments.del('comment_123');
104
+ return new MantleCoreClient({
105
+ fetchFn: authenticatedFetch,
106
+ });
107
+ }
1480
108
  ```
1481
109
 
1482
- ### Journal Entries
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
- Track journal entries for apps:
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
- ### Email Unsubscribe Groups
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
- Manage email unsubscribe groups and their members:
116
+ ### Creating Custom Middleware
1521
117
 
1522
118
  ```typescript
1523
- // List unsubscribe groups
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
- // List members of a group
1530
- const { members, hasNextPage } = await client.emailUnsubscribeGroups.listMembers('group_123');
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
- // Add members to a group
1533
- const result = await client.emailUnsubscribeGroups.addMembers('group_123', {
1534
- emails: ['user1@example.com', 'user2@example.com'],
1535
- });
125
+ await next();
1536
126
 
1537
- // Remove multiple members
1538
- await client.emailUnsubscribeGroups.removeMembers('group_123', {
1539
- emails: ['user1@example.com'],
1540
- });
127
+ const duration = Date.now() - start;
128
+ console.log(`[Response] ${ctx.response?.status} (${duration}ms)`);
129
+ };
1541
130
 
1542
- // Remove a single member by ID
1543
- await client.emailUnsubscribeGroups.removeMember('group_123', 'member_123');
131
+ const client = new MantleCoreClient({ apiKey: 'your-api-key' });
132
+ client.use(loggingMiddleware, { name: 'logging', priority: 10 });
1544
133
  ```
1545
134
 
1546
- ### Flow Extensions
135
+ ### Auth Refresh Middleware
1547
136
 
1548
- Extend automation flows with custom actions:
137
+ Automatically refresh expired access tokens:
1549
138
 
1550
139
  ```typescript
1551
- // List flow extension actions
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
- // Delete an action
1579
- await client.flowExtensions.deleteAction('action_123');
142
+ const client = new MantleCoreClient({ accessToken: 'initial-token' });
1580
143
 
1581
- // Update a flow action run status (called from your callback handler)
1582
- const { run } = await client.flowExtensions.updateActionRun('run_123', {
1583
- status: 'completed', // 'pending' | 'running' | 'completed' | 'failed'
1584
- output: { messageId: 'slack_msg_123' },
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
- ## Pagination
162
+ ### Rate Limit Middleware
1589
163
 
1590
- All list methods return pagination metadata:
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
- const { customers, hasNextPage, hasPreviousPage, cursor, total } =
1594
- await client.customers.list({ take: 25 });
167
+ import { createRateLimitMiddleware } from '@heymantle/core-api-client';
1595
168
 
1596
- // Cursor-based pagination (recommended)
1597
- if (hasNextPage) {
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
- // Offset-based pagination
1602
- const page2 = await client.customers.list({ take: 25, page: 1 });
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