> ## 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.

# Subscriptions

> Tie customers to pricing plans

# Subscriptions

A **subscription** ties a customer to a pricing plan. It's the thing that says "starting on this date, bill this customer according to this plan's rules." Until a customer has a subscription, MarginFront doesn't know how to charge them. Usage events can still be logged, but there's no pricing rule attached.

Creating a subscription is the most complex create in the whole API because it brings together four other objects: a customer, an agent, a pricing plan, and a start date. All four have to already exist before you can create the subscription.

***

## The whole integration chain

Before you can create a subscription, you need (in this order):

1. A **customer**. See [customers](./customers).
2. An **agent**. See [agents](./agents).
3. One or more **signals** attached to that agent. See [signals](./signals).
4. A **pricing plan** attached to that agent. See [pricing-plans](./pricing-plans).

Once those exist, you create the subscription that glues customer ↔ plan together. After that, every usage event you log gets priced according to the subscribed plan and rolled up into an invoice at the end of the billing period.

***

## Create a subscription

**In plain English:** Start billing a customer according to a pricing plan. You're saying "from this date forward, charge this customer for this agent's usage according to this plan."

**Method & URL:**

```
POST /v1/subscriptions
```

**Required fields:**

* `name` *(string)*: a human-readable name for the subscription. Useful for identifying it in the dashboard.
* `planId` *(UUID string)*: the pricing plan's internal ID. From the pricing plan's create response.
* `agentId` *(UUID string)*: the agent's internal ID. Must match the agent that the plan belongs to.
* `customerId` *(UUID string)*: the customer's internal ID. From the customer's create response.
* `startDate` *(ISO 8601 date string)*: when this subscription starts billing. Can be in the past (for backdating) or the future (for scheduled activation). Example: `"2026-04-10T00:00:00.000Z"`.

**Optional fields (most common):**

* `status` *(`"upcoming"` | `"active"` | `"ended"`, default `"upcoming"`)*: current state. Use `"active"` if you want billing to start immediately.
* `billingCycle` *(`"monthly"` | `"yearly"` | `"custom"`, default `"monthly"`)*: how often invoices are generated.
* `billingModel` *(`"subscription"` | `"usage"` | `"hybrid"`, default `"subscription"`)*: how billing is calculated.
  * `"subscription"` = flat recurring fee
  * `"usage"` = pay only for what you use
  * `"hybrid"` = base fee + usage
* `netTerms` *(number, default `30`)*: payment terms in days after invoice issued.

**Other optional fields:**

* `endDate` *(ISO date)*: fixed end date if this is a time-limited subscription
* `isForever` *(boolean, default `false`)*: set true for subscriptions with no end date (ignores `endDate`)
* `subscriptionDetails` *(object)*: free-form metadata specific to this subscription
* `seatsCount` *(number, default `0`)*: for per-seat pricing
* `customCycleDays` *(number)*: only when `billingCycle` is `"custom"`; how many days between invoices
* `proratedAmount` *(number)*: proration adjustment for mid-cycle starts
* `timezone` *(string)*: override for billing period calculations
* `billingDay` *(1-31)*: day of the month invoices are generated
* `invoiceMemo` *(string)*: a note that appears on every invoice for this subscription
* `metadata` *(object)*: custom key/value pairs; stored but not interpreted

**Example curl call (the minimum to get a working subscription):**

```bash theme={null}
curl -X POST https://api.marginfront.com/v1/subscriptions \
  -H "x-api-key: mf_sk_test_..." \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Acme Pro Subscription",
    "planId": "a1b2c3d4-5678-90ab-cdef-1234567890ab",
    "agentId": "b47e12fa-abcd-4567-8901-234567890abc",
    "customerId": "5e7f8a3d-1234-5678-9abc-def012345678",
    "startDate": "2026-04-10T00:00:00.000Z",
    "status": "active",
    "billingCycle": "monthly"
  }'
```

**What you get back (`201 Created`):**

```json theme={null}
{
  "id": "sub_9a8b7c6d-...",
  "name": "Acme Pro Subscription",
  "planId": "a1b2c3d4-...",
  "agentId": "b47e12fa-...",
  "customerId": "5e7f8a3d-...",
  "startDate": "2026-04-10T00:00:00.000Z",
  "status": "active",
  "billingCycle": "monthly",
  "createdAt": "2026-04-10T14:30:00.000Z"
}
```

