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

# Settings

> Configure subscription auto-cancellation, invoice numbering, and wallet balance alerts at the tenant and environment level.

Settings in Flexprice control behavior for respective environment against tenant, providing complete isolation between different environments within and across tenants. All settings are scoped to per (tenant, environment) pair, validated on write, cached for one hour, and audited.

**Benefits:**

* **Tenant and environment isolation** — Each tenant and environment has its own settings; no cross-contamination
* **Flexible updates** — Partial updates supported; only send the fields you want to change
* **Automatic caching** — Settings are cached for one hour to reduce latency
* **Audit trail** — All changes tracked with user and timestamp
* **Validated on write** — Strict type checking and value constraints prevent invalid configuration

## Available Settings

Flexprice supports the following setting keys:

* **Subscription Configuration** (`subscription_config`) — Controls subscription auto-cancellation for unpaid invoices
* **Invoice Configuration** (`invoice_config`) — Controls invoice number generation and due date calculation
* **Wallet Balance Alert Configuration** (`wallet_balance_alert_config`) —  Wallet balance alert thresholds configurations per tenant per environment
* **Bonus Credits Topup Configuration** (`bonus_credits_topup_config`) — Slab-based bonus credit rules applied automatically to purchased wallet top-ups
* **Custom Currency Configuration** (`custom_currency_config`): currencies of your own that the catalogue can be priced in, and the fiat currency invoices are denominated in

***

## Subscription Configuration

**Key:** `subscription_config`

Controls subscription auto-cancellation for unpaid invoices. When enabled, subscriptions are automatically cancelled after grace period if invoices remain unpaid.

### Schema

```json theme={null}
{
  "grace_period_days": number,
  "auto_cancellation_enabled": boolean
}
```

* **`grace_period_days`** — Required for new settings; optional on update. Integer ≥ 1, no decimals. Number of days after invoice due date before auto-cancellation.
* **`auto_cancellation_enabled`** — Optional; defaults to `false`. Boolean. Enable or disable auto-cancellation for this tenant and environment.

### Default Values

When creating a new setting via API, defaults are:

```json theme={null}
{
  "grace_period_days": 3,
  "auto_cancellation_enabled": false
}
```

### What Happens When Auto-Cancellation Is Enabled

When you enable auto-cancellation and set a grace period:

* **Subscriptions with overdue unpaid invoices** — If an invoice remains unpaid past its due date plus the grace period, the subscription is cancelled immediately (not at the end of the billing period).
* **You get notified** — A `subscription.canceled` webhook is sent so you can sync your systems.
* **Clean shutdown** — Future credit grants for that subscription are cancelled, and a final invoice is generated for any partial period used.
* **Audit trail** — Cancellations are recorded with reason and metadata so you can see why and when a subscription was cancelled.

### Validation

* **New settings:** `grace_period_days` required, integer ≥ 1, no decimals. `auto_cancellation_enabled` optional, boolean, default `false`.
* **Updates:** Partial updates allowed; only provided fields validated; omitted fields unchanged.

***

## Invoice Configuration

**Key:** `invoice_config`

Controls invoice number generation (prefix, format, sequence, timezone) and due date calculation.

### Schema

```json theme={null}
{
  "prefix": string,
  "format": string,
  "start_sequence": number,
  "timezone": string,
  "separator": string,
  "suffix_length": number,
  "due_date_days": number
}
```

* **`prefix`** — Required for new settings; optional on update. Non-empty string, not only whitespace. Invoice number prefix (e.g. `"INV"`).
* **`format`** — Required for new settings; optional on update. One of `YYYYMM`, `YYYYMMDD`, `YYMMDD`, `YY`, `YYYY`. Date format in invoice number.
* **`start_sequence`** — Required for new settings; optional on update. Integer ≥ 0, no decimals. Starting sequence number.
* **`timezone`** — Required for new settings; optional on update. Valid IANA timezone (e.g. `America/New_York`, `UTC`) or common abbreviation (e.g. `EST`, `GMT`). Timezone for date formatting.
* **`separator`** — Required for new settings; optional on update. String (empty allowed). Character(s) between prefix, date, and sequence (e.g. `"-"`).
* **`suffix_length`** — Required for new settings; optional on update. Integer 1–10. Number of digits for sequence (padded with zeros).
* **`due_date_days`** — Optional; defaults to `1`. Integer ≥ 0, no decimals. Number of days after invoice creation to set due date.

