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

# Subscriptions

> Manage recurring billing—create subscriptions, handle trials, process renewals, and recover failed payments.

Subscriptions automate recurring billing by linking customers to [plans](/guides/platform/plans). Define billing cycles, trial periods, and pricing once—PayNext handles charges, renewals, and failed payment recovery automatically.

<Note>
  Before creating subscriptions, set up a recurring plan in your Dashboard. See [Plans](/guides/platform/plans) to learn how to configure billing cycles, trial periods, and pricing.
</Note>

## The Subscription Lifecycle

When a customer completes checkout with a recurring plan, PayNext creates a subscription and manages it through these stages:

<div className="block dark:hidden">
  ```mermaid theme={"system"}
  flowchart TD
      A([Checkout completes]) --> B([trial])
      A --> C([active])
      B -->|Payment succeeds| C
      B -->|Payment fails| D
      B -->|Schedule cancel| E
      B -->|Cancel immediately| F
      C -->|Renewal fails| D([past_due])
      C -->|Schedule cancel| E([scheduled_for_cancellation])
      C -->|Cancel immediately| F
      D -->|Recovery succeeds| C
      D -->|Recovery exhausted| F([cancelled])
      E -->|Cycle ends| F
      F -->|Reactivate, paid period active or charge succeeds| C
      F -->|Reactivate, charge fails| D
      
      style A fill:#f3f4f6,stroke:#6b7280
      style B fill:#e0f2fe,stroke:#0284c7
      style C fill:#dcfce7,stroke:#16a34a
      style D fill:#fef3c7,stroke:#d97706
      style E fill:#fee2e2,stroke:#dc2626
      style F fill:#fee2e2,stroke:#dc2626
  ```
</div>

<div className="hidden dark:block">
  ```mermaid theme={"system"}
  flowchart TD
      A([Checkout completes]) --> B([trial])
      A --> C([active])
      B -->|Payment succeeds| C
      B -->|Payment fails| D
      B -->|Schedule cancel| E
      B -->|Cancel immediately| F
      C -->|Renewal fails| D([past_due])
      C -->|Schedule cancel| E([scheduled_for_cancellation])
      C -->|Cancel immediately| F
      D -->|Recovery succeeds| C
      D -->|Recovery exhausted| F([cancelled])
      E -->|Cycle ends| F
      F -->|Reactivate, paid period active or charge succeeds| C
      F -->|Reactivate, charge fails| D
      
      style A fill:#374151,stroke:#9ca3af,color:#f3f4f6
      style B fill:#1e3a5f,stroke:#38bdf8,color:#e0f2fe
      style C fill:#14532d,stroke:#4ade80,color:#dcfce7
      style D fill:#78350f,stroke:#fbbf24,color:#fef3c7
      style E fill:#7f1d1d,stroke:#f87171,color:#fee2e2
      style F fill:#7f1d1d,stroke:#f87171,color:#fee2e2
  ```
</div>

## Subscription Statuses

| Status                       | Description                                                     | Your Action                        |
| ---------------------------- | --------------------------------------------------------------- | ---------------------------------- |
| `trial`                      | In trial period, no charge yet                                  | Provision access                   |
| `active`                     | Billing successful, good standing                               | Maintain access                    |
| `past_due`                   | Renewal failed, retrying for 30 days                            | Keep access, notify customer       |
| `scheduled_for_cancellation` | Cancellation queued for cycle end                               | Maintain access until cycle ends   |
| `cancelled`                  | Ended; can be reactivated while the paid period is still active | Revoke access, unless reactivating |

