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

# Subscriptions

> Collect recurring crypto payments with plans, subscribers, and automatic billing cycles

# Subscriptions

Settlx subscriptions let you charge customers on a recurring schedule — weekly, monthly, annually, or any custom interval — using crypto. You create a plan once, enroll your customers, and Settlx handles the billing cycle automatically.

***

## How it works

```
Plan ─── defines interval, amount, currency
 │
 └─► Subscriber ─── a customer enrolled into a plan
          │
          └─► Invoice ─── created automatically each billing cycle
                   │
                   └─► Customer pays ─► subscriber advances to next period
```

1. **Create a plan** in the dashboard. Plans define the price, interval, and grace period.
2. **Enroll a subscriber** via API from your backend whenever a customer signs up.
3. Settlx **creates the first invoice immediately** and fires a `subscriber.enrolled` webhook.
4. When the customer pays, Settlx fires `subscriber.activated` and advances their subscription period.
5. At the start of each new billing cycle, Settlx creates a new invoice automatically and fires `subscriber.past_due`.
6. If payment is not received before the grace period ends, the subscriber is expired and `subscriber.expired` fires.

***

## Subscriber statuses

| Status      | Meaning                                                              |
| ----------- | -------------------------------------------------------------------- |
| `pending`   | Enrolled, first invoice created, awaiting first payment              |
| `trialing`  | In free-trial period — no invoice created until trial ends           |
| `active`    | Paid up — subscription is in good standing                           |
| `past_due`  | New billing cycle started, invoice created, payment not yet received |
| `paused`    | Manually paused by the merchant — no new invoices created            |
| `cancelled` | Cancelled by merchant — subscription will not renew                  |
| `expired`   | Grace period elapsed without payment                                 |

<Info>
  Subscribers start as `pending` and only become `active` after their first payment is confirmed on-chain. Do not provision access until you receive the `subscriber.activated` webhook.
</Info>

***

## Plans

Plans are created and managed from the **Subscriptions → Plans** section of your dashboard. The following fields are set at creation and **cannot be changed** after subscribers have enrolled:

| Field             | Notes                                                       |
| ----------------- | ----------------------------------------------------------- |
| `amount`          | Billing amount per cycle                                    |
| `currency`        | Fiat currency (e.g. `USD`)                                  |
| `interval`        | `day`, `week`, `month`, or `year`                           |
| `intervalCount`   | Number of intervals per cycle (e.g. `3` months = quarterly) |
| `trialPeriodDays` | Days of free trial before first charge                      |

These fields **can** be updated at any time:

| Field             | Notes                                                    |
| ----------------- | -------------------------------------------------------- |
| `name`            | Display name                                             |
| `description`     | Description shown to subscribers                         |
| `gracePeriodDays` | Days a subscriber has to pay before expiring (minimum 1) |

***

## Grace period

Every subscriber has a grace period — the window they have to pay each invoice before their subscription is expired. The grace period starts from the moment an invoice is created.

* Minimum grace period is **1 day**
* If a subscriber does not pay within the grace period, their status transitions to `expired` and `subscriber.expired` fires
* To reinstate an expired subscriber, you must re-enroll them

***

## Trial periods

If a plan has `trialPeriodDays > 0`, enrolled subscribers start as `trialing`. No invoice is created during the trial. When the trial ends, the first invoice is generated automatically and billing begins.

***

## Enrolling subscribers

Enroll subscribers from your backend server using your API key:

```bash theme={null}
curl -X POST https://api.settlx.io/api/v1/subscriptions/subscribers \
  -H "Authorization: Bearer pk_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "planId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "email": "customer@example.com",
    "externalId": "usr_789",
    "metadata": { "userId": "usr_789" }
  }'
```

See [Enroll Subscriber](/api-reference/subscriptions/enroll) for the full API reference.

<Warning>
  Never enroll subscribers from client-side code. Your API key must be kept server-side only.
</Warning>

***

## Receiving subscription webhooks

Set your **Webhook URL** in **Settings → Developer**. Settlx will POST all subscription lifecycle events to that URL — signed with the same HMAC-SHA256 secret as invoice webhooks.

Subscription events use a flat payload (no `data` wrapper):

```json theme={null}
{
  "event": "subscriber.activated",
  "subscriberId": "9f1e2d3c-4b5a-6789-abcd-ef0123456789",
  "merchantId": "f9e8d7c6-b5a4-3210-9876-543210fedcba",
  "planId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "email": "customer@example.com",
  "status": "active",
  "currentPeriodEnd": "2026-05-19T06:00:00.000Z",
  "timestamp": "2026-04-19T06:00:00.000Z"
}
```

The signature is in the `X-Webhook-Signature` header — same as invoice webhooks. Verify it the same way — see [Webhook Integration](/webhooks/integration).

### Handling all event types together

```javascript Node.js theme={null}
app.post('/webhooks/settlx', express.raw({ type: 'application/json' }), async (req, res) => {
  verifySignature(req); // same verification as invoice webhooks

  const event = JSON.parse(req.body);

  if (event.event.startsWith('invoice.')) {
    // Invoice payment events
    if (event.event === 'invoice.settled') {
      await fulfillOneTimeOrder(event.data.invoice.metadata.orderId);
    }
  }

  if (event.event.startsWith('subscriber.')) {
    // Subscription lifecycle events
    switch (event.event) {
      case 'subscriber.activated':
        await activateSubscription(event.email, event.planId);
        break;
      case 'subscriber.expired':
      case 'subscriber.cancelled':
        await revokeAccess(event.email);
        break;
      case 'subscriber.paused':
        await pauseAccess(event.email);
        break;
      case 'subscriber.resumed':
        await restoreAccess(event.email);
        break;
    }
  }

  res.status(200).json({ received: true });
});
```

***

## Subscription lifecycle reference

| Event                                                          | Status transition | What to do                                            |
| -------------------------------------------------------------- | ----------------- | ----------------------------------------------------- |
| [`subscriber.enrolled`](/webhook-events/subscriber-enrolled)   | → `pending`       | Send a welcome email; show payment instructions       |
| [`subscriber.activated`](/webhook-events/subscriber-activated) | → `active`        | **Provision access** to your product                  |
| [`subscriber.past_due`](/webhook-events/subscriber-past-due)   | → `past_due`      | Send payment reminder; restrict non-critical features |
| [`subscriber.expired`](/webhook-events/subscriber-expired)     | → `expired`       | **Revoke access**; offer resubscribe flow             |
| [`subscriber.cancelled`](/webhook-events/subscriber-cancelled) | → `cancelled`     | Schedule access revocation at period end              |
| [`subscriber.paused`](/webhook-events/subscriber-paused)       | → `paused`        | Suspend access for the pause duration                 |
| [`subscriber.resumed`](/webhook-events/subscriber-resumed)     | → `active`        | Restore access                                        |

***

## Manual actions

From the dashboard (**Subscriptions → Subscribers → \[subscriber]**) you can:

| Action           | When to use                                                             |
| ---------------- | ----------------------------------------------------------------------- |
| **Send Invoice** | Manually trigger a new invoice for a `pending` or `past_due` subscriber |
| **Pause**        | Temporarily halt billing without cancelling                             |
| **Resume**       | Restart a paused subscription                                           |
| **Cancel**       | End a subscription immediately or at period end                         |

***

## Re-billing

If a subscriber is stuck in `pending` or `past_due` and you want to prompt them to pay again, use the **Send Invoice** button on the subscriber detail page (or `POST .../rebill` via the merchant API). This is fully idempotent — if a pending invoice already exists, no duplicate is created.
