npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@heymantle/core-api-client

v0.1.13

Published

TypeScript SDK for the Mantle Core API

Readme

@heymantle/core-api-client

A TypeScript SDK for the Mantle Core API. Built with a resource-based architecture similar to the Stripe SDK.

Installation

npm install @heymantle/core-api-client

Quick Start

import { MantleCoreClient } from '@heymantle/core-api-client';

const client = new MantleCoreClient({
  apiKey: 'your-api-key',
});

// List customers
const { customers, hasNextPage } = await client.customers.list({ take: 25 });

// Get a specific customer
const { customer } = await client.customers.retrieve('cust_123');

Authentication

The client supports two authentication methods:

// API Key (for server-side use)
const client = new MantleCoreClient({
  apiKey: 'your-api-key',
});

// OAuth Access Token
const client = new MantleCoreClient({
  accessToken: 'your-oauth-token',
});

Middleware

The client supports Koa-style middleware for intercepting requests and responses. Middleware can be used for logging, authentication refresh, retry logic, and more.

Creating Custom Middleware

import { MantleCoreClient, type Middleware } from '@heymantle/core-api-client';

// Logging middleware
const loggingMiddleware: Middleware = async (ctx, next) => {
  const start = Date.now();
  console.log(`[Request] ${ctx.request.method} ${ctx.request.url}`);

  await next();

  const duration = Date.now() - start;
  console.log(`[Response] ${ctx.response?.status} (${duration}ms)`);
};

// Register middleware
const client = new MantleCoreClient({ apiKey: 'your-api-key' });
client.use(loggingMiddleware, { name: 'logging', priority: 10 });

Auth Refresh Middleware

Automatically refresh expired access tokens:

import { MantleCoreClient, createAuthRefreshMiddleware } from '@heymantle/core-api-client';

const client = new MantleCoreClient({
  accessToken: 'initial-token',
});

client.use(
  createAuthRefreshMiddleware({
    refreshToken: async () => {
      // Call your token refresh endpoint
      const response = await fetch('/api/refresh', { method: 'POST' });
      const data = await response.json();
      return data.accessToken;
    },
    onRefreshSuccess: (newToken) => {
      // Persist the new token
      localStorage.setItem('accessToken', newToken);
    },
    onRefreshFailed: (error) => {
      // Redirect to login
      window.location.href = '/login';
    },
    maxRefreshAttempts: 1,
  }),
  { name: 'auth-refresh' }
);

Middleware at Construction

const client = new MantleCoreClient({
  apiKey: 'your-api-key',
  middleware: [
    loggingMiddleware,
    [retryMiddleware, { name: 'retry', priority: 5 }],
  ],
});

Middleware Context

interface MiddlewareContext<T = unknown> {
  request: {
    url: string;
    method: 'GET' | 'POST' | 'PUT' | 'DELETE';
    headers: Record<string, string>;
    body?: string;
    endpoint: string;
  };
  response?: {
    data: T;
    status: number;
    headers: Headers;
  };
  error?: Error;
  retry: boolean;           // Set to true to retry the request
  retryCount: number;
  maxRetries: number;
  updateAuth: (credentials: { apiKey?: string; accessToken?: string }) => void;
}

Resources

Customers

// List customers with filters
const { customers, hasNextPage, total } = await client.customers.list({
  take: 25,
  search: 'acme',
  appIds: ['app_123'],
  shopifyShopDomain: 'store.myshopify.com',
  shopifyShopId: '12345',
  includeUsageMetrics: true,
  includeContactCount: true,
  sort: 'createdAt',
  sortDirection: 'desc',
});

// Retrieve a customer
const { customer } = await client.customers.retrieve('cust_123', {
  includeContactCount: true,
  includeCurrentInvoice: true,
});

// Create a customer
const { customer } = await client.customers.create({
  name: 'Acme Inc',
  email: '[email protected]',
  domain: 'acme.com',
  shopifyDomain: 'acme.myshopify.com',
  shopifyShopId: '12345',
  countryCode: 'US',
  preferredCurrency: 'USD',
  description: 'Enterprise customer',
  tags: ['enterprise', 'priority'],
  customFields: { industry: 'Technology', employees: 500 },
  companyId: 'company_123',
  appInstallations: [
    { appId: 'app_123', installedAt: '2024-01-15T00:00:00Z', test: false },
  ],
});