<Note>
  A `past_due` subscription also pauses retries when its saved payment method can no longer be charged at all, and resumes—immediately—if a card update revives it. See [Dead payment methods](/guides/use-cases/recover-subscriptions#dead-payment-methods).
</Note>

## Create a Subscription

Include a recurring `plan.id` in your client session. When checkout completes, PayNext creates the subscription automatically.

```json theme={"system"}
{
  "customer": {
    "email": "customer@example.com",
    "address": { "country": "US" }
  },
  "plan": {
    "id": "plan_7a8b9c0d-1e2f-3a4b-5c6d-7e8f9a0b1c2d"
  }
}
```

PayNext sends a `subscription_v2.created` webhook and schedules future renewals based on the plan's billing cycle.

## Manage Subscriptions

### Change Plans

Upgrade or downgrade active subscriptions:

* **Dashboard** — Select subscription → **Change Plan**
* **SDK/API** — See [Change Subscription Plan](/guides/use-cases/change-subscription-plan)

<Warning>
  Editing a plan in the Dashboard only affects new subscriptions. Existing subscribers keep their original terms.
</Warning>

### Cancel

You can cancel subscriptions immediately or schedule cancellation for the end of the billing cycle.

#### Schedule cancellation (recommended)

Customer keeps access until the current billing cycle ends, then transitions to `cancelled`.

* **Dashboard** — Select subscription → **Cancel** → **At end of billing cycle**
* **API** — `POST /subscriptions/schedule-cancel/{id}`

```bash theme={"system"}
curl -X POST https://api.paynext.com/subscriptions/schedule-cancel/sub_a1b2c3d4-5e6f-7a8b-9c0d-1e2f3a4b5c6d \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "X-API-Version: 2.0.0"
```

The subscription moves to `scheduled_for_cancellation` and automatically transitions to `cancelled` when the cycle ends.

#### Cancel immediately

Ends the subscription now. Customer loses access immediately.

* **Dashboard** — Select subscription → **Cancel** → **Immediately**
* **API** — `POST /subscriptions/cancel/{id}`

```bash theme={"system"}
curl -X POST https://api.paynext.com/subscriptions/cancel/sub_a1b2c3d4-5e6f-7a8b-9c0d-1e2f3a4b5c6d \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "X-API-Version: 2.0.0"
```

<Warning>
  Immediate cancellation does not issue refunds automatically. If you want to refund, perform this action separately via API or Dashboard.
</Warning>

### Cancellation details

Every cancelled subscription records **why** it ended and **when**, so you can tell voluntary churn apart from dunning exhaustion, workflow rules, and fraud/dispute activity. Two fields carry this — both always present on the subscription, and `null` until it's cancelled:

| Field                  | Description                                                                                                                                                                                              |
| ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `cancelled_at`         | UTC timestamp of when the subscription became `cancelled`. `null` while `trial`, `active`, `past_due`, or `scheduled_for_cancellation`.                                                                  |
| `cancellation_details` | `{ reason, trigger_payment_id }`. `reason` is server-attested; `trigger_payment_id` (prefixed `pay_`) points at the payment that caused a system cancellation, or `null` for merchant-initiated cancels. |

| `reason`                        | When it's set                                                                                             | `trigger_payment_id` |
| ------------------------------- | --------------------------------------------------------------------------------------------------------- | -------------------- |
| `merchant_initiated`            | You cancelled via API or Dashboard                                                                        | `null`               |
| `past_due_max_attempts_reached` | Dunning exhausted all retries                                                                             | Last failed renewal  |
| `workflow_action`               | A [workflow](/guides/platform/workflows) ended the subscription                                           | Triggering payment   |
| `fraud_prevention`              | A fraud / pre-dispute signal cancelled it (see [Fraud Prevention](/guides/fraud-prevention/introduction)) | Disputed payment     |

For scheduled cancellations, `cancellation_details` is populated at schedule time (visible on the `subscription_v2.scheduled_for_cancellation` event) and finalized when the subscription ends. Reactivating a subscription clears both fields back to `null`.

<Note>
  The **reason is server-owned** — you choose the cancellation *type* (`cancel_immediately` or `schedule_cancellation`), never the reason. Your API and Dashboard cancels are always attributed `merchant_initiated`. A cancel request that includes a reason-like field (`reason`, `cancellation_details`, `trigger_payment_id`) is rejected with `400`.
</Note>

### Reactivate

Set `status: active` with `PATCH /subscriptions` to reactivate a `scheduled_for_cancellation` or `cancelled` subscription. What happens depends on whether the paid period (`current_period_end`) is still active.

```bash theme={"system"}
curl -X PATCH https://api.paynext.com/subscriptions \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "X-API-Version: 2.0.0" \
  -H "Content-Type: application/json" \
  -d '{
    "subscription": {
      "id": "sub_a1b2c3d4-5e6f-7a8b-9c0d-1e2f3a4b5c6d",
      "status": "active"
    }
  }'
```

| Subscription                 | Paid period                                       | Result                                                              |
| ---------------------------- | ------------------------------------------------- | ------------------------------------------------------------------- |
| `scheduled_for_cancellation` | Still active                                      | → `active`, no charge                                               |
| `cancelled`                  | Still active (`current_period_end` in the future) | → `active`, no charge—access restored for the remaining paid period |
| `cancelled`                  | Ended (`current_period_end` in the past or unset) | PayNext attempts an immediate charge on the saved payment method    |

When the paid period has ended, the reactivation charge determines the outcome:

* **Charge succeeds** → `active` with a new billing period.
* **Charge fails** → `past_due`; the subscription enters the standard [dunning flow](#handle-failed-payments) and access is **not** restored.

Either way, PayNext emits a single `subscription_v2` event reflecting the resulting status (`subscription_v2.activated` on reactivation, or `subscription_v2.past_due` if the reactivation charge fails).

<Note>
  A `past_due` subscription cannot be reactivated with this endpoint—collect payment via SDK checkout instead. See [Recover Subscriptions](/guides/use-cases/recover-subscriptions).
</Note>

## Handle Failed Payments

When a renewal payment fails, PayNext automatically retries up to **8 times**. During this period, the subscription remains `past_due`.

<Tip>
  Notify users when their payment fails and prompt them to update their payment method. Use the SDK to let customers recover their subscription directly. See [Recover Subscriptions](/guides/use-cases/recover-subscriptions).
</Tip>

### Automatic retry

PayNext attempts recovery automatically. Track progress via the `subscription_v2.past_due` webhook, which carries an incremented `attempt_count` on each retry:

```json theme={"system"}
{
  "past_due": {
    "attempt_count": 3,
    "max_attempts_count": 8
  }
}
```

| Field                | Description                                  |
| -------------------- | -------------------------------------------- |
| `attempt_count`      | Number of recovery attempts made so far      |
| `max_attempts_count` | Maximum attempts before subscription cancels |

An attempt can also run ahead of its scheduled slot. For a payment declined for insufficient funds, the card network signals when the funds are likely there and the attempt runs at that moment instead—it replaces the scheduled attempt rather than adding one. See [Funds-Available Retries](/guides/advanced/funds-available-retries).

### Billing date on recovery

When recovery succeeds, the next billing date shifts to the recovery date plus one billing interval—not from the original renewal date.

**Example:** A 28-day subscription was due to renew on Dec 1, but the payment failed. Recovery succeeds on Dec 5. The next billing date is **Jan 2** (Dec 5 + 28 days), not Dec 29 (Dec 1 + 28 days).

### Recovery exhausted

If all 8 retry attempts fail, the subscription automatically transitions to `cancelled`.

## Webhook Events

Listen for these events to keep your system in sync:

| Event                                        | When it fires                                                         |
| -------------------------------------------- | --------------------------------------------------------------------- |
| `subscription_v2.created`                    | New subscription created                                              |
| `subscription_v2.activated`                  | Became active from a non-active state (trial → paid, or reactivation) |
| `subscription_v2.renewed`                    | Recurring renewal or past-due recovery                                |
| `subscription_v2.past_due`                   | A renewal failed and dunning began (one per retry)                    |
| `subscription_v2.scheduled_for_cancellation` | Cancellation scheduled for period end                                 |
| `subscription_v2.cancelled`                  | Subscription ended (recovery exhausted or cancelled)                  |
| `subscription_v2.updated`                    | Plan or metadata change, or un-cancel                                 |

See [Webhook Events](/webhooks/introduction/event-types) for the full list and payload schemas.
