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

# subscriber.cancelled

> The subscription has been cancelled by the merchant. No further invoices will be created.

## When it fires

When a merchant cancels a subscriber — either immediately or scheduled at the end of the current period — from the dashboard.

* **Immediate cancellation**: subscriber status is set to `cancelled` right away; `subscriber.cancelled` fires immediately
* **Cancel at period end**: subscriber continues as `active` until the current period ends, then transitions to `cancelled` and this event fires

***

## What to do

Depends on whether this is an immediate or end-of-period cancellation. Check whether `currentPeriodEnd` is in the future.

**If `currentPeriodEnd` is in the past or now:** Revoke access immediately.

**If `currentPeriodEnd` is in the future:** The subscriber paid through the end of the period. Maintain access until then and schedule revocation. You will not receive another webhook at period end — act on this event.

```javascript theme={null}
const periodEnd = new Date(event.currentPeriodEnd);
const now = new Date();

if (periodEnd <= now) {
  await revokeAccess(event.email); // immediate
} else {
  await scheduleAccessRevocation(event.email, periodEnd); // at period end
}
```

***

## Payload

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

| Field              | Type   | Description                                                   |
| ------------------ | ------ | ------------------------------------------------------------- |
| `event`            | string | Always `subscriber.cancelled`                                 |
| `subscriberId`     | string | UUID of the subscriber record                                 |
| `merchantId`       | string | Your merchant account UUID                                    |
| `planId`           | string | UUID of the plan                                              |
| `email`            | string | Subscriber email address                                      |
| `status`           | string | Always `cancelled`                                            |
| `currentPeriodEnd` | string | ISO 8601 — if in the future, access continues until this date |
| `timestamp`        | string | ISO 8601 — when the event was generated                       |

***

## Handler example

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

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

  if (event.event === 'subscriber.cancelled') {
    const { subscriberId, email, currentPeriodEnd } = event;

    await db.subscriptions.update(subscriberId, {
      status: 'cancelled',
      accessUntil: currentPeriodEnd,
    });

    const periodEnd = new Date(currentPeriodEnd);
    const now = new Date();

    if (periodEnd <= now) {
      // Immediate cancellation — revoke now
      await revokeAccess(email);
      await sendEmail(email, 'subscription-cancelled-immediate');
    } else {
      // End-of-period — schedule revocation
      await scheduleJob('revoke-access', { email }, periodEnd);
      await sendEmail(email, 'subscription-cancelled-period-end', {
        accessUntil: currentPeriodEnd,
      });
    }
  }

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

***

## Related events

* [`subscriber.expired`](/webhook-events/subscriber-expired) — Expiry due to non-payment (not a manual cancellation).
* [`subscriber.paused`](/webhook-events/subscriber-paused) — Temporary halt; does not end the subscription.