// Update a customer
const { customer } = await client.customers.update('cust_123', {
  name: 'Acme Corporation',
  tags: ['enterprise', 'vip'],
});

// Add/remove tags
await client.customers.addTags('cust_123', ['premium', 'partner']);
await client.customers.removeTags('cust_123', ['trial']);

// Timeline events
const { events, hasNextPage } = await client.customers.getTimeline('cust_123', {
  appId: 'app_123',
  type: 'subscription.created',
  limit: 50,
  cursor: 'cursor_abc',
});

// Account owners
const { accountOwners } = await client.customers.listAccountOwners('cust_123');
const { accountOwner } = await client.customers.addAccountOwner('cust_123', {
  email: '[email protected]',
  name: 'John Owner',
});
await client.customers.removeAccountOwner('cust_123', 'owner_123');

// Custom fields
const { customFields } = await client.customers.listCustomFields({ appId: 'app_123' });
const { customField } = await client.customers.createCustomField({
  appId: 'app_123',
  name: 'Industry',
  type: 'select', // 'string' | 'number' | 'boolean' | 'date' | 'select'
  options: ['Technology', 'Healthcare', 'Finance', 'Retail'],
  defaultValue: 'Technology',
  showOnCustomerDetail: true,
  filterable: true,
  private: false,
});
const { customField } = await client.customers.retrieveCustomField('field_123');
const { customField } = await client.customers.updateCustomField('field_123', {
  name: 'Industry Type',
  options: ['Technology', 'Healthcare', 'Finance', 'Retail', 'Other'],
});
await client.customers.deleteCustomField('field_123');

Contacts

// List contacts
const { contacts, hasNextPage } = await client.contacts.list({
  take: 25,
  search: 'john',
  socialProfileType: 'linkedin', // 'linkedin' | 'x' | 'facebook' | 'instagram' | 'website'
  socialProfileUrl: 'https://linkedin.com/in/johndoe',
});

// Create or update a contact (upsert by email)
// If a contact with the same email exists, it will be updated
const { contact, created } = await client.contacts.create({
  name: 'John Doe',
  email: '[email protected]',
  phone: '+1-555-123-4567',
  jobTitle: 'CTO',
  notes: 'Primary technical contact',
  tags: ['decision-maker', 'technical'],
  customers: ['cust_123', 'cust_456'],
  socialProfiles: [
    { key: 'linkedin', value: 'https://linkedin.com/in/johndoe' },
    { key: 'x', value: 'https://x.com/johndoe' },
    { key: 'website', value: 'https://johndoe.com' },
  ],
});
console.log(created ? 'New contact created' : 'Existing contact updated');

// Update a contact
const { contact } = await client.contacts.update('contact_123', {
  jobTitle: 'VP of Engineering',
  socialProfiles: [
    { key: 'linkedin', value: 'https://linkedin.com/in/johndoe-updated' },
  ],
});

// Retrieve a contact
const { contact } = await client.contacts.retrieve('contact_123');

Subscriptions

// List subscriptions
const { subscriptions, hasNextPage } = await client.subscriptions.list({
  appId: 'app_123',
  customerId: 'cust_123',
  active: true,
  ids: ['sub_123', 'sub_456'],
  startDate: '2024-01-01',
  endDate: '2024-12-31',
});

// Retrieve a subscription
const { subscription } = await client.subscriptions.retrieve('sub_123');

Deals

Deals support multiple ways to link customers and contacts:

// List deals with filters
const { deals, hasNextPage, total } = await client.deals.list({
  customerId: 'cust_123',
  appId: 'app_123',
  planId: 'plan_123',
  dealStageId: 'stage_123',
  dealFlowId: 'flow_123',
  affiliateId: 'aff_123',
  partnershipId: 'partner_123',
  acquirerId: 'user_123',
  ownerId: 'user_456',
  contactId: 'contact_123',
  stage: 'negotiation',
  minAmount: 1000,
  maxAmount: 50000,
  acquisitionChannel: 'inbound',
  acquisitionSource: 'website',
  includeArchived: false,
});