**Common errors:**

* **`400 Bad Request`**: missing one of the required fields, or a UUID is the wrong format, or `startDate` isn't a valid ISO date.
* **`404 Not Found`**: one of the referenced objects (customer, agent, plan) doesn't exist in this org.
* **`409 Conflict`**: this customer already has an overlapping active subscription for this plan, depending on your org's rules.

**When to call this:** When a customer upgrades, signs up for a paid plan, or activates a trial. This is the "billing starts now" moment.

***

## Read a subscription

**Method & URL:**

```
GET /v1/subscriptions/{subscriptionId}
```

***

## Read a subscription with revenue

**In plain English:** fetch a subscription together with its revenue, cost, and margin for a time window. Use this to power subscription detail pages without two round trips.

**Method & URL:**

```
GET /v1/subscriptions/{subscriptionId}/revenue
```

**Query parameters** (all optional):

* `startDate` *(ISO date)*: start of the window, inclusive
* `endDate` *(ISO date)*: end of the window, inclusive

If you omit both, MarginFront defaults the window to the last 30 days (UTC).

**Example:**

```bash theme={null}
curl "https://api.marginfront.com/v1/subscriptions/9a8b7c6d-.../revenue?startDate=2026-04-01&endDate=2026-04-30" \
  -H "x-api-key: $MF_API_SECRET_KEY"
```

**What it returns:** a canonical `RevenueMetrics` object scoped to this subscription. Same shape as [`GET /v1/analytics/revenue`](./analytics-revenue), same math. Revenue, cost, margin, margin percent, the usage/recurring/seat/onetime breakdown, per-subscription breakdown (one row for this subscription), per-strategy breakdown.

See [the SDK types reference](/sdk/types-reference) for the full `RevenueMetrics` shape.

**Using the SDK:** `client.subscriptions.getWithRevenue(id, window)` wraps this endpoint and returns `{ subscription, revenue }` in a single call (it fires the subscription fetch and this revenue fetch in parallel). See [SDK subscriptions](/sdk/subscriptions).

**Common errors:**

* **`404 Not Found`**: no subscription with that ID exists in this org.
* **`401 Unauthorized`**: API key missing or wrong.

***

## List subscriptions

**Method & URL:**

```
GET /v1/subscriptions
```

**Useful query parameters:** `customerId`, `status`, `agentId` (check the controller for the full list).

***

## Update a subscription

**Method & URL:**

```
PATCH /v1/subscriptions/{subscriptionId}
```

**Fields:** most fields from create are updatable. The structural fields (`planId`, `agentId`, `customerId`) generally should NOT be changed. If a customer switches plans, it's usually cleaner to end the current subscription and create a new one rather than mutating the existing subscription, because it preserves a clean audit trail for accounting.

**The billing dates can't be changed after a subscription is created.** The `startDate` and the current billing period's start and end dates decide which usage each invoice picks up, so they're locked once the subscription exists. If you include any of them in a PATCH, the request comes back `400 Bad Request` with a message naming the fields you tried to move. To bill on a different schedule, end this subscription and create a new one that starts on the dates you want.

***

## Update invoice dates

**Method & URL:**

```
PATCH /v1/subscriptions/{subscriptionId}/invoice-dates
```

**What it does:** Adjusts when future invoices will be generated for this subscription. Use this for things like "customer wants to move their billing day from the 1st to the 15th."

***

## Read the subscription changelog

**Method & URL:**

```
GET /v1/subscriptions/{subscriptionId}/changelog
```

**What it returns:** a history of all changes made to this subscription: plan changes, price updates, date adjustments, status transitions. Useful for audit trails and for customer support when someone asks "when did that price change?"

***

## Using the Node SDK

```js theme={null}
// List all subscriptions
const { data } = await mf.subscriptions.list();

// Read a specific subscription
const sub = await mf.subscriptions.get("sub_9a8b7c6d-...");
```

**Subscription CREATE is not yet wrapped by the `@marginfront/sdk` npm package.** For now, create subscriptions through the HTTP API using curl or your language of choice. See the "Create a subscription" section above.
