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

# Subscription Settings

> Configure global defaults for trials, dunning, renewals, and cancellations. New operations use these values; active cases keep their own configuration.

Subscription settings give you one place to control the global defaults that Reorder applies when new subscription operations begin. You can adjust trial lengths, dunning retry schedules, renewal behavior, and cancellation posture without redeploying your store.

<Note>
  Settings changes apply to **future operations and newly created process state only**. Existing active dunning cases, cancellation flows, and renewal cycles keep the configuration that was snapshotted when they were created.
</Note>

## Accessing subscription settings

In your Medusa Admin, navigate to **Settings → Subscription Settings** (`/app/settings/subscription-settings`). The page loads the current effective settings and lets you edit and save them in a single form.

The settings page is split into four sections:

* **Trial** — default trial period for new subscription operations
* **Dunning** — retry schedule and maximum attempt count for new dunning cases
* **Renewals** — default renewal behavior for newly started renewal cycles
* **Cancellation defaults** — default posture when a new cancellation flow opens

## Configurable fields

| Field                           | Type                        | Default                     | Description                                                                                                                        |
| ------------------------------- | --------------------------- | --------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| `default_trial_days`            | integer ≥ 0                 | `0`                         | Number of trial days applied by default to new subscription operations. `0` means no default trial.                                |
| `dunning_retry_intervals`       | array of integers (minutes) | `[1440, 4320, 10080]`       | Ordered retry schedule for newly created dunning cases, expressed in minutes. Must be strictly increasing with no duplicates.      |
| `max_dunning_attempts`          | integer > 0                 | `3`                         | Maximum number of retry attempts for newly created dunning flows. Must equal the number of intervals in `dunning_retry_intervals`. |
| `default_renewal_behavior`      | enum                        | `process_immediately`       | Global default behavior when a new renewal operation begins. See [renewal behavior values](#renewal-behavior-values).              |
| `default_cancellation_behavior` | enum                        | `recommend_retention_first` | Global default posture when a new cancellation flow starts. See [cancellation behavior values](#cancellation-behavior-values).     |

### Renewal behavior values

| Value                                | Meaning                                                                                                                                      |
| ------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------- |
| `process_immediately`                | Treat new renewals as immediately processable from a global-settings perspective. Workflow-level validations and approval rules still apply. |
| `require_review_for_pending_changes` | When a new renewal starts and there is reviewable change context (such as a pending plan update), default toward a review and approval path. |

### Cancellation behavior values

| Value                       | Meaning                                                                                                                                               |
| --------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| `recommend_retention_first` | When a new cancellation flow opens, begin with retention-oriented handling — pause offers, discounts, or bonuses — before proceeding to cancellation. |
| `allow_direct_cancellation` | When a new cancellation flow opens, allow a direct-cancellation path as the default posture. Cancellation validations still run.                      |

## Persisted state and the is\_persisted flag

Before you save settings for the first time, Reorder serves built-in fallback defaults. These defaults are not stored in the database — they are assembled at read time. Once you save settings for the first time, Reorder creates a persistent singleton record and uses it as the runtime source of truth.

The `is_persisted` field in the API response tells you which state you are in:

| `is_persisted` | Meaning                                                                        |
| -------------- | ------------------------------------------------------------------------------ |
| `false`        | The response is built from fallback defaults. No settings have been saved yet. |
| `true`         | The response comes from the stored singleton. At least one save has occurred.  |

The info panel at the top of the settings page shows the current `version`, `updated_at`, and `updated_by` values so you can see when the record was last changed and by whom.

## The version field

Every successful save increments the `version` field by one. Version starts at `0` for fallback defaults and becomes `1` after the first save.

The `version` field is used for optimistic locking. When you submit a settings update through the API, you pass the `expected_version` you read to ensure your update is based on the latest state. If another update has occurred since your read, the API returns a `409 Conflict`.

## Updating settings via the Admin API

You can read and update subscription settings programmatically using the Admin API.

### Get current settings

```bash theme={null}
GET /admin/subscription-settings
```

This endpoint always returns a valid response. If no settings have been saved yet, it returns the fallback defaults with `is_persisted: false`. It never returns `404`.

**Example response (fallback defaults):**

```json theme={null}
{
  "subscription_settings": {
    "settings_key": "global",
    "default_trial_days": 0,
    "dunning_retry_intervals": [1440, 4320, 10080],
    "max_dunning_attempts": 3,
    "default_renewal_behavior": "process_immediately",
    "default_cancellation_behavior": "recommend_retention_first",
    "version": 0,
    "updated_by": null,
    "updated_at": null,
    "metadata": null,
    "is_persisted": false
  }
}
```

### Update settings

```bash theme={null}
POST /admin/subscription-settings
```

Send only the fields you want to change. Omitted fields keep their current effective values.

**Request body:**

```json theme={null}
{
  "default_trial_days": 21,
  "dunning_retry_intervals": [1440, 4320, 10080],
  "max_dunning_attempts": 3,
  "expected_version": 0
}
```

<Note>
  Pass `expected_version: 0` for your first save. For subsequent saves, pass the `version` value returned by the most recent GET or POST response.
</Note>

**Example response (after first save):**

```json theme={null}
{
  "subscription_settings": {
    "settings_key": "global",
    "default_trial_days": 21,
    "dunning_retry_intervals": [1440, 4320, 10080],
    "max_dunning_attempts": 3,
    "default_renewal_behavior": "process_immediately",
    "default_cancellation_behavior": "recommend_retention_first",
    "version": 1,
    "updated_by": "user_01ABC",
    "updated_at": "2026-04-03T14:00:00.000Z",
    "metadata": {
      "audit_log": [
        {
          "action": "update_settings",
          "who": "user_01ABC",
          "when": "2026-04-03T14:00:00.000Z",
          "reason": "admin_save",
          "previous_version": 0,
          "next_version": 1,
          "change_summary": [
            { "field": "default_trial_days", "from": 0, "to": 21 }
          ]
        }
      ],
      "last_update": {
        "action": "update_settings",
        "who": "user_01ABC",
        "when": "2026-04-03T14:00:00.000Z",
        "reason": "admin_save",
        "previous_version": 0,
        "next_version": 1,
        "change_summary": [
          { "field": "default_trial_days", "from": 0, "to": 21 }
        ]
      }
    },
    "is_persisted": true
  }
}
```

## Validation rules

The API enforces these rules on every update request:

* `default_trial_days` must be `>= 0`
* `max_dunning_attempts` must be `> 0`
* `dunning_retry_intervals` must contain positive integers only
* `dunning_retry_intervals` must be strictly increasing with no duplicates
* `max_dunning_attempts` must equal the number of intervals in `dunning_retry_intervals`
* `default_renewal_behavior` must be one of the supported enum values
* `default_cancellation_behavior` must be one of the supported enum values
* `expected_version` must be `>= 0`

A request that violates any of these rules returns `400 invalid_data`. A version mismatch returns `409 Conflict`.

## Next steps

* [Plugin setup](/configuration/plugin-setup) — review the full plugin installation steps
* [Dunning](/concepts/dunning) — understand how dunning cases consume these settings at create time
* [Renewals](/concepts/renewals) — see how renewal behavior settings apply to new renewal cycles