// Create a deal - Option 1: Link existing customer
const { deal } = await client.deals.create({
  name: 'Enterprise Deal',
  amount: 50000,
  amountCurrencyCode: 'USD',
  customerId: 'cust_123',
  contactIds: ['contact_123', 'contact_456'],
  dealFlowId: 'flow_123',
  dealStageId: 'stage_123',
  appId: 'app_123',
  planId: 'plan_456',
  ownerIds: ['user_123'],
  acquisitionChannel: 'outbound',
  acquisitionSource: 'sales_call',
  firstInteractionAt: '2024-01-15T10:00:00Z',
  closingAt: '2024-03-01T00:00:00Z',
  notes: 'High priority enterprise deal',
});

// Create a deal - Option 2: Create/update customer inline
const { deal } = await client.deals.create({
  name: 'New Prospect Deal',
  amount: 25000,
  // Customer will be matched by domain or created if not found
  customer: {
    name: 'Acme Corp',
    email: '[email protected]',
    domain: 'acme.com',
    shopifyDomain: 'acme.myshopify.com',
    shopifyShopId: '12345',
    tags: ['prospect'],
    countryCode: 'US',
    preferredCurrency: 'USD',
  },
  // Contacts will be matched by email or created if not found
  contacts: [
    {
      email: '[email protected]',
      name: 'John Doe',
      phone: '+1-555-123-4567',
      jobTitle: 'CEO',
      label: 'primary',
      notes: 'Decision maker',
      tags: ['executive'],
    },
    {
      email: '[email protected]',
      name: 'Jane Smith',
      jobTitle: 'CTO',
      label: 'technical',
    },
  ],
  dealFlowId: 'flow_123',
  dealStageId: 'stage_123',
});

// Create a deal - Option 3: Find/create customer by domain
const { deal } = await client.deals.create({
  name: 'Domain-based Deal',
  shopifyDomain: 'newstore.myshopify.com',
  dealFlowId: 'flow_123',
  dealStageId: 'stage_123',
});

// Update a deal
const { deal } = await client.deals.update('deal_123', {
  amount: 75000,
  dealStageId: 'stage_456',
  closedAt: '2024-02-15T00:00:00Z',
  notes: 'Deal closed successfully!',
});

// Archive a deal
await client.deals.del('deal_123');

// Get deal timeline
const { events } = await client.deals.getTimeline('deal_123');

// Get deal events
const { events } = await client.deals.getEvents('deal_123');

Deal Flows

Manage deal pipelines and stages:

// List deal flows
const { dealFlows } = await client.dealFlows.list();

// Retrieve a deal flow with stages
const { dealFlow } = await client.dealFlows.retrieve('flow_123');
// dealFlow.stages contains the ordered stages

// Create a deal flow
const { dealFlow } = await client.dealFlows.create({
  name: 'Enterprise Sales Pipeline',
  description: 'For deals over $10k',
});

// Update a deal flow
const { dealFlow } = await client.dealFlows.update('flow_123', {
  name: 'Enterprise Sales Pipeline v2',
});

// Delete a deal flow
await client.dealFlows.del('flow_123');

Deal Activities

Track activities within deal flows:

// List deal activities
const { dealActivities } = await client.dealActivities.list();

// Retrieve a deal activity
const { dealActivity } = await client.dealActivities.retrieve('activity_123');

// Create a deal activity
const { dealActivity } = await client.dealActivities.create({
  name: 'Initial Call',
  dealFlowId: 'flow_123',
  description: 'First discovery call with prospect',
  order: 1,
});

// Update a deal activity
const { dealActivity } = await client.dealActivities.update('activity_123', {
  name: 'Discovery Call',
  description: 'Updated description',
});

// Delete a deal activity
await client.dealActivities.del('activity_123');

Apps

// List apps
const { apps } = await client.apps.list({
  minUpdatedAt: '2024-01-01T00:00:00Z',
  maxUpdatedAt: '2024-12-31T23:59:59Z',
});

// Retrieve an app
const { app } = await client.apps.retrieve('app_123');

Plans

// List plans for an app
const { plans, total, hasMore } = await client.apps.listPlans('app_123', {
  public: true,
  page: 0,
  perPage: 25,
  search: 'pro',
});

// Retrieve a plan
const { plan } = await client.apps.retrievePlan('app_123', 'plan_123');

