> ## Documentation Index
> Fetch the complete documentation index at: https://docs.marginfront.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Customers

> Create, update, list, and fetch customers. Plus getWithRevenue for detail pages.

# Customers

The customers resource handles the usual create, read, update, delete, plus one method built for customer detail pages: `getWithRevenue`. It fetches the customer record AND their revenue numbers for a time window in one round trip.

This page covers:

1. Creating a customer
2. Listing customers
3. Getting one customer
4. Updating a customer
5. Deleting a customer
6. Getting a customer with their revenue numbers attached

***

## Setup

```typescript theme={null}
import { MarginFrontClient } from "@marginfront/sdk";

const mf = new MarginFrontClient(process.env.MF_API_SECRET_KEY);
```

***

## `customers.create`

Creates a new customer. If you pass `agentCode`, MarginFront also auto-creates a subscription between the customer and that agent.

### Signature

```typescript theme={null}
await mf.customers.create(params: CreateCustomerData): Promise<Customer>
```

### Example

```typescript theme={null}
const customer = await mf.customers.create({
  name: "Acme Corp",
  externalId: "acme-001",
  email: "billing@acme.com",
  agentCode: "cs-bot-v2", // optional: auto-creates a subscription
});
```

See the [Customers API reference](/api-reference/customers) for the full field list.

***

## `customers.list`

Returns a paginated list of customers with optional filters.

### Signature

```typescript theme={null}
await mf.customers.list(params?: CustomerListParams): Promise<CustomerListResponse | Customer[]>
```

### Example

```typescript theme={null}
const { data, totalResults, hasMore } = await mf.customers.list({
  limit: 20,
  page: 1,
});

for (const customer of data) {
  console.log(`${customer.name} (${customer.externalId})`);
}
```

***

## `customers.get`

Fetches one customer by id, including their subscriptions.

### Signature

```typescript theme={null}
await mf.customers.get(id: string): Promise<Customer>
```

### Example

```typescript theme={null}
const customer = await mf.customers.get("c4e8d1a2-1234-4567-8901-abcdef123456");

console.log(customer.name);
console.log(`Subscriptions: ${customer.subscriptions?.length ?? 0}`);
```

***

## `customers.update`

Updates an existing customer. Pass only the fields you want to change.

### Signature

```typescript theme={null}
await mf.customers.update(id: string, params: UpdateCustomerData): Promise<Customer>
```

### Example

```typescript theme={null}
const updated = await mf.customers.update(
  "c4e8d1a2-1234-4567-8901-abcdef123456",
  {
    email: "new-billing@acme.com",
    netTerms: 45,
  },
);
```

***

## `customers.delete`

Deletes a customer.

### Signature

```typescript theme={null}
await mf.customers.delete(id: string): Promise<void>
```

### Example

```typescript theme={null}
await mf.customers.delete("c4e8d1a2-1234-4567-8901-abcdef123456");
```

***

## `customers.getWithRevenue`

**What it does in plain English:** fetches a customer AND their revenue numbers for a time window, in one call. Lets you render a customer detail page (profile, subscriptions, revenue, cost, margin) without juggling two round trips.

Behind the scenes the SDK fires both requests in parallel, so the wall-clock time is roughly the time of one call.

### Signature

```typescript theme={null}
await mf.customers.getWithRevenue(
  id: string,
  window?: CustomerRevenueWindow,
): Promise<CustomerDetailWithRevenue>
```

### Parameters

| Name               | Type     | Required | Description                                    |
| ------------------ | -------- | -------- | ---------------------------------------------- |
| `id`               | `string` | yes      | The customer id (MarginFront's internal UUID). |
| `window.startDate` | `string` | no       | ISO date. Defaults to 30 days ago if omitted.  |
| `window.endDate`   | `string` | no       | ISO date. Defaults to today if omitted.        |

Pass both window fields together or neither. Omitting both defaults to the last 30 days UTC.

### Response shape

```typescript theme={null}
interface CustomerDetailWithRevenue {
  customer: Customer;
  revenue: RevenueMetrics;
}
```

The `customer` field is the same shape as `customers.get` returns. The `revenue` field is the same canonical shape `analytics.revenue` returns, scoped to this one customer. See [Types Reference](/sdk/types-reference) for the complete interfaces.

### Example

```typescript theme={null}
// Default window (last 30 days)
const { customer, revenue } = await mf.customers.getWithRevenue(
  "c4e8d1a2-1234-4567-8901-abcdef123456",
);

console.log(`${customer.name}`);
console.log(`External id: ${customer.externalId ?? "(none)"}`);
console.log(`Status: ${customer.status}`);

console.log(`Revenue: $${revenue.revenue.toFixed(2)}`);
console.log(`Cost: $${revenue.cost.toFixed(2)}`);
console.log(`Margin: $${revenue.margin.toFixed(2)}`);

if (revenue.marginPercent !== null) {
  console.log(`Margin %: ${revenue.marginPercent.toFixed(1)}%`);
} else {
  console.log(`Margin %: not available (no revenue in window)`);
}

console.log(`Events: ${revenue.eventCount}`);

// Which subscriptions contributed the most revenue
const topSubs = revenue.bySubscription
  .sort((a, b) => b.revenue - a.revenue)
  .slice(0, 3);

for (const row of topSubs) {
  console.log(
    `  Sub ${row.subscriptionId}: $${row.revenue.toFixed(2)} revenue`,
  );
}

// Explicit window
const april = await mf.customers.getWithRevenue(
  "c4e8d1a2-1234-4567-8901-abcdef123456",
  {
    startDate: "2026-04-01",
    endDate: "2026-04-30",
  },
);
```

### What this returns, in plain English

* **`customer`** the usual customer record. Profile, contact info, status, subscriptions list (if populated), billing settings.
* **`revenue`** a full canonical revenue block for this one customer, in the window you asked for. Revenue, cost, margin, marginPercent, plus the usage/recurring/seat/onetime breakdown, a per-subscription row list, and a per-pricing-strategy row list.

For the full shape of `RevenueMetrics`, see [Types Reference](/sdk/types-reference#revenuemetrics).

### When to use this

Customer detail pages. Account manager dashboards. Churn-risk reviews. Anywhere you need the customer record AND how much they're contributing in one view.

For just the customer record, use `customers.get`. For revenue across many customers, use `analytics.revenue` with no filter (and read `bySubscription` for per-customer rollups).

***

## Next steps

* **[Analytics](/sdk/analytics)**: all seven canonical analytics methods
* **[Types Reference](/sdk/types-reference)**: full interface definitions
* **[Subscriptions with Revenue](/sdk/subscriptions)**: the same pattern, but scoped to a subscription
