npm package: @marginfront/sdk
Description: Official Node.js SDK for MarginFront - usage-based billing, invoicing, and analytics
Author: MarginFront
Latest version: 0.5.0

# @marginfront/sdk

[![npm version](https://badge.fury.io/js/%40marginfront%2Fsdk.svg)](https://badge.fury.io/js/%40marginfront%2Fsdk)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

Official Node.js SDK for MarginFront. Simplify integration with MarginFront's billing, customer management, and usage tracking services.

## Installation

```bash
npm install @marginfront/sdk
# or
yarn add @marginfront/sdk
```

## Quick Start

```typescript
import { MarginFrontClient } from '@marginfront/sdk';

const client = new MarginFrontClient('mf_sk_your_secret_key');

// Track a usage event
await client.trackEvent({
  agentCode: 'agent_123',
  customerExternalId: 'customer_456',
  signalName: 'api_call',
  quantity: 1,
});
```

## Documentation

- [Configuration Options](#configuration)
- [Event Tracking Examples](#event-tracking)
- [Usage Cost Tracking](#usage-cost-tracking)
- [Customer Management](#customer-management)
- [Error Handling](#error-handling)
- [Advanced Features](#advanced-features)

## Configuration

```typescript
const client = new MarginFrontClient('mf_sk_your_secret_key', {
  baseUrl: 'https://api.marginfront.com/v1',
  timeout: 10000,
  retries: 3,
  retryDelay: 300,
  logging: {
    enabled: true,
    level: 'info',
  },
  telemetry: {
    enabled: true,
    sampleRate: 1,
  },
});

await client.connect();
```

## Usage Examples

### Event Tracking

```typescript
// Simple event tracking
await client.trackEvent({
  agentCode: 'agent_123',
  customerExternalId: 'customer_456',
  signalName: 'api_call',
  quantity: 1,
});

// Event with metadata and usage cost tracking
await client.trackEvent({
  agentCode: 'agent_123',
  customerExternalId: 'customer_456',
  signalName: 'email_sent',
  quantity: 1,
  metadata: {
    eventId: 'email_sent',
    usageCost: [
      {
        serviceName: 'LLM',
        units: 7,
      },
      {
        serviceName: 'Intuit',
        units: 1,
      },
    ],
  },
});

// Batch tracking
await client.trackEvent({
  records: [
    {
      customerExternalId: 'customer_456',
      agentCode: 'agent_123',
      signalName: 'api_call',
      quantity: 10,
      metadata: {
        endpoint: '/api/v1/search',
      },
    },
    {
      customerExternalId: 'customer_789',
      agentCode: 'agent_123',
      signalName: 'storage',
      quantity: 100,
      usageDate: new Date('2023-08-15'),
      metadata: {
        storageType: 'object',
      },
    },
  ],
});
```

### Usage Cost Tracking

Track detailed cost breakdown through the `usageCost` field in metadata:

```typescript
await client.trackEvent({
  agentCode: 'agent_123',
  customerExternalId: 'customer_456',
  signalName: 'lead_generated',
  quantity: 1,
  metadata: {
    eventId: 'lead_generated',
    usageCost: [
      {
        serviceName: 'wfloengine',
        units: 1,
      },
    ],
  },
});
```

The `usageCost` field structure:

| Field       | Type   | Description                              |
| ----------- | ------ | ---------------------------------------- |
| serviceName | string | Name of the service (e.g., 'LLM', 'TTS') |
| units       | number | Number of units consumed                 |

### Customer Management

```typescript
// Create a customer
const customer = await client.customers.create({
  name: 'Acme Corp',
  email: 'billing@acmecorp.com',
  externalId: 'acme-123',
});

// List customers
const customers = await client.customers.list({
  limit: 10,
  page: 1,
});

// Get, update and delete customers
const customer = await client.customers.get('customer_id');
await client.customers.update('customer_id', { name: 'Updated Name' });
await client.customers.delete('customer_id');
```

### Invoices

```typescript
// List invoices with filters
const { invoices, totalResults } = await client.invoices.list({
  customerId: 'cust_123',
  status: 'pending',
  page: 1,
  limit: 20,
});

// Get a specific invoice
const invoice = await client.invoices.get('inv_abc');
console.log(`Invoice ${invoice.invoiceNumber}: $${invoice.totalAmount}`);
```

### Analytics

```typescript
const analytics = await client.analytics.usage({
  startDate: '2024-01-01',
  endDate: '2024-01-31',
  groupBy: 'daily',
  customerId: 'cust_123',
});

console.log(`Total usage: ${analytics.summary.totalQuantity}`);
console.log(`Total cost: $${analytics.summary.totalCost}`);

// Time series data
analytics.data.forEach((point) => {
  console.log(`${point.date}: ${point.quantity} units, $${point.cost}`);
});
```

### Subscriptions

```typescript
// List subscriptions
const { subscriptions } = await client.subscriptions.list({
  status: 'active',
  customerId: 'cust_123',
});

// Get subscription with usage details
const sub = await client.subscriptions.get('sub_abc');
console.log(`Usage this period: ${sub.usage.totalQuantity}`);
```

### Portal Sessions

```typescript
// Create a portal session (requires secret key mf_sk_*)
const session = await client.portalSessions.create({
  customerId: 'cust_123',
  returnUrl: 'https://myapp.com/account',
  features: ['invoices', 'usage', 'subscriptions'],
});

// Redirect customer to the portal
res.redirect(session.url);
```

## Error Handling

```typescript
import {
  MarginFrontClient,
  MarginFrontError,
  AuthenticationError,
  RateLimitError,
  ValidationError,
} from '@marginfront/sdk';

try {
  await client.connect();
  await client.trackEvent({
    /* ... */
  });
} catch (error) {
  if (error instanceof AuthenticationError) {
    console.error(`Authentication failed. Request ID: ${error.requestId}`);
  } else if (error instanceof RateLimitError) {
    console.error(`Rate limit exceeded. Retry after ${error.retryAfter}s`);
  } else if (error instanceof ValidationError) {
    console.error(`Validation error: ${error.message}`);
  } else if (error instanceof MarginFrontError) {
    console.error(`API Error (${error.statusCode}): ${error.message}`);
  }
}
```

## Advanced Features

### Request Retries

```typescript
const client = new MarginFrontClient('mf_sk_your_secret_key', {
  retries: 3,
  retryDelay: 300,
});
```

### Logging & Telemetry

The SDK includes a telemetry system that tracks API request performance and usage patterns:

```typescript
const client = new MarginFrontClient('mf_sk_your_secret_key', {
  logging: {
    enabled: true,
    level: 'debug',
    handler: (level, message, data) => {
      myLoggingSystem.log(level, message, data);
    },
  },
  telemetry: {
    enabled: true,
    sampleRate: 0.5, // Track 50% of requests
    handler: (metrics) => {
      myMonitoringSystem.trackApiRequest(metrics);
    },
  },
});
```

You can access telemetry statistics programmatically:

```typescript
// Get current statistics
const stats = client.getTelemetryStats();
console.log(`Total Requests: ${stats.requestCount}`);
console.log(`Success Rate: ${(stats.successRate * 100).toFixed(2)}%`);
```


## CLI (Testing Tool)

The SDK ships with a lightweight CLI (`mf`) for testing your integration without writing code.

> **Note:** The CLI is a testing tool only. It has no effect on the SDK when used as a library in your application.

### Install globally

```bash
npm install -g @marginfront/sdk
```

Then run commands from anywhere:

```bash
mf verify
mf track-event --customer-id customer-1 --agent-code my-agent --signal CALL_MINUTES --quantity 10
```

### Commands

#### `mf verify`

Verifies your API key and returns organization details.

```bash
mf verify [options]

Options:
  --api-key <key>    API key (mf_sk_* or mf_pk_*)
  --base-url <url>   API base URL (default: https://api.marginfront.com/v1)
  --debug            Enable debug output
```

#### `mf track-event`

Sends a single usage event to the API.

```bash
mf track-event [options]

Options:
  --api-key <key>      API key (mf_sk_*)
  --base-url <url>     API base URL (default: https://api.marginfront.com/v1)
  --customer-id <id>   Customer external ID
  --agent-code <code>  Agent code (external ID set in the UI)
  --signal <name>      Signal name (e.g. CALL_MINUTES)
  --quantity <number>  Quantity to record (default: 1)
  --metadata <json>    Optional metadata as a JSON string
  --debug              Enable debug output
```

### Default values via `.env.marginfront.cli`

To avoid repeating flags, create a `.env.marginfront.cli` file in the directory where you run the CLI. Any value set here is used as a default and can be overridden by passing the flag directly.

```env
# ⚠️  FOR TESTING ONLY
# This file is NOT used when the SDK is imported as a library.
# It only applies when running the mf CLI.

MF_API_KEY=mf_sk_your_key_here
MF_BASE_URL=http://localhost:4000/v1
MF_AGENT_CODE=your-agent-code
MF_CUSTOMER_ID=customer-1
MF_SIGNAL=CALL_MINUTES
MF_QUANTITY=10
MF_DEBUG=false
```

**Priority:** CLI flags > `.env.marginfront.cli` > built-in defaults

| CLI Flag        | `.env` Key        |
|-----------------|-------------------|
| `--api-key`     | `MF_API_KEY`      |
| `--base-url`    | `MF_BASE_URL`     |
| `--customer-id` | `MF_CUSTOMER_ID`  |
| `--agent-code`  | `MF_AGENT_CODE`   |
| `--signal`      | `MF_SIGNAL`       |
| `--quantity`    | `MF_QUANTITY`     |
| `--debug`       | `MF_DEBUG`        |

Add `.env.marginfront.cli` to your `.gitignore` to avoid committing test credentials.

## License

MIT License. See [LICENSE](./LICENSE) for details.