// Create a plan with usage charges and features
const { plan } = await client.apps.createPlan('app_123', {
  name: 'Pro Plan',
  description: 'For growing businesses',
  amount: 4900, // $49.00
  currencyCode: 'USD',
  interval: 'month', // 'month' | 'year' | 'one_time'
  trialDays: 14,
  public: true,
  visible: true,
  customerTags: ['premium'],
  customerExcludeTags: ['churned'],
  shopifyPlans: ['shopify', 'advanced'],
  flexBilling: true,
  flexBillingTerms: 'Charged at end of billing period',
  // Usage-based pricing
  planUsageCharges: [
    {
      usageMetricId: 'metric_123',
      cappedAmount: 10000, // $100 cap
      terms: '$0.01 per API call',
      interval: 'month',
    },
  ],
  // Feature flags
  features: [
    { featureId: 'feature_api', value: true },
    { featureId: 'feature_seats', value: 10 },
  ],
  customFields: { tier: 'mid' },
});

// Update a plan
const { plan } = await client.apps.updatePlan('app_123', 'plan_123', {
  amount: 5900,
  description: 'Updated description',
});

// Archive/unarchive a plan
await client.apps.archivePlan('app_123', 'plan_123');
await client.apps.unarchivePlan('app_123', 'plan_123');

Features

// List features
const { features } = await client.apps.listFeatures('app_123');

// Retrieve a feature
const { feature } = await client.apps.retrieveFeature('app_123', 'feature_123');

// Create a feature
const { feature } = await client.apps.createFeature('app_123', {
  name: 'API Access',
  type: 'boolean', // 'boolean' | 'limit' | 'unlimited'
  description: 'Access to REST API',
  usageMetricId: 'metric_123', // Link to usage tracking
});

// Update a feature
const { feature } = await client.apps.updateFeature('app_123', 'feature_123', {
  name: 'API Access v2',
  description: 'Updated description',
});

// Delete a feature
await client.apps.deleteFeature('app_123', 'feature_123');

Usage Metrics

// List usage metrics
const { usageMetrics } = await client.apps.listUsageMetrics('app_123');

// Retrieve a usage metric
const { usageMetric } = await client.apps.retrieveUsageMetric('app_123', 'metric_123');

// Create a usage metric
const { usageMetric } = await client.apps.createUsageMetric('app_123', {
  name: 'API Calls',
  description: 'Number of API requests',
  eventName: 'api_call',
  aggregationType: 'count',
});

// Update a usage metric
const { usageMetric } = await client.apps.updateUsageMetric('app_123', 'metric_123', {
  name: 'API Requests',
});

// Delete a usage metric
await client.apps.deleteUsageMetric('app_123', 'metric_123');

// Get event names for an app
const { eventNames } = await client.apps.listEventNames('app_123');

// Get property keys for an event
const { propertyKeys } = await client.apps.listPropertyKeys('app_123', 'api_call');

App Events

// List app events
const { appEvents, hasNextPage } = await client.apps.listAppEvents('app_123', {
  customerId: 'cust_123',
  take: 50,
});

Reviews

// List reviews
const { reviews } = await client.apps.listReviews('app_123');

// Retrieve a review
const { review } = await client.apps.retrieveReview('app_123', 'review_123');

// Create a review
const { review } = await client.apps.createReview('app_123', {
  rating: 5,
  title: 'Excellent app!',
  body: 'This app transformed our workflow.',
});

// Update a review
const { review } = await client.apps.updateReview('app_123', 'review_123', {
  rating: 4,
  body: 'Updated review text',
});

// Delete a review
await client.apps.deleteReview('app_123', 'review_123');

Tickets

// List tickets with filters
const { tickets, hasNextPage, total } = await client.tickets.list({
  status: 'open', // 'open' | 'pending' | 'resolved' | 'closed'
  priority: 'high', // 'low' | 'medium' | 'high' | 'urgent'
  assignedToId: 'user_123',
  appId: 'app_123',
  customerId: 'cust_123',
  contactId: 'contact_123',
  channelId: 'channel_123',
  tags: ['billing', 'urgent'],
  take: 25,
});

// Retrieve a ticket
const { ticket } = await client.tickets.retrieve('ticket_123');