### Default Values

When creating a new setting via API, defaults are:

```json theme={null}
{
  "prefix": "INV",
  "format": "YYYYMM",
  "start_sequence": 1,
  "timezone": "UTC",
  "separator": "-",
  "suffix_length": 5,
  "due_date_days": 1
}
```

### What You Get

Invoice numbers are generated in the format you configure: prefix, optional separator, date (based on your format and timezone), then a zero-padded sequence. Each tenant and environment has its own sequence, so numbers stay unique and predictable. The sequence resets according to the date format (e.g. monthly for `YYYYMM`, daily for `YYYYMMDD`).

**Example with separator:**

Configuration: `prefix: "INV"`, `format: "YYYYMM"`, `separator: "-"`, `suffix_length: 5`.

Generated: `INV-202501-00001`, `INV-202501-00002`.

**Example without separator:**

Configuration: `prefix: "INV"`, `format: "YYYYMM"`, `separator: ""`, `suffix_length: 5`.

Generated: `INV20250100001`, `INV20250100002`.

### Supported Timezones

* **IANA names (recommended):** `America/New_York`, `Europe/London`, `Asia/Tokyo`, `UTC`.
* **Common abbreviations:** `EST`, `CST`, `MST`, `PST`, `GMT`, `CET`, `EET`, `IST`, `JST`, `KST`, `AEST`, `AWST`, and more.

### Validation

* **New settings:** All fields except `due_date_days` required; see constraints above.
* **Updates:** Partial updates allowed; same rules for provided fields; omitted fields unchanged.

***

## Wallet Balance Alert Configuration

**Key:** `wallet_balance_alert_config`

Sets the **default** balance alert configuration for the tenant and environment. It applies only to wallets that do not have their own alert settings. Per-wallet alert configuration is done via [Wallet Sentinel Alerts](/docs/wallet/low-balance-alert) (or `alert_settings` on the wallet in the API).

### What This Setting Controls

* **When enabled** — Wallets in this tenant and environment that have no per-wallet alert settings use this config as their default. Balance alerts run for those wallets using the thresholds you set here.
* **When disabled** — Wallets that would otherwise use this default do not receive balance alerts until they have their own alert settings or you turn this setting back on.
* **Per-wallet overrides** — Any wallet with its own `alert_settings` always uses those; this setting only applies to wallets without per-wallet config.

Resolution order for a given wallet: Flexprice uses the wallet’s own alert settings if present; otherwise it uses this tenant-and-environment default. If the default is disabled, wallets without per-wallet settings do not receive balance alerts.

### Schema

```json theme={null}
{
  "alert_enabled": boolean,
  "alert_threshold_type": "absolute" | "percentage",
  "critical": { "threshold": string, "condition": "below" },
  "warning":  { "threshold": string, "condition": "below" },
  "info":     { "threshold": string, "condition": "below" }
}
```

* **`alert_enabled`**: Required. Boolean. Turn alerts on or off at tenant and environment level.

