# Apply custom balances to invoices

Use scripts to customize how customer balances are applied to invoices.

Customer balance application scripts allow you to customize how you apply invoice balances, and override the Stripe default behavior. By default, when a customer has a non-zero invoice balance, Stripe automatically applies it to the next invoice—credits reduce the amount due, while debits increase it. This script extension point gives you more control over when and how much of the balance to apply.

Example use cases include:

- Zero-charge customers while adjusting only their balance when specific conditions are met. For example, only charge when the total amount exceeds a threshold.
- Partially apply customer balances based on custom criteria. For example, only apply large debit balances to avoid inconveniencing customers with small charges on large invoices.
- Implement business-specific balance settlement logic that goes beyond the standard automatic application.

## Customize how you apply balances 

With the [standard customer balance behavior](https://docs.stripe.com/billing/customer/balance.md#details), Stripe automatically applies the full balance to each invoice. This extension point gives you control over balance application, allowing you to:

- Choose whether to apply the balance to specific invoices.
- Apply only a portion of the balance based on your business rules.
- Implement conditional logic that determines when to settle balances.
- Defer charges until accumulated balances reach a threshold.

Your script receives the invoice total and current customer balance, then returns how much of that balance to apply, which gives you control over the balance settlement workflow.

### Stripe-authored scripts

To get you started, Stripe has authored two scripts that address common customer balance application customizations:

- [Minimum amount before collection](https://docs.stripe.com/billing/scripts/stripe-authored.md#minimum-amount-before-collection): Stripe defers the amount owed as a debit to the customer balance when the total is below the [default minimum charge amount](https://docs.stripe.com/currencies.md#minimum-and-maximum-charge-amounts). With this script, you can set a new minimum amount threshold an invoice must surpass to result in collection.
- [Maximum credit per invoice](https://docs.stripe.com/billing/scripts/stripe-authored.md#maximum-credit-per-invoice): By default, Stripe automatically applies the full customer balance to each invoice. This script allows you to put a limit on how much credit you can apply from the customer’s balance toward an invoice.

### Author your own script

To further customize customer balance application behavior, you can [author your own script](https://docs.stripe.com/billing/scripts/author-your-own.md#before-you-begin) in a [subset of TypeScript](https://docs.stripe.com/billing/scripts/script-language.md).

> #### Verify your script
> 
> You’re responsible for verifying that your script reflects your intended functionality. Make sure you don’t enter any proprietary information, confidential information (for example, *PII* (Personally identifiable information (PII) is information that, when used alone or with other relevant data, can identify an individual. Examples include passport numbers, driver's license, mailing address, or credit card information)), or malicious code.

## Before you begin

Before implementing a custom balance application script, learn how [customer balances](https://docs.stripe.com/billing/customer/balance.md) work in Stripe Billing. Understanding debits, credits, and how balances affect invoices helps you design effective custom logic.

For an introduction to scripts and how to deploy them, see the [Scripts overview](https://docs.stripe.com/billing/scripts.md).

See also:

- [Customer balance guide](https://docs.stripe.com/billing/customer/balance.md)
- [Customer Balance Transactions API](https://docs.stripe.com/api/customer_balance_transactions/object.md)
- [Invoice finalization](https://docs.stripe.com/invoicing/overview.md#invoice-lifecycle)

In addition the [global limitations for user-authored scripts](https://docs.stripe.com/billing/scripts/author-your-own.md#before-you-begin), customer balance application scripts have the following limitations:

- Balance application logic doesn’t run for one-off invoices or invoices without an associated subscription.
- This script is configured at the account level. You can’t apply different scripts to individual customers or subscriptions.

## Example implementation

This example implements the `Custom charge threshold` logic. Only charge customers when the total amount (invoice plus balance) exceeds a threshold. Below the threshold, you don’t charge the invoice, and we add the full amount to the customer’s balance for the next billing cycle.

```typescript
import type { Billing, Context } from '@stripe/extensibility-sdk/extensions';
import { type MonetaryAmount } from '@stripe/extensibility-sdk/stdlib';

type Currency = 'usd' | 'eur' | 'cad' | 'jpy' | 'gbp';

/** * Configuration for the script */
interface CustomerBalanceApplicationConfig extends Record<string, unknown> {
  /**
   * @displayName Minimum Amount
   * @exclusiveMinimum :amount 0
   */
  minimumAmount: MonetaryAmount;
}

/**
 * Only charge customers when the total amount (invoice + balance) exceeds the minimum amount.
 * Below the minimum amount, zero-charge the invoice and adjust the customer balance.
 */
export default class MinimumAmountBeforeCollection
  implements Billing.CustomerBalanceApplication<CustomerBalanceApplicationConfig> {
  computeAppliedCustomerBalance(
    input: Billing.CustomerBalanceApplication.CustomerBalanceApplicationInput,
    config: CustomerBalanceApplicationConfig,
    _context: Context
  ): Billing.CustomerBalanceApplication.CustomerBalanceApplicationResult {
    const {minimumAmount} = config;
    const {totalAmount, customerBalance} = input;
    // Calculate the total amount the customer would owe
    // (positive balance is a debit, meaning they owe money)
    const totalOwed = totalAmount.amount.add(customerBalance.amount);

    // If currencies don't match, fall back to default behavior
    if (
      minimumAmount.currency.toLowerCase() !==
      totalAmount.currency.toLowerCase()
    ) {
      return {
        appliedCustomerBalance: {
          amount: customerBalance.amount,
          currency: totalAmount.currency,
        },
      };
    }

    // Below minimum amount: zero-charge the invoice by applying a credit
    // equal to the invoice total
    if (totalOwed.lt(minimumAmount.amount)) {
      return {
        appliedCustomerBalance: {
          amount: totalAmount.amount.neg(),
          currency: totalAmount.currency,
        },
      };
    }

    // At or above minimum amount: apply the full customer balance
    return {
      appliedCustomerBalance: {
        amount: customerBalance.amount,
        currency: totalAmount.currency,
      },
    };
  }
}
```

### Implementation considerations

Consider these key points when implementing threshold based balance behavior.

1. **Calculate the total owed**: Sum the invoice total and customer balance to determine what the customer would owe if the full balance were applied.
1. **Handle currency mismatches**: Always verify that currencies match between the invoice, balance, and threshold. Fall back to default behavior when they don’t.
1. **Apply correct sign conventions**: Negative values create credits that reduce the invoice amount, positive values apply debits that increase it.
1. **Preserve invoice total**: When zero-charging below a threshold, apply a credit equal to the negative invoice total to bring the charge to zero.
1. **Configuration flexibility**: Use a configuration object to make thresholds and other parameters adjustable without code changes.

### How this example works

#### Scenario 1: Below threshold

- Invoice total: 20 USD
- Customer balance: 30 USD debit
- Threshold: 100 USD
- Total owed would be: 50 USD

Since 50 USD is below the 100 USD threshold:

- Apply -20 USD (a credit equal to the invoice total)
- Customer is charged: 0 USD
- New customer balance: 50 USD (to be charged next billing cycle)

#### Scenario 2: At or above threshold

- Invoice total: 80 USD
- Customer balance: 30 USD debit
- Threshold: 100 USD
- Total owed would be: 110 USD

Since 110 USD meets the threshold:

- Apply the full 30 USD debit balance
- Customer is charged: 110 USD
- New customer balance: 0 USD

### SDK reference

For complete TypeScript type definitions and interfaces, see the [Extensibility SDK on GitHub :external: link-to-extensibility-sdk](https://github.com/stripe/extensibility-sdk/tree/master/libs/extensibility-sdk/src/extensions/billing/customer_balance_application.ts).

### Extension method

Implement the `computeAppliedCustomerBalance` function to define your custom balance application logic:

```typescript
export default class MyCustomerBalanceApplicationExtension
  implements Billing.CustomerBalanceApplication<CustomerBalanceApplicationConfig> {
  computeAppliedCustomerBalance(
    input: Billing.CustomerBalanceApplication.CustomerBalanceApplicationInput,
    config: CustomerBalanceApplicationConfig,
    context: Context,
  ): Billing.CustomerBalanceApplication.CustomerBalanceApplicationResult {
    // ...
  }
}
```

#### Parameters

| Field     | Type                               | Description                                                                                                       |
| --------- | ---------------------------------- | ----------------------------------------------------------------------------------------------------------------- |
| `input`   | `CustomerBalanceApplicationInput`  | The invoice total and current customer balance.                                                                   |
| `config`  | `CustomerBalanceApplicationConfig` | Your custom configuration object. You define the structure based on your requirements.                            |
| `context` | `Context`                          | Runtime context including the extension identifier, livemode status, and optional Stripe-specific context values. |

#### Returns

| Field                              | Description                                             |
| ---------------------------------- | ------------------------------------------------------- |
| `CustomerBalanceApplicationResult` | The amount of customer balance to apply to the invoice. |

### Input and output types

#### Input type

```typescript
export interface CustomerBalanceApplicationInput {
  totalAmount: MonetaryAmount;
  customerBalance: MonetaryAmount;
}

export interface MonetaryAmount {
  amount: Decimal;
  currency: Currency;
}
```

##### Field descriptions 

| Field             | Type             | Description                                                                                                                                                                |
| ----------------- | ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `totalAmount`     | `MonetaryAmount` | The total amount of the invoice before you apply any customer balance.                                                                                                     |
| `customerBalance` | `MonetaryAmount` | The current customer balance available to apply. Positive values indicate debits (the customer owes money), negative values indicate credits (you owe the customer money). |
| `amount`          | `Decimal`        | Amount in the currency’s smallest unit (for example, cents for USD).                                                                                                       |
| `currency`        | `Currency`       | Three-letter ISO currency code (for example, “usd”, “eur”).                                                                                                                |

##### Example input

```typescript
{
  "totalAmount": {
    "amount": 5000,
    "currency": "usd"
  },
  "customerBalance": {
    "amount": 1000,
    "currency": "usd"
  }
}
```

In this example:

- The invoice total is 50 USD (5000 cents).
- The customer has a debit balance of 10 USD (1000 cents), meaning they owe you money.

#### Output type

```typescript
export interface CustomerBalanceApplicationResult {
  appliedCustomerBalance: MonetaryAmount;
}
```

##### Field descriptions 

| Field                    | Type             | Description                                                                                                                                                                                                |
| ------------------------ | ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `appliedCustomerBalance` | `MonetaryAmount` | The amount of customer balance to apply to this invoice. Positive values increase the invoice amount (applying a debit), negative values decrease it (applying a credit). Set to zero to apply no balance. |

> #### Automatic balance adjustment
> 
> Stripe automatically ensures that the total amount charged to the customer remains correct by adjusting the customer balance accordingly. Your script only needs to return how much balance to apply. The system handles the accounting to conserve the balance.

##### Example output

```json
{
  "appliedCustomerBalance": {
    "amount": 1000,
    "currency": "usd"
  }
}
```

In this example:

- Apply the full 10 USD debit balance to the invoice.
- You charge the customer 60 USD total (50 USD plus 10 USD).

## Test your script

Before deploying your script to production:

1. Test in a [sandbox](https://docs.stripe.com/sandboxes.md) with various invoice amounts and customer balance scenarios.
1. Verify that currency handling matches your expectations.
1. Confirm that the script handles edge cases (zero balances, mismatched currencies).
1. Review the customer balance transaction history to make sure adjustments are recorded correctly.

## Data validation requirements

Your script must meet these requirements to execute successfully. Violations result in a validation error.

- Return an `AppliedCustomerBalanceResult` with both `amount` and `currency` on every invocation.
- The `currency` in `applied_customer_balance` must match the invoice currency.

## Best practices

We recommend the following best practices when you’re authoring your own custom logic:

- **Handle currency mismatches**: Always check that currencies match between the invoice and customer balance. Fall back to default behavior when they don’t.
- **Respect sign conventions**: Positive values apply debits (increase invoice amount), negative values apply credits (reduce invoice amount).
- **Test edge cases**: Verify that your logic handles zero balances, negative balances (credits), and balances that exceed the invoice total.
- **Document your logic**: Add comments explaining your balance application rules for future maintainers.

## Next steps

- Learn more about [scripts](https://docs.stripe.com/billing/scripts.md)
- See the [script language definition](https://docs.stripe.com/billing/scripts/script-language.md)