// Create a ticket - Option 1: Link existing contact
const { ticket } = await client.tickets.create({
  subject: 'Need help with integration',
  status: 'open',
  priority: 'medium',
  customerId: 'cust_123',
  contactId: 'contact_123',
  appId: 'app_123',
  channelId: 'channel_123',
  assignedToId: 'user_123',
  tags: ['integration', 'api'],
});

// Create a ticket - Option 2: Create contact inline
const { ticket } = await client.tickets.create({
  subject: 'Billing question',
  priority: 'high',
  customerId: 'cust_123',
  contact: {
    email: '[email protected]',
    name: 'Support User',
  },
});

// Update a ticket
const { ticket } = await client.tickets.update('ticket_123', {
  status: 'pending',
  priority: 'urgent',
  assignedToId: 'user_456',
  tags: ['escalated'],
});

// Delete a ticket
await client.tickets.del('ticket_123');

// List messages for a ticket
const { messages } = await client.tickets.listMessages('ticket_123');

// Retrieve a message
const { message } = await client.tickets.retrieveMessage('ticket_123', 'message_123');

// Create a message with attachments
const { message } = await client.tickets.createMessage('ticket_123', {
  body: 'Here is the solution to your problem...',
  from: 'agent', // 'customer' | 'agent'
  attachments: [
    {
      filename: 'solution.pdf',
      url: 'https://storage.example.com/solution.pdf',
      contentType: 'application/pdf',
      size: 102400,
    },
  ],
});

// Update a message
const { message } = await client.tickets.updateMessage('ticket_123', 'message_123', {
  body: 'Updated message content',
});

// Delete a message
await client.tickets.deleteMessage('ticket_123', 'message_123');

Channels

Manage CX channels for tickets:

// List channels
const { channels } = await client.channels.list({
  type: 'email', // 'email' | 'chat'
});

// Create a channel
const { channel } = await client.channels.create({
  type: 'email',
  name: 'Support Email',
});

Agents

List support agents:

// List agents
const { agents } = await client.agents.list();

Metrics

Retrieve analytics and business metrics:

import type { DateRangeType } from '@heymantle/core-api-client';

// Date range options:
// 'last_30_minutes' | 'last_60_minutes' | 'last_12_hours' | 'last_24_hours'
// 'last_7_days' | 'last_14_days' | 'last_30_days' | 'last_90_days'
// 'last_12_months' | 'last_24_months'
// 'today' | 'yesterday' | 'last_month'
// 'month_to_date' | 'quarter_to_date' | 'year_to_date'
// 'all_time' | 'custom'

// Monthly Recurring Revenue
const mrr = await client.metrics.mrr({
  appId: 'app_123',
  dateRange: 'last_30_days',
});
console.log(mrr.total, mrr.formattedTotal); // 50000, "$500.00"
console.log(mrr.change, mrr.changePercentage); // 5000, 10

// Annual Recurring Revenue
const arr = await client.metrics.arr({ appId: 'app_123' });

// Average Revenue Per User
const arpu = await client.metrics.arpu({ appId: 'app_123' });

// Customer Lifetime Value
const ltv = await client.metrics.ltv({ appId: 'app_123' });

// Predicted LTV
const predictedLtv = await client.metrics.predictedLtv({ appId: 'app_123' });

// Revenue Churn
const revenueChurn = await client.metrics.revenueChurn({ appId: 'app_123' });

// Logo (Customer) Churn
const logoChurn = await client.metrics.logoChurn({ appId: 'app_123' });

// Revenue Retention
const revenueRetention = await client.metrics.revenueRetention({ appId: 'app_123' });

// Net Revenue Retention
const nrr = await client.metrics.netRevenueRetention({ appId: 'app_123' });

// Net Revenue
const netRevenue = await client.metrics.netRevenue({ appId: 'app_123' });

// Active Subscriptions
const activeSubs = await client.metrics.activeSubscriptions({ appId: 'app_123' });

// Active Installs
const activeInstalls = await client.metrics.activeInstalls({ appId: 'app_123' });

// Net Installs
const netInstalls = await client.metrics.netInstalls({ appId: 'app_123' });

// Charges
const charges = await client.metrics.charges({ appId: 'app_123' });