* **`alert_threshold_type`**: Optional. Defaults to `"absolute"` when omitted. The threshold type applies to all three levels, so Critical, Warning and Info are always read the same way.

  1. **`"absolute"`**: Thresholds are fixed amounts denominated in the customer's wallet currency. On a USD denominated wallet, a threshold of `10` triggers when the balance falls below \$10. Negative values are allowed, so `-5` triggers when a post-paid wallet has gone \$5 below zero.
  2. **`"percentage"`**: Thresholds are specified as a percentage of the credits granted during the customer's current billing period. For example, a threshold of `20` triggers when the ongoing balance falls below 20% of the credits granted in that billing period. If the customer has no active subscription, the wallet's total lifetime credits granted is used as the reference amount. Values must be between 0 and 100.

  See [Threshold Types](/docs/wallet/low-balance-alert#threshold-types) for a full comparison of the available threshold types.

* **`critical`**, **`warning`**, **`info`**: Optional. Each has:

  * **`threshold`**: String. Read as an amount or a percentage according to `alert_threshold_type`.
  * **`condition`**: `"below"`. Wallet balance alerts trigger on a falling balance.

### Default Value

When no custom value is stored (or after DELETE), the default is:

```json theme={null}
{
  "critical": { "threshold": "0", "condition": "below" },
  "alert_enabled": false
}
```

### Validation

* If `alert_enabled` is `true`, at least one of `critical`, `warning`, or `info` must be present.
* A critical threshold is required when a warning threshold is set.
* Thresholds must ascend by severity: critical \< warning \< info.

### Alert behavior (same as per-wallet alerts)

Once a wallet is using alert config (either its own or this default), behavior matches [Wallet Sentinel Alerts](/docs/wallet/low-balance-alert): balance is monitored against the thresholds, **Info** / **Warning** / **Critical** are raised when thresholds are crossed, state is updated on the wallet, and webhooks are sent when alert state changes.

***

## Bonus Credits Topup Configuration

**Key:** `bonus_credits_topup_config`

Defines slab-based rules for granting bonus credits automatically on purchased wallet top-ups. When enabled, a top-up's credit amount is matched against a table of thresholds, and the matching slab's bonus is granted alongside the purchase.

### Schema

```json theme={null}
{
  "enabled": boolean,
  "slabs": [
    {
      "threshold": string,
      "operator": "gte",
      "bonus": { "type": "flat" | "percentage", "value": string },
      "expiration_duration": number,
      "expiration_duration_unit": "DAY" | "WEEK" | "MONTH" | "YEAR"
    }
  ]
}
```

* **`enabled`** — Required. Boolean. Turn automatic slab-based bonus resolution on or off for this tenant and environment.
* **`slabs`** — Required and non-empty if `enabled` is `true`; optional otherwise. Array of slab objects, evaluated in list order, so they must be sorted **descending** by `threshold`. The first slab a top-up's credit amount clears is the one that applies.
  * **`threshold`** — Required. Decimal string ≥ 0. The credit amount being purchased is compared against this value.
  * **`operator`** — Required. Only `gte` is accepted; the top-up's credit amount must be greater than or equal to `threshold` to match.
  * **`bonus.type`** — Required. `flat` or `percentage`.
  * **`bonus.value`** — Required. Decimal string ≥ 0. For `flat`, this is the bonus credit amount added as-is. For `percentage`, this is a percentage of the credits being purchased.
  * **`expiration_duration`** / **`expiration_duration_unit`** — Optional; must be set together or not at all. Sets an expiry for bonus credits granted from this slab, unless the top-up request already sets `bonus_credits_expiry_date_utc` explicitly. Unit is one of `DAY`, `WEEK`, `MONTH`, `YEAR`.

### Default Values

When creating a new setting via API, defaults are:

```json theme={null}
{
  "enabled": false,
  "slabs": []
}
```

### What Happens When Enabled

* **Applies only to purchased credits** — Slab resolution runs only for top-ups with `transaction_reason` set to `PURCHASED_CREDIT_DIRECT` or `PURCHASED_CREDIT_INVOICED` (including pay-first checkout). Free credit top-ups never receive a bonus.
* **Manual override skips resolution** — If the top-up request sets `bonus_credits_to_add` directly, slab resolution does not run for that top-up.
* **Bonus is a separate transaction** — The bonus is recorded as its own wallet transaction with `transaction_reason: PURCHASED_CREDIT_BONUS`, linked to the purchase transaction via `parent_transaction_id`. It shares the purchase transaction's status and completes with it.

See [Top-Up Wallet](/docs/wallet/top-up#bonus-credits-on-top-up) for how slabs resolve against a purchase, the manual override, and how the bonus transaction is recorded. See the [Top-Up Wallet API Reference](/api-reference/wallets/top-up-wallet) for the `bonus_credits_to_add` and `bonus_credits_expiry_date_utc` request fields.

### Validation

* **New settings:** `enabled` required, boolean. If `enabled` is `true`, `slabs` required, non-empty.
* **Slab constraints:** `operator` must be `gte`; `threshold` ≥ 0; `bonus.type` one of `flat`, `percentage`; `bonus.value` ≥ 0; `expiration_duration` and `expiration_duration_unit` must both be set or both omitted; slabs must be sorted strictly descending by `threshold`.
* **Updates:** Partial updates allowed; only provided fields validated; omitted fields unchanged.

## Custom Currency Configuration

**Key:** `custom_currency_config`

Defines currencies of your own, such as credits, and the fiat currency invoices are denominated in. Prices, subscriptions, wallets, addons, and coupons can then be created in a configured currency, or in any of the fiat currencies listed in its conversion factors.

### Schema

```json theme={null}
{
  "custom_currencies": {
    "<code>": {
      "name": string,
      "symbol": string,
      "fiat_conversion_factors": { "<fiat_code>": string }
    }
  },
  "default_fiat_currency": string
}
```

* **`custom_currencies`**: Optional. Map keyed by a 3-character currency code. When empty, only Flexprice's supported fiat currencies are accepted, therefore a custom code must be configured here before anything can be created in it.
  * **`name`**: Required. Display name, for example `FinePrint Credits`.
  * **`symbol`**: Required. Shown wherever an amount in this currency is displayed.
    * **`fiat_conversion_factors`**: Required, at least one entry. Decimal string > 0 per fiat currency. The factor is how much fiat one unit of this currency is worth, so `"usd": "0.10"` means one unit is \$0.10.
* **`default_fiat_currency`**: Required when `custom_currencies` is non-empty. The currency every invoice is issued in.

### Example

```json theme={null}
{
  "custom_currencies": {
    "fpc": {
      "name": "FinePrint Credits",
      "symbol": "FPC",
      "fiat_conversion_factors": { "usd": "0.10", "inr": "8.50" }
    }
  },
  "default_fiat_currency": "usd"
}
```

### Default Values

When creating a new setting via API, defaults are:

```json theme={null}
{
  "custom_currencies": {},
  "default_fiat_currency": ""
}
```

### What Happens When Configured

* **Currencies are restricted**: Creating a price, subscription, wallet, addon, or coupon in a currency that is neither a configured code nor one of the mapped fiat currencies is rejected. The error names both sets.
* **Invoices are issued in fiat**: Every invoice uses `default_fiat_currency`, with the pre-conversion amounts kept on the invoice and its line items in a `custom_currency` object.
* **The rate is frozen at finalization**: Editing a factor afterwards does not change an invoice that is already finalized.

### Validation

* **Codes:** Exactly 3 characters. Case-insensitive and stored lowercase, so two codes differing only in case collide.
* **Factors:** Every factor must be a positive decimal.
* **Default currency:** Required when `custom_currencies` is non-empty, and cannot itself be a custom currency code. Every custom currency must define a factor for it.
* **Matching fiat currencies:** Every custom currency must define factors for the same fiat currencies. If one defines `inr` and another does not, the update is rejected.

***

## API Endpoints

### Get Setting

```
GET /v1/settings/:key
```

**Parameters**:

* `key` (path): Required. One of: `subscription_config`, `invoice_config`

**Response**:

```json theme={null}
{
  "value": {
    // Setting specific fields based on key type
  },
  "tenant_id": "string",
  "environment_id": "string",
  "created_at": "2024-01-01T00:00:00Z",
  "updated_at": "2024-01-01T00:00:00Z"
}
```

**Error Responses**:

* `404 Not Found`: Setting not found for tenant × environment
* `400 Bad Request`: Invalid setting key
* `403 Forbidden`: Missing tenant or environment context

### Create/Update Setting

```
PUT /v1/settings/:key
```

**Parameters**:

* `key` (path): Required. One of: `subscription_config`, `invoice_config`

**Request**:

```json theme={null}
{
  "value": {
    // Setting specific fields based on key type
  }
}
```

**Response**:

```json theme={null}
{
  "value": {
    // Complete setting after operation
  },
  "tenant_id": "string",
  "environment_id": "string",
  "created_at": "2024-01-01T00:00:00Z",
  "updated_at": "2024-01-01T00:00:00Z"
}
```

**Error Responses**:

* `400 Bad Request`: Invalid setting key or validation failed
* `403 Forbidden`: Missing tenant or environment context

**Behavior**:

* Single endpoint handles both creation and updates
* If setting doesn't exist for tenant × environment:
  * Creates new setting
  * All required fields must be provided
  * Default values applied for optional fields
* If setting exists for tenant × environment:
  * Updates existing setting
  * Supports partial updates
  * Only provided fields are validated
  * Omitted fields retain their existing values
  * No defaults are applied

### Delete Setting

```
DELETE /v1/settings/:key
```

**Parameters**:

* `key` (path): Required. One of: `subscription_config`, `invoice_config`

**Response**:

```json theme={null}
{
  "message": "Setting deleted successfully"
}
```

**Error Responses**:

* `404 Not Found`: Setting not found for tenant × environment
* `400 Bad Request`: Invalid setting key
* `403 Forbidden`: Missing tenant or environment context

***

## Use Cases

### Subscription Auto-Cancellation

* **SaaS with trial plans** — Auto-cancel free trials after grace period if no payment method is added
* **B2B billing** — Cancel subscriptions with overdue invoices after a grace period (e.g. 30 days)
* **Compliance** — Automatically stop service for customers who haven't paid within the grace period

### Invoice Numbering

* **Multi-region operations** — Use timezone to generate invoice numbers in the customer's local time
* **Custom branding** — Set prefix and separator to match your invoice format (e.g. `ACME-202501-00001`)
* **Sequence isolation** — Each tenant and environment has its own sequence; no conflicts

### Wallet Balance Alerts (Tenant and Environment Default)

* **Enable alerts for all wallets** — Set tenant and environment default so new wallets inherit alert config
* **Disable alerts globally** — Turn off async consumer for that environment by setting `alert_enabled: false`
* **Fallback for wallets without config** — Wallets with no `alert_settings` use this default

### Bonus Credits on Top-Up

* **Volume incentives** — Grant a larger bonus on bigger top-ups (e.g. 10% bonus at \$200+) to encourage customers to purchase more credits at once
* **Flat promotional bonus** — Grant a fixed bonus amount for top-ups that clear a lower threshold (e.g. 50 bonus credits at \$100+)
* **Automatic, no per-request work** — Configure the slab table once; the bonus is resolved on every purchased-credit top-up without callers passing bonus fields

***

## Best Practices

💡 **Send required fields on create** — When creating a new setting, include all required fields; defaults apply only on API create.

💡 **Use partial updates** — Send only the fields you want to change; omitted fields keep their existing values.

💡 **Prefer IANA timezones** — For `invoice_config`, use IANA names (e.g. `America/New_York`) instead of abbreviations for clarity and daylight saving time support.

💡 **Set a default for wallet balance alerts** — Use `wallet_balance_alert_config` to define default thresholds for all wallets in this tenant and environment that don’t have their own alert settings. Enable it so those wallets get balance alerts; disable or DELETE to turn alerts off for them.

💡 **Restrict who can change settings** — Limit setting changes to admin users; use tenant-scoped API keys and review audit logs.

💡 **Match grace period to your dunning process** — Set `grace_period_days` to align with how long you allow overdue invoices before cancelling (e.g. after how many reminder emails or days).

💡 **Monitor auto-cancellation outcomes** — Use `subscription.canceled` webhooks to see which subscriptions were cancelled and adjust grace period or dunning if needed.

💡 **Use invoice prefix and format for traceability** — A clear prefix and consistent date format in invoice numbers make it easier to match invoices to periods and environments.

💡 **Combine with per-wallet alerts** — Set `wallet_balance_alert_config` as the default, then override on specific wallets via [Wallet Sentinel Alerts](/docs/wallet/low-balance-alert) where you need different thresholds.

💡 **Sort slabs descending, and use round thresholds** — Since the first matching slab wins, keep `slabs` sorted from highest to lowest `threshold` and pick thresholds that make the applicable bracket predictable at a glance.

***

## Related Documentation

* [Wallet Sentinel Alerts](/docs/wallet/low-balance-alert) — Configure per-wallet balance alerts
* [Top-Up Wallet](/docs/wallet/top-up#bonus-credits-on-top-up) — Slab-based and manual bonus credits on purchased wallet top-ups
* [Subscriptions](/docs/subscriptions/customers-create-subscription) — Manage customer subscriptions
* [Invoices](/docs/invoices/overview) — Invoice lifecycle and payment tracking


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.