# Contracts

Learn how to model negotiated sales agreements with dedicated contract billing.

Use contracts to model negotiated sales agreements that require custom pricing, defined service periods, and mid-deal seat changes while keeping your product catalog clean and avoiding complex [subscription schedules](https://docs.stripe.com/api/subscription_schedules.md).

> This feature is in private preview. You can request early access by filling in the form below.

### Get early access to billing contracts.

Enter your email to request access.

```bash
curl https://docs.stripe.com/preview/register \
  -X POST \
  -H "Content-Type: application/json" \
  -H "Referer: https://docs.stripe.com/billing/contracts" \
  -d '{"email": "EMAIL", "preview": "billing_contracts"}'
```

## Manage contracts in the Dashboard

Use the Dashboard to create, edit, activate, and cancel contracts without writing code. Creating and editing contracts in the Dashboard is in preview and only available in sandboxes. In live mode, you can view contracts, but you can’t create or edit them.

Go to the [Contracts page](https://dashboard.stripe.com/test/contracts) in a sandbox to get started. The Dashboard and API use the same Contract objects, so you can manage a contract with either method.

## Compare contracts and subscriptions

Contracts and [subscriptions](https://docs.stripe.com/api/subscriptions.md) support different billing models and can coexist on the same platform.

|  | Contracts | Subscriptions |
| --- | --- | --- |
| Optimized for | Flexibility, with different terms for each customer | Scale, with the same terms across many customers |
| Pricing | Negotiated rates through overrides on top of catalog pricing | Standard catalog pricing |
| Lifecycle | Defined start and end dates | Recurring with no end date unless canceled |
| Driven by | Sales-led negotiations | Customer self-service |

Contracts and subscriptions use the same [products](https://docs.stripe.com/api/products.md) and [prices](https://docs.stripe.com/api/prices.md). For example, you can reference a product priced at 50 USD per seat per month by both a subscription and a contract, with the contract applying negotiated pricing through overrides.

## Understand how contracts work

Contracts include these building blocks for mapping to a negotiated deal:

- **Recurring price terms**: Recurring prices from your catalog, with quantities and service periods.
- **Pricing override terms**: Negotiated rates that differ from your standard catalog pricing (price override or percentage multiplier).
- **License quantity**: Seat or unit counts that you can change mid-contract period.
- **Billing settings**: Collection method and payment terms specific to the deal.
- **One-time fees**: Products billed on explicit dates outside the recurring cycle, such as a setup or implementation fee.

### Contracts lifecycle

Contracts move through four statuses:

| Status | Description |
| --- | --- |
| `draft` | Configuration. No billing occurs. |
| `active` | Billing in effect. Invoices generated. |
| `ended` | End date reached. The contract completed its term. |
| `canceled` | Contract canceled before its end date. |

### Create a contract

Create a contract in `draft` status to map your billing cycle to your negotiated sales agreement, then activate it when you’re ready to begin billing.

#### Dashboard

To create a contract in the Dashboard:

1. In a sandbox, go to the [Contracts page](https://dashboard.stripe.com/test/contracts).
2. Click **Create contract**.
3. Enter a contract number, then select a customer and currency.
4. To add a recurring fee, click **Add item**, select an existing product and price, and set the start date, end date, and quantity.
5. To replace a recurring fee’s sticker price, select the fee, click **Schedule price override**, and enter the new amount and the dates it applies to.
6. To apply a discount or markup, click **Add item**, select **Discount** or **Markup**, then enter a percentage and the date range and recurring fees it applies to.
7. Click **Save draft contract**. Stripe saves the contract in `draft` status.

#### API

Create a contract with a recurring price term that references an existing price in your catalog. Add a pricing override term to replace its unit amount:

```curl
curl -X POST https://api.stripe.com/v2/billing/contracts \
  -H "Authorization: Bearer <<YOUR_SECRET_KEY>>" \
  -H "Stripe-Version: 2026-10-28.preview" \
  --json '{
    "currency": "usd",
    "contract_number": "C-2026-0001",
    "terms": [
        {
            "type": "recurring_price",
            "lookup_key": "base_price",
            "recurring_price": {
                "price": "{{PRICE_ID}}",
                "quantity": "12",
                "starts_at": {
                    "type": "timestamp",
                    "timestamp": "2026-07-01T00:00:00Z"
                },
                "ends_at": {
                    "type": "timestamp",
                    "timestamp": "2027-07-01T00:00:00Z"
                }
            }
        },
        {
            "type": "pricing_override",
            "pricing_override": {
                "type": "overwrite",
                "priority": 20,
                "starts_at": {
                    "type": "timestamp",
                    "timestamp": "2026-07-01T00:00:00Z"
                },
                "ends_at": {
                    "type": "timestamp",
                    "timestamp": "2027-07-01T00:00:00Z"
                },
                "criteria": [
                    {
                        "type": "include",
                        "terms": [
                            {
                                "type": "lookup_key",
                                "lookup_key": "base_price"
                            }
                        ]
                    }
                ],
                "overwrite": {
                    "unit_amount_decimal": "100"
                }
            }
        }
    ],
    "metadata": {},
    "billing_settings": {
        "billing_profile_details": {
            "customer": "{{CUSTOMER_ID}}"
        },
        "collection_settings_details": {
            "collection_method": "send_invoice"
        },
        "bill_settings_details": {
            "invoice": {
                "time_until_due": {
                    "interval": "month",
                    "interval_count": 1
                }
            }
        }
    }
  }'
```

### Activate a contract

Activate a contract to finalize the draft and create the first invoice when applicable. After activation, the contract `status` changes to `active`.

#### Dashboard

To activate a contract in the Dashboard:

1. Go to the [Contracts page](https://dashboard.stripe.com/test/contracts) and open a draft contract.
2. Click **Activate contract**.
3. Review the amount due and invoice date, then click **Activate contract** to confirm.

#### API

Activate the contract with the following request:

```curl
curl -X POST https://api.stripe.com/v2/billing/contracts/{{BILLINGCONTRACTID_ID}}/activate \
  -H "Authorization: Bearer <<YOUR_SECRET_KEY>>" \
  -H "Stripe-Version: 2026-10-28.preview"
```

### Modify terms on an existing contract

Update or remove recurring price terms on a draft or active contract.

#### Dashboard

To modify terms in the Dashboard:

1. Go to the [Contracts page](https://dashboard.stripe.com/test/contracts) and open the contract.
2. Click **Edit contract**.
3. Select an existing recurring fee, discount, or markup in the contract editor to update its details. To remove it, click the remove button in its form.
4. Click **Save changes**.

You can’t change a term’s start date after it starts. You also can’t remove a term after it starts. Instead, update its end date to end it.

#### API

Update the contract with `actions` to modify or remove a term. Select the term by its ID or `lookup_key`.

```curl
curl -X POST https://api.stripe.com/v2/billing/contracts/{{BILLINGCONTRACTID_ID}} \
  -H "Authorization: Bearer <<YOUR_SECRET_KEY>>" \
  -H "Stripe-Version: 2026-10-28.preview" \
  --json '{
    "actions": [
        {
            "type": "update_term",
            "update_term": {
                "term": {
                    "type": "lookup_key",
                    "lookup_key": "base_price"
                },
                "recurring_price": {
                    "quantity": "20"
                }
            }
        }
    ]
  }'
```

You can’t change `starts_at` after a term has started.

To remove a term, use the `remove_term` action type.

```curl
curl -X POST https://api.stripe.com/v2/billing/contracts/{{BILLINGCONTRACTID_ID}} \
  -H "Authorization: Bearer <<YOUR_SECRET_KEY>>" \
  -H "Stripe-Version: 2026-10-28.preview" \
  --json '{
    "actions": [
        {
            "type": "remove_term",
            "remove_term": {
                "term": {
                    "type": "lookup_key",
                    "lookup_key": "base_price"
                }
            }
        }
    ]
  }'
```

You can’t remove a term after it starts. Instead, update its `ends_at` to end it.

### Choose a collection method

Contracts support `send_invoice` and `charge_automatically` collection methods.

#### API

Set `billing_settings.collection_settings_details.collection_method` to one of the following values:

- **`send_invoice`**: Stripe sends the invoice to the customer, who pays it before the due date you set with `time_until_due`. An outstanding invoice makes the contract’s `collection_status` become `past_due` after its due date, and `unpaid` 30 days after that due date.
- **`charge_automatically`**: Stripe attempts payment on each invoice using the default payment method. See [Collect contract payments automatically](https://docs.stripe.com/billing/contracts/automatic-collection.md) to set it up, monitor collection status, and recover failed payments.

For both collection methods, `collection_status` is separate from the contract’s lifecycle `status`. Use `past_due` as a grace period before an outstanding invoice reaches its unpaid deadline. An `unpaid` status means an invoice has reached that deadline, and you should suspend service according to your agreement with the customer. Stripe keeps new cycle invoices in draft while the contract is `unpaid`, for both collection methods. This status doesn’t cancel the contract, suspend service automatically, or stop collection on existing invoices. See [Monitor collection status](https://docs.stripe.com/billing/contracts/automatic-collection.md#monitor-collection-status) for all statuses, deadlines, and webhook events.

### Create a contract with one-time fees 

Use one-time fees to bill fixed charges that aren’t tied to the recurring billing cycle, such as setup fees, implementation charges, or one-off professional services. Each one-time fee references a product from your catalog and specifies the amounts and dates to bill.

#### Dashboard

To add a one-time fee when creating a contract in the Dashboard:

1. In the contract editor, click **Add**, then select **One-time fee**.
2. Select an existing product.
3. Enter the **Amount** and **Bill date**.
4. Click **Save draft contract**.

#### API

Include an `ad_hoc_product` term when creating a contract. Set its `bill_schedule.type` to `custom` and specify the amount and bill date in `bill_schedule.custom`:

```curl
curl -X POST https://api.stripe.com/v2/billing/contracts \
  -H "Authorization: Bearer <<YOUR_SECRET_KEY>>" \
  -H "Stripe-Version: 2026-10-28.preview" \
  --json '{
    "currency": "usd",
    "contract_number": "C-2026-0042",
    "terms": [
        {
            "type": "recurring_price",
            "recurring_price": {
                "price": "{{PRICE_ID}}",
                "quantity": "5",
                "starts_at": {
                    "type": "timestamp",
                    "timestamp": "2026-07-01T00:00:00Z"
                },
                "ends_at": {
                    "type": "timestamp",
                    "timestamp": "2027-07-01T00:00:00Z"
                }
            }
        },
        {
            "type": "ad_hoc_product",
            "ad_hoc_product": {
                "product": "{{PRODUCT_ID}}",
                "bill_schedule": {
                    "type": "custom",
                    "custom": [
                        {
                            "amount": {
                                "value": 50000,
                                "currency": "usd"
                            },
                            "bill_at": {
                                "type": "now"
                            }
                        }
                    ]
                }
            }
        }
    ],
    "billing_settings": {
        "billing_profile_details": {
            "customer": "{{CUSTOMER_ID}}"
        },
        "collection_settings_details": {
            "collection_method": "send_invoice"
        },
        "bill_settings_details": {
            "invoice": {
                "time_until_due": {
                    "interval": "month",
                    "interval_count": 1
                }
            }
        }
    }
  }'
```

Use these fields on the `ad_hoc_product` term:

| Parameter | Description |
| --- | --- |
| [ad_hoc_product.product](https://docs.stripe.com/api/v2/billing-contracts/contracts/create.md?api-version=2026-10-28.preview#v2_create_contracts-terms-ad_hoc_product-product) | The ID of the product to bill. |
| [ad_hoc_product.bill_schedule.custom[].amount](https://docs.stripe.com/api/v2/billing-contracts/contracts/create.md?api-version=2026-10-28.preview#v2_create_contracts-terms-ad_hoc_product-bill_schedule-custom-amount) | The amount to bill, with `value` as a non-negative integer in the currency’s [smallest unit](https://docs.stripe.com/currencies.md#minor-units), and `currency` as a three-letter ISO currency code. For example, use `50000` to charge 500 USD. |
| [ad_hoc_product.bill_schedule.custom[].bill_at](https://docs.stripe.com/api/v2/billing-contracts/contracts/create.md?api-version=2026-10-28.preview#v2_create_contracts-terms-ad_hoc_product-bill_schedule-custom-bill_at) | When to bill this installment. Set `type` to `now` to bill immediately, or `timestamp` with a specific date. |
| [lookup_key](https://docs.stripe.com/api/v2/billing-contracts/contracts/create.md?api-version=2026-10-28.preview#v2_create_contracts-terms-lookup_key) | An optional user-provided key, unique across all terms on the contract, to identify this term for later updates or removal. |

To bill for a one-time fee on a future date instead of immediately, set `bill_schedule.custom[].bill_at.type` to `timestamp`:

```curl
curl -X POST https://api.stripe.com/v2/billing/contracts \
  -H "Authorization: Bearer <<YOUR_SECRET_KEY>>" \
  -H "Stripe-Version: 2026-10-28.preview" \
  --json '{
    "currency": "usd",
    "contract_number": "C-2026-0042",
    "terms": [
        {
            "type": "ad_hoc_product",
            "lookup_key": "implementation_fee",
            "ad_hoc_product": {
                "product": "{{PRODUCT_ID}}",
                "bill_schedule": {
                    "type": "custom",
                    "custom": [
                        {
                            "amount": {
                                "value": 100000,
                                "currency": "usd"
                            },
                            "bill_at": {
                                "type": "timestamp",
                                "timestamp": "2026-10-01T00:00:00Z"
                            }
                        }
                    ]
                }
            }
        }
    ]
  }'
```

### Manage one-time fees on an existing contract 

After creating a contract, you can add one-time fees, update their unbilled installments, or remove one-time fees whose first bill date hasn’t passed.

#### Dashboard

To manage one-time fees in the Dashboard:

1. Go to the [Contracts page](https://dashboard.stripe.com/test/contracts) and open the contract.
2. Click **Edit contract**.
3. To add a fee, click **Add**, select **One-time fee**, and enter its product, amount, and bill date.
4. To change an existing fee, select it in the contract editor and update its details. To remove it, select the fee and click **Remove one-time fee**.
5. Click **Save changes**.

You can’t update or remove a one-time fee that has already been billed on an active contract.

#### API

Update the contract with `actions` to manage one-time fees.

To add a one-time fee to an existing contract:

```curl
curl -X POST https://api.stripe.com/v2/billing/contracts/{{BILLINGCONTRACTID_ID}} \
  -H "Authorization: Bearer <<YOUR_SECRET_KEY>>" \
  -H "Stripe-Version: 2026-10-28.preview" \
  --json '{
    "actions": [
        {
            "type": "add_term",
            "add_term": {
                "type": "ad_hoc_product",
                "ad_hoc_product": {
                    "product": "{{PRODUCT_ID}}",
                    "bill_schedule": {
                        "type": "custom",
                        "custom": [
                            {
                                "amount": {
                                    "value": 25000,
                                    "currency": "usd"
                                },
                                "bill_at": {
                                    "type": "now"
                                }
                            }
                        ]
                    }
                }
            }
        }
    ]
  }'
```

To update an existing one-time fee, select it by ID or `lookup_key` and replace its remaining unbilled installments. This example changes the amount of a scheduled implementation charge while keeping its bill date:

```curl
curl -X POST https://api.stripe.com/v2/billing/contracts/{{BILLINGCONTRACTID_ID}} \
  -H "Authorization: Bearer <<YOUR_SECRET_KEY>>" \
  -H "Stripe-Version: 2026-10-28.preview" \
  --json '{
    "actions": [
        {
            "type": "update_term",
            "update_term": {
                "term": {
                    "type": "lookup_key",
                    "lookup_key": "implementation_fee"
                },
                "ad_hoc_product": {
                    "bill_schedule": {
                        "type": "custom",
                        "custom": [
                            {
                                "amount": {
                                    "value": 150000,
                                    "currency": "usd"
                                },
                                "bill_at": {
                                    "type": "timestamp",
                                    "timestamp": "2026-10-01T00:00:00Z"
                                }
                            }
                        ]
                    }
                }
            }
        }
    ]
  }'
```

To remove a one-time fee before its first bill date:

```curl
curl -X POST https://api.stripe.com/v2/billing/contracts/{{BILLINGCONTRACTID_ID}} \
  -H "Authorization: Bearer <<YOUR_SECRET_KEY>>" \
  -H "Stripe-Version: 2026-10-28.preview" \
  --json '{
    "actions": [
        {
            "type": "remove_term",
            "remove_term": {
                "term": {
                    "type": "lookup_key",
                    "lookup_key": "implementation_fee"
                }
            }
        }
    ]
  }'
```

Updates replace the remaining unbilled installments. Billed installments are immutable. You can remove a one-time fee only before its first bill date.

### Cancel a contract

Cancel a contract to end it before the scheduled end date. You can specify whether to generate credit prorations for unused time.

#### Dashboard

To cancel a contract in the Dashboard:

1. Go to the [Contracts page](https://dashboard.stripe.com/test/contracts) and open an active contract.
2. Click the overflow menu (⋯), then select **Cancel contract**.
3. Choose whether to refund the customer for unused time.
4. Click **Cancel contract immediately**.

#### API

Cancel the contract with the following request:

```curl
curl -X POST https://api.stripe.com/v2/billing/contracts/{{BILLINGCONTRACTID_ID}}/cancel \
  -H "Authorization: Bearer <<YOUR_SECRET_KEY>>" \
  -H "Stripe-Version: 2026-10-28.preview" \
  --json '{
    "proration_behavior": "none"
  }'
```

### List invoices for a contract

After activating a contract, Stripe generates [invoices](https://docs.stripe.com/api/invoices.md) according to its pricing and billing terms.

#### Dashboard

To view a contract’s invoices in the Dashboard:

1. Go to the [Contracts page](https://dashboard.stripe.com/test/contracts) and open the contract.
2. Click the **Invoices** tab.
3. Select an invoice to open its invoice details page.

#### API

Use the [contract](https://docs.stripe.com/api/invoices/list.md#list_invoices-contract) parameter to [retrieve all invoices](https://docs.stripe.com/api/invoices/list.md) associated with a specific contract.

```curl
curl -G https://api.stripe.com/v1/invoices \
  -u "<<YOUR_SECRET_KEY>>:" \
  -H "Stripe-Version: 2026-10-28.preview" \
  -d "contract={{BILLINGCONTRACTID_ID}}"
```

## Testing

Use [test clocks](https://docs.stripe.com/billing/testing.md#test-clocks) to test your contract setup and simulate the advancement of time. Inspect the invoices and event notifications that Stripe generates as time advances.

### Limitations

Contracts don’t support all subscription features. Notable exceptions include the following.

- **Trials**: Contracts don’t have a trial status. To model a trial period, use pricing overrides to reduce pricing.
- **Discounts**: Contracts don’t support coupons and discounts. To reduce pricing, use pricing overrides.
- **Mandates**: Contract payments with `collection_method=charge_automatically` don’t support cards that require mandates.
- **Payment terms**: You can’t set `time_until_due` with `collection_method=charge_automatically`. Stripe attempts payment as soon as we finalize the invoice, so these invoices have no payment term.
- **Metered prices**: Contracts only support licensed prices.