// Payout
const payout = await client.metrics.payout({ appId: 'app_123' });

// Usage event metrics
const usageMetrics = await client.metrics.usageEvent({
  appId: 'app_123',
  eventName: 'api_call',
  propertyKey: 'endpoint',
  aggregation: 'count', // 'count' | 'sum' | 'avg' | 'min' | 'max'
  dateRange: 'last_7_days',
});

// Usage metric by ID
const metricData = await client.metrics.usageMetric({
  appId: 'app_123',
  metricId: 'metric_123',
  dateRange: 'last_30_days',
});

// Custom metric query
const data = await client.metrics.fetch({
  metric: 'PlatformApp.activeInstalls',
  appId: 'app_123',
  dateRange: 'last_90_days',
  startDate: '2024-01-01',
  endDate: '2024-03-31',
  includes: ['includeTotal'],
  appEventsForMrr: true,
});

Usage Events

Track customer usage for billing:

// List usage events
const { usageEvents, hasNextPage } = await client.usageEvents.list({
  appId: 'app_123',
  customerId: 'cust_123',
  eventName: 'api_call',
  billingStatus: 'unbilled',
  countryCode: 'US',
  startDate: '2024-01-01',
  endDate: '2024-01-31',
  propertiesFilters: { endpoint: '/users' },
});

// Track a single event
await client.usageEvents.create({
  eventName: 'api_call',
  customerId: 'cust_123',
  appId: 'app_123',
  timestamp: new Date().toISOString(),
  eventId: 'unique-event-id', // For deduplication
  properties: { endpoint: '/users', method: 'GET', responseTime: 150 },
  private: false,
});

// Track multiple events
await client.usageEvents.create({
  events: [
    { eventName: 'api_call', customerId: 'cust_123', appId: 'app_123' },
    { eventName: 'api_call', customerId: 'cust_456', appId: 'app_123' },
    { eventName: 'file_upload', customerId: 'cust_123', appId: 'app_123', properties: { size: 1024 } },
  ],
});

Webhooks

// List webhooks
const { webhooks } = await client.webhooks.list();

// Retrieve a webhook
const { webhook } = await client.webhooks.retrieve('webhook_123');

// Create a webhook
const { webhook } = await client.webhooks.create({
  topic: 'customer.created',
  address: 'https://your-app.com/webhooks',
});

// Update a webhook
const { webhook } = await client.webhooks.update('webhook_123', {
  address: 'https://your-app.com/webhooks/v2',
});

// Delete a webhook
await client.webhooks.del('webhook_123');

Affiliates

// List affiliates
const { affiliates, hasNextPage } = await client.affiliates.list({
  affiliateProgramId: 'program_123',
  status: 'active', // 'pending' | 'active' | 'rejected' | 'suspended'
  appId: 'app_123',
  email: '[email protected]',
});

// Retrieve an affiliate
const { affiliate } = await client.affiliates.retrieve('affiliate_123');

// Update an affiliate
const { affiliate } = await client.affiliates.update('affiliate_123', {
  status: 'active',
  commissionRate: 0.25, // 25%
});

Affiliate Programs

// List affiliate programs
const { affiliatePrograms } = await client.affiliatePrograms.list();

// Retrieve an affiliate program
const { affiliateProgram } = await client.affiliatePrograms.retrieve('program_123');

// Create an affiliate program
const { affiliateProgram } = await client.affiliatePrograms.create({
  name: 'Partner Program',
  description: 'Earn 20% commission on referrals',
  commissionType: 'percentage', // 'percentage' | 'fixed'
  commissionValue: 20,
  commissionDurationMonths: 12,
  cookieDurationDays: 30,
  minimumPayoutAmount: 5000, // $50.00
  payoutCurrency: 'USD',
  active: true,
});

// Update an affiliate program
const { affiliateProgram } = await client.affiliatePrograms.update('program_123', {
  commissionValue: 25,
});

// Delete an affiliate program
await client.affiliatePrograms.del('program_123');

Affiliate Commissions

// List commissions
const { commissions, hasNextPage } = await client.affiliateCommissions.list({
  affiliateId: 'affiliate_123',
  status: 'pending', // 'pending' | 'approved' | 'paid' | 'rejected'
});

// Retrieve a commission
const { commission } = await client.affiliateCommissions.retrieve('commission_123');

