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

# Settings

> Read and update the global subscription settings singleton — dunning schedules, renewal behavior, cancellation policy, and trial defaults.

The subscription settings endpoints manage the global configuration singleton used by the Reorder plugin at runtime. You can read the effective settings — which fall back to hardcoded defaults if no record has been persisted yet — and write a new or updated singleton through the dedicated workflow. All routes require an authenticated Medusa Admin user. The POST route uses optimistic locking via `expected_version`.

<Info>All routes require an authenticated Medusa Admin user. Unauthenticated requests return `401`.</Info>

## Field reference

| Field                           | Type       | Description                                                                           |
| ------------------------------- | ---------- | ------------------------------------------------------------------------------------- |
| `settings_key`                  | `string`   | Always `global` in MVP.                                                               |
| `default_trial_days`            | `number`   | Default trial length in days. Must be `>= 0`.                                         |
| `dunning_retry_intervals`       | `number[]` | Retry schedule in minutes. Must be strictly increasing positive integers.             |
| `max_dunning_attempts`          | `number`   | Maximum retry attempts. Must equal the number of intervals.                           |
| `default_renewal_behavior`      | `string`   | `process_immediately` or `require_review_for_pending_changes`.                        |
| `default_cancellation_behavior` | `string`   | `recommend_retention_first` or `allow_direct_cancellation`.                           |
| `version`                       | `number`   | Monotonic version for optimistic locking.                                             |
| `is_persisted`                  | `boolean`  | `false` when the response uses fallback defaults; `true` when a stored record exists. |

***

## GET /admin/subscription-settings

Returns the effective settings payload. When no record has been saved yet the response uses hardcoded fallback defaults and `is_persisted` is `false`. This route never returns `404`.

### Response

<ResponseField name="subscription_settings" type="object" required>
  <Expandable title="settings fields">
    <ResponseField name="settings_key" type="string">Always `global`.</ResponseField>
    <ResponseField name="default_trial_days" type="number">Trial length in days.</ResponseField>
    <ResponseField name="dunning_retry_intervals" type="number[]">Retry intervals in minutes.</ResponseField>
    <ResponseField name="max_dunning_attempts" type="number">Maximum retry attempts.</ResponseField>
    <ResponseField name="default_renewal_behavior" type="string">Global renewal policy.</ResponseField>
    <ResponseField name="default_cancellation_behavior" type="string">Global cancellation policy.</ResponseField>
    <ResponseField name="version" type="number">Current version number.</ResponseField>
    <ResponseField name="updated_by" type="string | null">Actor ID of the last update, or `null` when using defaults.</ResponseField>
    <ResponseField name="updated_at" type="string | null">Timestamp of the last update, or `null` when using defaults.</ResponseField>
    <ResponseField name="metadata" type="object | null">Audit metadata including `audit_log` and `last_update`.</ResponseField>
    <ResponseField name="is_persisted" type="boolean">`false` when returning fallback defaults.</ResponseField>
  </Expandable>
</ResponseField>

```json Fallback response example 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
  }
}
```

```json Persisted response example theme={null}
{
  "subscription_settings": {
    "settings_key": "global",
    "default_trial_days": 21,
    "dunning_retry_intervals": [45, 180, 720],
    "max_dunning_attempts": 3,
    "default_renewal_behavior": "require_review_for_pending_changes",
    "default_cancellation_behavior": "allow_direct_cancellation",
    "version": 1,
    "updated_by": "user_01ABC",
    "updated_at": "2026-04-03T14:00:00.000Z",
    "metadata": {
      "audit_log": [],
      "last_update": null
    },
    "is_persisted": true
  }
}
```

***

## POST /admin/subscription-settings

Persists a new or updated settings singleton through the dedicated workflow. The first successful POST creates the record. Omitted fields retain their current effective value.

### Body parameters

<ParamField body="default_trial_days" type="number">
  Default trial length in days. Must be `>= 0`.
</ParamField>

<ParamField body="dunning_retry_intervals" type="number[]">
  Retry intervals in minutes. Must be strictly increasing positive integers. Length must equal `max_dunning_attempts`.
</ParamField>

<ParamField body="max_dunning_attempts" type="number">
  Maximum retry attempts. Must be a positive integer equal to the number of intervals.
</ParamField>

<ParamField body="default_renewal_behavior" type="string">
  Global renewal policy. One of `process_immediately` or `require_review_for_pending_changes`.
</ParamField>

<ParamField body="default_cancellation_behavior" type="string">
  Global cancellation policy. One of `recommend_retention_first` or `allow_direct_cancellation`.
</ParamField>

<ParamField body="expected_version" type="number">
  Current version for optimistic locking. Use `0` on the first write.
</ParamField>

<ParamField body="reason" type="string">
  Optional reason for the update, recorded in the audit log.
</ParamField>

```json Request example theme={null}
{
  "default_trial_days": 21,
  "dunning_retry_intervals": [45, 180, 720],
  "max_dunning_attempts": 3,
  "default_renewal_behavior": "require_review_for_pending_changes",
  "default_cancellation_behavior": "allow_direct_cancellation",
  "expected_version": 0,
  "reason": "admin_save"
}
```

### Response

Returns the updated `subscription_settings` object. The `metadata.audit_log` and `metadata.last_update` fields record the change summary.

```json Response example theme={null}
{
  "subscription_settings": {
    "settings_key": "global",
    "default_trial_days": 21,
    "dunning_retry_intervals": [45, 180, 720],
    "max_dunning_attempts": 3,
    "default_renewal_behavior": "require_review_for_pending_changes",
    "default_cancellation_behavior": "allow_direct_cancellation",
    "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
  }
}
```

### Errors

| Code  | Error              | Meaning                                                                                                       |
| ----- | ------------------ | ------------------------------------------------------------------------------------------------------------- |
| `400` | `invalid_data`     | Invalid scalar ranges, invalid enum values, invalid retry interval list, or mismatched `max_dunning_attempts` |
| `409` | `conflict`         | Stale `expected_version` — optimistic locking mismatch                                                        |
| `500` | `unexpected_state` | Unexpected workflow or persistence failure                                                                    |
