Add changelog entry for checkout_session_params deep-merge fix (#999)

* docs improvements

* many changes

* prompt changes

* add refetch comment

* fix: checkout subscription data

* cus eligibility fixes

* rm cursor thing

---------

Co-authored-by: Ayush Rodrigues <joesj2905@gmail.com>
Co-authored-by: John Yeo <johnyeocx@gmail.com>
Co-authored-by: John Yeo <51376134+johnyeocx@users.noreply.github.com>
Co-authored-by: Ayush <74830628+ay-rod@users.noreply.github.com>
This commit is contained in:
mintlify[bot]
2026-03-17 17:33:52 +00:00
committed by GitHub
parent ef8367c4af
commit 9bd20cb2e9
48 changed files with 2449 additions and 4486 deletions

View File

@@ -63,14 +63,18 @@ Push changes with `atmn push`.
## Billing methods
| Method | Behavior |
|--------|----------|
| **Prepaid** | Customer commits to a quantity at checkout and pays immediately. To change quantity, they update their subscription. |
| **Usage-based** | Customer is billed for the actual number of units at the end of each billing cycle. |
| Method | When charged | Quantity | Best for |
|--------|-------------|----------|----------|
| **Prepaid** | Upfront at purchase | Customer selects a fixed quantity | Seat licenses with committed counts |
| **Usage-based** | End of billing cycle (prorated on changes) | Automatic — tracks actual usage | Seats that fluctuate frequently |
### Prepaid per-unit
With prepaid, the customer selects a quantity when purchasing. Pass the quantity via `options`:
With prepaid, the customer selects a **total quantity** when purchasing. The `quantity` includes any free included amount — Autumn subtracts the included amount and charges for the remainder.
For example, with 5 included seats at \$10/extra seat, a customer who selects `quantity: 10` gets 10 seats total and pays for 5 extra seats (\$50/month).
Pass the quantity via `featureQuantities`:
<CodeGroup>
@@ -79,11 +83,11 @@ import { Autumn } from "autumn-js";
const autumn = new Autumn({ secretKey: "am_sk_..." });
const { data } = await autumn.checkout({
customer_id: "user_123",
plan_id: "pro",
options: [{
feature_id: "seats",
const { data } = await autumn.billing.attach({
customerId: "user_123",
planId: "pro",
featureQuantities: [{
featureId: "seats",
quantity: 10,
}],
});
@@ -94,10 +98,10 @@ from autumn_sdk import Autumn
autumn = Autumn("am_sk_...")
response = await autumn.checkout(
response = await autumn.billing.attach(
customer_id="user_123",
plan_id="pro",
options=[{
feature_quantities=[{
"feature_id": "seats",
"quantity": 10,
}],
@@ -105,13 +109,13 @@ response = await autumn.checkout(
```
```bash cURL
curl -X POST "https://api.useautumn.com/v1/checkout" \
curl -X POST "https://api.useautumn.com/v1/billing/attach" \
-H "Authorization: Bearer am_sk_..." \
-H "Content-Type: application/json" \
-d '{
"customer_id": "user_123",
"plan_id": "pro",
"options": [{
"feature_quantities": [{
"feature_id": "seats",
"quantity": 10
}]
@@ -120,9 +124,15 @@ curl -X POST "https://api.useautumn.com/v1/checkout" \
</CodeGroup>
The customer's balance is set to the total quantity (10). If they're upgrading and already have seats in use, the existing usage is carried over — so a customer with 3 seats in use would see a remaining balance of 7.
<Note>
Autumn does not prevent you from passing a `quantity` lower than the customer's current usage. If the customer has 5 seats in use and you pass `quantity: 3`, the balance goes negative (-2). The `check` endpoint will return `allowed: false`, preventing new seats from being added, but existing seats are not forcibly removed.
</Note>
### Usage-based per-unit
With usage-based billing, track seat additions and removals as they happen. Autumn bills the total at the end of the billing cycle.
With usage-based billing, no quantity is needed at purchase time. Track seat additions and removals as they happen, and Autumn bills for the actual number of seats in use.
<CodeGroup>
@@ -131,11 +141,19 @@ import { Autumn } from "autumn-js";
const autumn = new Autumn({ secretKey: "am_sk_..." });
// Add a seat
await autumn.track({
customer_id: "user_123",
feature_id: "seats",
value: 1,
});
// Remove a seat
await autumn.track({
customer_id: "user_123",
feature_id: "seats",
value: -1,
});
```
```python Python
@@ -143,14 +161,23 @@ from autumn_sdk import Autumn
autumn = Autumn("am_sk_...")
# Add a seat
await autumn.track(
customer_id="user_123",
feature_id="seats",
value=1,
)
# Remove a seat
await autumn.track(
customer_id="user_123",
feature_id="seats",
value=-1,
)
```
```bash cURL
# Add a seat
curl -X POST "https://api.useautumn.com/v1/track" \
-H "Authorization: Bearer am_sk_..." \
-H "Content-Type: application/json" \
@@ -163,6 +190,42 @@ curl -X POST "https://api.useautumn.com/v1/track" \
</CodeGroup>
When a customer purchases the plan, any seats already in use are **automatically reflected** in their subscription from day one. For example, if a customer has 3 seats in use and purchases a plan with 5 included seats at \$10/extra seat:
- Their balance starts at 5 (the included amount)
- The 3 existing seats are carried over, leaving a remaining balance of 2
- No extra charge yet — they're within the included amount
- As they add seats beyond 5, each additional seat is billed at \$10/month with [proration](/documentation/modelling-pricing/proration)
## Existing usage on upgrade
When a customer upgrades from one plan to another, Autumn **automatically carries over** their current seat usage to the new plan. This ensures there's no gap in tracking — existing seats don't disappear or go unbilled.
### Prepaid
The customer's balance is set to their chosen quantity. Existing usage is then deducted from that balance.
> **Example**: Customer has **3 seats** in use. They purchase a plan with 5 included seats, passing `quantity: 10`.
> - Balance is set to 10 (5 included + 5 purchased)
> - 3 existing seats are deducted → **7 remaining**
> - Stripe charges for 10 seats (with 5 in the free tier)
### Usage-based
No quantity is needed. The Stripe subscription quantity is set to the customer's current usage automatically.
> **Example**: Customer has **3 seats** in use. They purchase a plan with 5 included seats at \$10/extra seat.
> - Balance starts at 5 (included amount)
> - 3 existing seats are deducted → **2 remaining**
> - Stripe subscription reflects 3 seats in use (within the free tier, so no extra charge)
> - When they add a 6th seat, billing begins at \$10/seat for the overage
| Scenario | Prepaid (qty: 8) | Usage-based |
|----------|------------------|-------------|
| **3 in use, 5 included** | Balance: 8 → 5 remaining. Charged for 3 extra. | Balance: 5 → 2 remaining. No extra charge. |
| **3 in use, 0 included** | Balance: 8 → 5 remaining. Charged for 8. | Balance: 0 → -3. Charged for 3 seats. |
| **7 in use, 5 included** | Balance: 8 → 1 remaining. Charged for 3 extra. | Balance: 5 → -2. Charged for 2 extra seats. |
## Checking access
Before allowing a user to add a new seat, check if they have capacity:
@@ -176,7 +239,7 @@ const { data } = await autumn.check({
});
if (!data.allowed) {
// Prompt user to purchase more seats
// Prompt user to purchase more seats or upgrade
}
```
@@ -187,7 +250,7 @@ response = await autumn.check(
)
if not response.allowed:
# Prompt user to purchase more seats
# Prompt user to purchase more seats or upgrade
```
```bash cURL
@@ -202,6 +265,10 @@ curl -X POST "https://api.useautumn.com/v1/check" \
</CodeGroup>
For **prepaid**, `allowed` is `true` when the customer has remaining prepaid balance (ie. unused seats).
For **usage-based**, `allowed` is `true` as long as the customer has a usage-based price configured — additional seats are simply billed at the per-unit rate, so there's no hard cap.
## Proration on quantity changes
When a customer increases or decreases their seat count mid-billing-cycle, you can configure how the price adjustment is handled. See [Proration](/documentation/modelling-pricing/proration) for details.

View File

@@ -0,0 +1,286 @@
---
title: Prepaid Pricing
description: Charge customers upfront for a quantity of a feature, and draw from it as usage occurs
---
Prepaid pricing lets customers pay for a fixed quantity of a feature upfront. They select how many units they want at purchase time, pay immediately, and their balance is decremented as they use it.
This is in contrast to [usage-based pricing](/documentation/modelling-pricing/usage-based-pricing), where customers are billed for actual usage at the end of a billing cycle.
> **Example** <br />
> An AI platform has a Pro plan at \$20/month that includes:
> - **API Credits**: 500 included for free, then \$10 per 1,000 credits per month (consumable)
> - **Seats**: 3 included for free, then \$5 per seat per month (non-consumable)
>
> A customer selects 3,000 credits and 10 seats. They pay \$20 base + \$25 for 2,500 extra credits + \$35 for 7 extra seats = \$80/month.
## Setting up
<Tabs>
<Tab title="CLI">
Create your features and add them to a plan with `prepaid` prices:
```ts autumn.config.ts
import { feature, item, plan } from 'atmn';
export const apiCredits = feature({
id: 'api_credits',
name: 'API Credits',
type: 'metered',
consumable: true,
});
export const seats = feature({
id: 'seats',
name: 'Seats',
type: 'metered',
consumable: false,
});
export const pro = plan({
id: 'pro',
name: 'Pro',
price: { amount: 20, interval: 'month' },
items: [
item({
featureId: apiCredits.id,
included: 500,
price: {
amount: 10,
billingUnits: 1000,
billingMethod: 'prepaid',
interval: 'month',
},
}),
item({
featureId: seats.id,
included: 3,
price: {
amount: 5,
billingMethod: 'prepaid',
interval: 'month',
},
}),
],
});
```
Push changes with `atmn push`.
</Tab>
<Tab title="Dashboard">
1. Navigate to **Plans** and create or edit a plan
2. Add your features:
- A `metered`, `consumable` feature for credits (e.g., "API Credits") — set an **included** amount (500), a **price** ($10 per 1,000 per month), and billing method **Prepaid**
- A `metered`, `non-consumable` feature for seats (e.g., "Seats") — set an **included** amount (3), a **price** ($5 per seat per month), and billing method **Prepaid**
3. Save the plan
</Tab>
</Tabs>
## How it works
When a plan has prepaid features, customers select a **quantity** at purchase time. This quantity determines:
- **How many units are granted** as their balance
- **How much they're charged**, based on the price and billing units
The `quantity` is the **total** number of feature units the customer will receive, including any included amount.
Using our example plan:
- A customer selects **3,000 API credits**. 500 are included, so they pay for 2,500 → \$10 × (2,500 / 1,000) = **\$25/month** for credits.
- The same customer selects **10 seats**. 3 are included, so they pay for 7 → \$5 × 7 = **\$35/month** for seats.
<Note>
If you pass a `quantity` equal to or less than the included amount, the customer gets the included amount and pays nothing extra for that feature.
</Note>
## Passing `feature_quantities`
When attaching a plan or updating a subscription that contains prepaid features, use the `feature_quantities` parameter to specify how many units the customer wants.
### Attaching a plan
Pass a `feature_quantities` entry for each prepaid feature on the plan:
<CodeGroup>
```typescript TypeScript
import { Autumn } from "autumn-js";
const autumn = new Autumn({ secretKey: "am_sk_..." });
const { data } = await autumn.billing.attach({
customerId: "user_123",
planId: "pro",
featureQuantities: [
{ featureId: "api_credits", quantity: 3000 },
{ featureId: "seats", quantity: 10 },
],
});
```
```python Python
from autumn_sdk import Autumn
autumn = Autumn("am_sk_...")
response = await autumn.billing.attach(
customer_id="user_123",
plan_id="pro",
feature_quantities=[
{ "feature_id": "api_credits", "quantity": 3000 },
{ "feature_id": "seats", "quantity": 10 },
],
)
```
```bash cURL
curl -X POST "https://api.useautumn.com/v1/billing/attach" \
-H "Authorization: Bearer am_sk_..." \
-H "Content-Type: application/json" \
-d '{
"customer_id": "user_123",
"plan_id": "pro",
"feature_quantities": [
{ "feature_id": "api_credits", "quantity": 3000 },
{ "feature_id": "seats", "quantity": 10 }
]
}'
```
</CodeGroup>
### Updating a subscription
To change prepaid quantities on an existing subscription, use `billing.update`. For example, to add more seats mid-cycle:
<CodeGroup>
```typescript TypeScript
await autumn.billing.update({
customerId: "user_123",
planId: "pro",
featureQuantities: [
{ featureId: "api_credits", quantity: 3000 },
{ featureId: "seats", quantity: 15 },
],
});
```
```python Python
await autumn.billing.update(
customer_id="user_123",
plan_id="pro",
feature_quantities=[
{ "feature_id": "api_credits", "quantity": 3000 },
{ "feature_id": "seats", "quantity": 15 },
],
)
```
```bash cURL
curl -X POST "https://api.useautumn.com/v1/billing/update" \
-H "Authorization: Bearer am_sk_..." \
-H "Content-Type: application/json" \
-d '{
"customer_id": "user_123",
"plan_id": "pro",
"feature_quantities": [
{ "feature_id": "api_credits", "quantity": 3000 },
{ "feature_id": "seats", "quantity": 15 }
]
}'
```
</CodeGroup>
See [Updating Subscriptions](/documentation/customers/updating-subscriptions) for more on previewing changes. When quantities change mid-cycle, Autumn can prorate the charge — see [Proration](/documentation/modelling-pricing/proration) for configuration options.
## Understanding prepaid balances
Once a customer is attached to a plan with prepaid features, their balance `breakdown` distinguishes between what was included for free and what was purchased.
| Field | Description |
|-------|-------------|
| `included_grant` | The amount granted by the plan for free — the "included" amount configured on the plan item. |
| `prepaid_grant` | The amount purchased via `feature_quantities` — the quantity minus the included amount. |
| `granted` | Top-level total: `included_grant + prepaid_grant` summed across all breakdown items. |
| `remaining` | How much is left to use. |
| `usage` | How much has been consumed. |
Using the plan from our setup, a customer who attaches with 3,000 credits and 10 seats will have:
```json expandable
{
"api_credits": {
"feature_id": "api_credits",
"granted": 3000,
"remaining": 3000,
"usage": 0,
"unlimited": false,
"overage_allowed": false,
"breakdown": [
{
"id": "cus_ent_abc123",
"plan_id": "pro",
"included_grant": 500,
"prepaid_grant": 2500,
"remaining": 3000,
"usage": 0,
"reset": {
"interval": "month",
"resets_at": 1773851121437
},
"price": {
"amount": 10,
"billing_units": 1000,
"billing_method": "prepaid"
},
"expires_at": null
}
]
},
"seats": {
"feature_id": "seats",
"granted": 10,
"remaining": 10,
"usage": 0,
"unlimited": false,
"overage_allowed": false,
"breakdown": [
{
"id": "cus_ent_def456",
"plan_id": "pro",
"included_grant": 3,
"prepaid_grant": 7,
"remaining": 10,
"usage": 0,
"reset": null,
"price": {
"amount": 5,
"billing_units": 1,
"billing_method": "prepaid"
},
"expires_at": null
}
]
}
}
```
Use the [check](/documentation/customers/check) endpoint before allowing a customer to use a prepaid feature, and [track](/documentation/customers/tracking-usage) usage afterwards to decrement their balance.
## Prepaid vs usage-based
| | Prepaid | Usage-based |
|---|---|---|
| **When charged** | Upfront at purchase | End of billing cycle |
| **Customer selects quantity** | Yes, via `feature_quantities` | No |
| **Balance behavior** | Decremented as usage occurs | Accumulated and billed |
| **Best for** | Credits, top-ups, seat licenses | Metered APIs, storage, bandwidth |

View File

@@ -6,7 +6,7 @@ description: Handle mid-cycle plan changes with prorated billing
Proration adjusts billing when a customer changes their subscription mid-cycle — whether upgrading to a higher plan, downgrading, or changing the quantity of a non-consumable feature like seats. Autumn calculates the prorated amount and either charges or credits the customer.
> **Example** <br />
> A customer on a $20/month plan upgrades to a $50/month plan halfway through the billing cycle. They're charged $15 (the prorated difference for the remaining half of the month).
> A customer on a \$20/month plan upgrades to a \$50/month plan halfway through the billing cycle. They're charged \$15 (the prorated difference for the remaining half of the month).
## Setting up

View File

@@ -1,12 +1,12 @@
---
title: Recurring Plans
description: Set up recurring subscription plans for your customers
description: Grant customers a recurring allowance of consumable features like messages, credits, or API calls
---
Subscriptions are the most common way to charge customers on a recurring basis. A subscription plan has a fixed base price that customers pay at a regular interval (monthly, quarterly, annually), and can include features with usage limits or additional usage-based charges.
Recurring plans let you grant customers a fixed allowance of consumable features -- like messages, credits, or API calls -- that resets each billing period. Customers pay a base price at a regular interval (monthly, quarterly, annually), and receive a fresh grant of their included features at the start of each cycle.
> **Example** <br />
> A project management tool offers a Pro plan at $20/month that includes 10 seats, 50GB storage, and SSO access.
> An AI writing tool offers a Pro plan at $20/month that grants 1,000 messages per month. When the billing period resets, the customer's message balance is reset back to 1,000.
## Setting up
@@ -25,12 +25,6 @@ export const messages = feature({
consumable: true,
});
export const sso = feature({
id: 'sso',
name: 'SSO',
type: 'boolean',
});
export const pro = plan({
id: 'pro',
name: 'Pro',
@@ -41,9 +35,6 @@ export const pro = plan({
included: 1000,
reset: { interval: 'month' },
}),
item({
featureId: sso.id,
}),
],
});
```
@@ -57,7 +48,7 @@ Push changes with `atmn push`.
2. Click **Create Plan**
3. Set a **name** and **ID** for the plan (e.g., "Pro", `pro`)
4. Under **Price**, set the amount and select a billing interval (`month`, `quarter`, `semi_annual`, or `year`)
5. Add features to the plan set grant amounts, reset intervals, and prices as needed. These will be granted to the customer once they purchase the plan.
5. Add consumable features to the plan -- set grant amounts and reset intervals. These will be granted to the customer each billing period once they subscribe.
6. Save your changes
</Tab>
@@ -182,30 +173,6 @@ curl -X POST "https://api.useautumn.com/v1/attach" \
"expiresAt": null
}
]
},
"sso": {
"featureId": "sso",
"granted": 1,
"remaining": 1,
"usage": 0,
"unlimited": false,
"overageAllowed": false,
"maxPurchase": null,
"nextResetAt": null,
"breakdown": [
{
"id": "cus_ent_def456",
"planId": "pro",
"includedGrant": 1,
"prepaidGrant": 0,
"remaining": 1,
"usage": 0,
"unlimited": false,
"reset": null,
"price": null,
"expiresAt": null
}
]
}
}
}
@@ -215,8 +182,8 @@ curl -X POST "https://api.useautumn.com/v1/attach" \
When a subscription is created, Autumn:
1. Creates a Stripe subscription with the plan's prices
2. Provisions [balances](/documentation/concepts/balances) for each feature in the plan
3. Starts the billing cycle based on the plan's interval
2. Grants the customer their included [balances](/documentation/concepts/balances) for each consumable feature
3. Starts the billing cycle -- balances reset automatically at the start of each period
## Billing intervals
@@ -234,6 +201,15 @@ You can create a separate plan for each interval you want to support. For exampl
You can also configure a custom `interval_count` to charge at non-standard intervals (e.g., every 2 months).
### Billing interval vs reset interval
The billing interval (how often the customer is charged) and the reset interval (how often their feature balance replenishes) are configured independently. They don't have to match.
> **Example** <br />
> A plan billed at $200/year could grant 100 messages/month. The customer pays once a year, but their message balance resets to 100 every month.
This is useful when you want to offer an annual discount while still metering usage on a shorter cycle.
## Managing subscriptions
Once a customer has an active subscription, you can manage upgrades, downgrades, and cancellations. See [Managing Subscriptions](/documentation/customers/s) for details on:

View File

@@ -6,7 +6,7 @@ description: Bill customers based on actual usage at the end of each billing per
Pay-per-use (usage-based) pricing charges customers based on how much of a feature they actually consume, billed at the end of each billing period. This is ideal for products where usage varies significantly between customers.
> **Example** <br />
> A notification service charges $1 per 1,000 notifications sent. A customer who sends 5,000 notifications in a month pays $5 at the end of that month.
> A notification service charges \$1 per 1,000 notifications sent. A customer who sends 5,000 notifications in a month pays \$5 at the end of that month.
## Setting up