// Update a commission
const { commission } = await client.affiliateCommissions.update('commission_123', {
  status: 'approved',
});

Affiliate Payouts

// List payouts
const { payouts, hasNextPage } = await client.affiliatePayouts.list({
  affiliateId: 'affiliate_123',
  status: 'completed', // 'pending' | 'processing' | 'completed' | 'failed'
});

// Retrieve a payout
const { payout } = await client.affiliatePayouts.retrieve('payout_123');

// Create a payout
const { payout } = await client.affiliatePayouts.create({
  affiliateId: 'affiliate_123',
  amount: 10000, // $100.00
  currencyCode: 'USD',
});

Affiliate Referrals

// List referrals
const { referrals, hasNextPage } = await client.affiliateReferrals.list({
  affiliateId: 'affiliate_123',
  status: 'converted', // 'pending' | 'converted' | 'expired'
});

// Retrieve a referral
const { referral } = await client.affiliateReferrals.retrieve('referral_123');

Companies

// List companies
const { companies, hasNextPage } = await client.companies.list({
  take: 25,
  search: 'acme',
});

// Retrieve a company
const { company } = await client.companies.retrieve('company_123');

// Create a company
const { company } = await client.companies.create({
  name: 'Acme Holdings',
  domain: 'acme.com',
});

// Update a company
const { company } = await client.companies.update('company_123', {
  name: 'Acme Holdings Inc',
});

// Delete a company
await client.companies.del('company_123');

Customer Segments

// List customer segments
const { customerSegments } = await client.customerSegments.list();

// Retrieve a segment
const { customerSegment } = await client.customerSegments.retrieve('segment_123');

// Create a segment
const { customerSegment } = await client.customerSegments.create({
  name: 'Enterprise Customers',
  filters: { lifetimeValue: { gte: 10000 } },
});

// Update a segment
const { customerSegment } = await client.customerSegments.update('segment_123', {
  name: 'Enterprise Customers (Updated)',
});

// Delete a segment
await client.customerSegments.del('segment_123');

Tasks

// List tasks
const { tasks, hasNextPage } = await client.tasks.list({
  status: 'pending',
  assignedToId: 'user_123',
  customerId: 'cust_123',
});

// Retrieve a task
const { task } = await client.tasks.retrieve('task_123');

// Create a task
const { task } = await client.tasks.create({
  title: 'Follow up with customer',
  description: 'Discuss renewal options',
  dueAt: '2024-02-15T10:00:00Z',
  assignedToId: 'user_123',
  customerId: 'cust_123',
});

// Update a task
const { task } = await client.tasks.update('task_123', {
  status: 'completed',
});

// Delete a task
await client.tasks.del('task_123');

Flows (Automation)

// List flows
const { flows } = await client.flows.list();

// Retrieve a flow
const { flow } = await client.flows.retrieve('flow_123');

// Create a flow
const { flow } = await client.flows.create({
  name: 'Onboarding Flow',
  trigger: 'customer.created',
  actions: [
    { type: 'email', template: 'welcome' },
  ],
});

// Update a flow
const { flow } = await client.flows.update('flow_123', {
  name: 'Updated Onboarding Flow',
  enabled: true,
});

// Delete a flow
await client.flows.del('flow_123');

Transactions & Charges

// List transactions
const { transactions, hasNextPage } = await client.transactions.list({
  customerId: 'cust_123',
  appId: 'app_123',
});

// Retrieve a transaction
const { transaction } = await client.transactions.retrieve('txn_123');

// List charges
const { charges, hasNextPage } = await client.charges.list({
  customerId: 'cust_123',
  appId: 'app_123',
});

// Retrieve a charge
const { charge } = await client.charges.retrieve('charge_123');

Users

// List users in the organization
const { users } = await client.users.list();

// Retrieve a user
const { user } = await client.users.retrieve('user_123');

Me & Organization

// Get current user and organization
const { user, organization } = await client.me.retrieve();

// Get organization details
const { organization } = await client.organization.retrieve();

Documentation

// List documentation collections
const { collections } = await client.docs.listCollections();

// Retrieve a collection
const { collection } = await client.docs.retrieveCollection('collection_123');

// List documentation pages
const { pages } = await client.docs.listPages({
  collectionId: 'collection_123',
});

// Retrieve a page
const { page } = await client.docs.retrievePage('page_123');

// Create a page
const { page } = await client.docs.createPage({
  title: 'Getting Started',
  content: '# Getting Started\n\nWelcome to our docs...',
  collectionId: 'collection_123',
});

// Update a page
const { page } = await client.docs.updatePage('page_123', {
  content: 'Updated content',
});

// Delete a page
await client.docs.deletePage('page_123');

Entities

Generic entity management:

// List entities
const { entities } = await client.entities.list({
  type: 'custom_entity',
});

// Retrieve an entity
const { entity } = await client.entities.retrieve('entity_123');

// Create an entity
const { entity } = await client.entities.create({
  type: 'custom_entity',
  data: { field1: 'value1' },
});

// Update an entity
const { entity } = await client.entities.update('entity_123', {
  data: { field1: 'updated_value' },
});

// Delete an entity
await client.entities.del('entity_123');

Pagination

All list methods return pagination metadata:

const { customers, hasNextPage, hasPreviousPage, cursor, total } =
  await client.customers.list({ take: 25 });

// Cursor-based pagination (recommended)
if (hasNextPage) {
  const nextPage = await client.customers.list({ take: 25, cursor });
}

// Offset-based pagination
const page2 = await client.customers.list({ take: 25, page: 1 });

Error Handling

import {
  MantleAPIError,
  MantleAuthenticationError,
  MantlePermissionError,
  MantleValidationError,
  MantleRateLimitError,
} from '@heymantle/core-api-client';

try {
  await client.customers.retrieve('invalid_id');
} catch (error) {
  if (error instanceof MantleAuthenticationError) {
    // Handle authentication error (401)
    console.log('Please re-authenticate');
  } else if (error instanceof MantlePermissionError) {
    // Handle permission error (403)
    console.log('Access denied');
  } else if (error instanceof MantleValidationError) {
    // Handle validation error (422)
    console.log('Validation failed:', error.details);
  } else if (error instanceof MantleRateLimitError) {
    // Handle rate limit (429)
    console.log(`Rate limited. Retry after: ${error.retryAfter}s`);
  } else if (error instanceof MantleAPIError) {
    // Handle other API errors
    console.log(`Error ${error.statusCode}: ${error.message}`);
  }
}

TypeScript Support

All types are exported for use in your application:

import type {
  // Client config
  MantleCoreClientConfig,

  // Entities
  Customer,
  Contact,
  Deal,
  Subscription,
  Ticket,
  TicketMessage,
  App,
  Plan,
  Feature,
  Affiliate,
  AffiliateProgram,
  AffiliateCommission,
  AffiliatePayout,
  AffiliateReferral,

  // Params
  CustomerCreateParams,
  CustomerUpdateParams,
  CustomerListParams,
  DealCreateParams,
  DealCustomerInput,
  DealContactInput,
  TicketCreateParams,
  PlanCreateParams,

  // Responses
  CustomerListResponse,
  DealListResponse,
  MetricsResponse,
  PaginatedResponse,

  // Enums/Types
  DateRangeType,
  MetricType,
  SocialProfileType,

  // Middleware
  Middleware,
  MiddlewareContext,
  MiddlewareOptions,
} from '@heymantle/core-api-client';

Configuration Options

import { MantleCoreClient, type Middleware } from '@heymantle/core-api-client';

const client = new MantleCoreClient({
  // Required: one of apiKey or accessToken
  apiKey: 'your-api-key',
  // OR
  accessToken: 'your-oauth-token',

  // Optional: custom base URL (defaults to https://api.heymantle.com/v1)
  baseURL: 'https://api.heymantle.com/v1',

  // Optional: request timeout in ms (defaults to 30000)
  timeout: 30000,

  // Optional: middleware to register on instantiation
  middleware: [
    loggingMiddleware,
    [authRefreshMiddleware, { name: 'auth', priority: 1 }],
  ],
});

// Update authentication at runtime
client.updateAuth({ accessToken: 'new-token' });

// Add middleware at runtime
client.use(newMiddleware, { name: 'custom', priority: 50 });

// Remove middleware by name
client.removeMiddleware('custom');

License

MIT