docs wip pricing
This commit is contained in:
@@ -26,12 +26,66 @@ A credit system is made up of a list of [features](/documentation/concepts/featu
|
||||
system.
|
||||
</Warning>
|
||||
|
||||
<Tabs>
|
||||
<Tab title="CLI">
|
||||
|
||||
Define metered features, then create a `credit_system` feature with a `creditSchema` that maps each feature to a credit cost:
|
||||
|
||||
```ts autumn.config.ts
|
||||
import { feature, item, plan } from 'atmn';
|
||||
|
||||
export const basicMessage = feature({
|
||||
id: 'basic_message',
|
||||
name: 'Basic Message',
|
||||
type: 'metered',
|
||||
consumable: true,
|
||||
});
|
||||
|
||||
export const premiumMessage = feature({
|
||||
id: 'premium_message',
|
||||
name: 'Premium Message',
|
||||
type: 'metered',
|
||||
consumable: true,
|
||||
});
|
||||
|
||||
export const credits = feature({
|
||||
id: 'credits',
|
||||
name: 'Credits',
|
||||
type: 'credit_system',
|
||||
creditSchema: [
|
||||
{ meteredFeatureId: basicMessage.id, creditCost: 1 },
|
||||
{ meteredFeatureId: premiumMessage.id, creditCost: 10 },
|
||||
],
|
||||
});
|
||||
|
||||
export const pro = plan({
|
||||
id: 'pro',
|
||||
name: 'Pro',
|
||||
price: { amount: 20, interval: 'month' },
|
||||
items: [
|
||||
item({
|
||||
featureId: credits.id,
|
||||
included: 200,
|
||||
reset: { interval: 'month' },
|
||||
}),
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
Push changes with `atmn push`.
|
||||
|
||||
</Tab>
|
||||
<Tab title="Dashboard">
|
||||
|
||||
1. Navigate to the features page, under Plans.
|
||||
2. Click "Create Credit System"
|
||||
4. Add the features that can draw from this credit system.
|
||||
5. For each feature, define how many credits each unit of usage should cost (eg, 3 credits per "premium request").
|
||||
6. Click "Create"
|
||||
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
<Info>
|
||||
**Example**
|
||||
|
||||
@@ -182,6 +236,18 @@ curl -X POST "https://api.useautumn.com/v1/track" \
|
||||
|
||||
Since the customer started with a balance of 100 credits, and used 18 credits, their remaining balance is 82 credits.
|
||||
|
||||
## Stacking with direct balances
|
||||
|
||||
A feature can have both a direct balance **and** belong to a credit system. When this happens, the balances stack and **direct balances are always consumed before credit system balances**, regardless of interval.
|
||||
|
||||
> **Example** <br />
|
||||
> A customer's plan grants `10 premium messages` per month directly, plus `200 credits` per month from a credit system (where each premium message costs 10 credits). <br /><br />
|
||||
> When the customer sends a premium message, Autumn deducts from the direct premium message balance first. Once those 10 direct messages are used up, subsequent premium messages draw from the credit pool instead.
|
||||
|
||||
<Note>
|
||||
The `check` endpoint accounts for both balances. If the customer has 5 direct premium messages remaining plus 100 credits (enough for 10 more premium messages), `check` will report that the customer is allowed.
|
||||
</Note>
|
||||
|
||||
## Monetary credits
|
||||
|
||||
You may want your credit system to represent a monetary value: eg, $10 of credits. To implement this, you can map each credit to a cent value (eg, 1 credit = 1 cent).
|
||||
@@ -202,6 +268,6 @@ See the credits pricing guide for a more detailed example of setting up a moneta
|
||||
<Card
|
||||
title="Credits Example"
|
||||
horizontal
|
||||
href="/examples/credits"
|
||||
href="/examples/monetary-credits"
|
||||
icon="money-bills"
|
||||
/>
|
||||
|
||||
@@ -58,22 +58,15 @@ Push changes with `atmn push`.
|
||||
|
||||
1. Navigate to **Plans** and click **Create Plan**
|
||||
2. Set the plan name and ID (e.g., "Free", `free`)
|
||||
3. Leave the **Price** empty (no base price)
|
||||
4. Add features with grant amounts and reset intervals
|
||||
5. Toggle **Auto-enable** so the plan is automatically assigned to new customers
|
||||
6. Set a **group** (e.g., `main`) if you have paid plans the customer can upgrade to
|
||||
7. Click **Create**
|
||||
3. Toggle **Auto-enable** so the plan is automatically assigned to new customers
|
||||
4. Add features and save your changes
|
||||
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
## How it works
|
||||
|
||||
When `autoEnable` is set:
|
||||
|
||||
1. Every new customer created via the API or SDK is automatically assigned this plan
|
||||
2. Feature balances are provisioned immediately — no checkout or payment needed
|
||||
3. When the customer [upgrades](/documentation/customers/managing-subscriptions#upgrades) to a paid plan in the same group, the free plan is replaced
|
||||
When `autoEnable` is set, every new customer created via the API or SDK is automatically assigned this plan. This flag can only be set if there are no prices on the plan. Since there are no prices, no payment is required.
|
||||
|
||||
<Note>
|
||||
If a customer cancels their paid plan and you have an auto-enabled free plan in the same group, the free plan will be re-activated automatically.
|
||||
@@ -126,10 +119,4 @@ curl -X POST "https://api.useautumn.com/v1/check" \
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
When `allowed` is `false`, the customer has exhausted their free tier balance. This is a good moment to prompt them to upgrade.
|
||||
|
||||
## Tips
|
||||
|
||||
- Set a **group** on your free plan that matches your paid plans, so upgrades automatically replace the free tier
|
||||
- Use `reset` intervals (e.g., monthly) to give customers a recurring allowance
|
||||
- Combine with [pay-per-use](/documentation/modelling-pricing/pay-per-use) to let free users optionally pay for overages
|
||||
When `allowed` is `false`, the customer has exhausted their free tier balance. This is a good moment to prompt them to upgrade.
|
||||
@@ -28,7 +28,6 @@ export const credits = feature({
|
||||
export const creditTopUp = plan({
|
||||
id: 'credit_top_up',
|
||||
name: 'Credit Top-Up',
|
||||
addOn: true,
|
||||
items: [
|
||||
item({
|
||||
featureId: credits.id,
|
||||
@@ -36,16 +35,13 @@ export const creditTopUp = plan({
|
||||
amount: 10,
|
||||
billingUnits: 500,
|
||||
billingMethod: 'prepaid',
|
||||
interval: 'one_off',
|
||||
},
|
||||
}),
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
<Tip>
|
||||
Set `addOn: true` so the plan can be purchased alongside an existing subscription instead of replacing it.
|
||||
</Tip>
|
||||
|
||||
Push changes with `atmn push`.
|
||||
|
||||
</Tab>
|
||||
@@ -65,9 +61,9 @@ Push changes with `atmn push`.
|
||||
|
||||
When a customer purchases a one-off plan:
|
||||
|
||||
1. Autumn creates a Stripe invoice (not a subscription) and charges it immediately
|
||||
2. The feature balance is provisioned with the purchased quantity
|
||||
3. The balance has a `one_off` interval — it never resets or expires
|
||||
- Autumn creates a Stripe invoice (not a subscription) and charges it immediately
|
||||
- The feature balance is provisioned with the purchased quantity
|
||||
- The balance has a `one_off` interval — it never resets or expires
|
||||
|
||||
<Note>
|
||||
One-off purchases don't create Stripe subscriptions. They generate a one-time invoice instead.
|
||||
|
||||
@@ -6,7 +6,7 @@ description: Charge customers based on the number of units they use, such as sea
|
||||
Per-unit pricing charges customers based on the quantity of a resource they use — seats, workspaces, environments, or any other non-consumable feature. Customers either commit to a quantity upfront (prepaid) or are billed based on actual usage at the end of each billing cycle (usage-based).
|
||||
|
||||
> **Example** <br />
|
||||
> A collaboration tool charges $10/seat/month. The plan includes 5 seats for free, and each additional seat costs $10.
|
||||
> A collaboration tool charges \$10/seat/month. The plan includes 5 seats for free, and each additional seat costs \$10.
|
||||
|
||||
## Setting up
|
||||
|
||||
@@ -36,13 +36,8 @@ export const pro = plan({
|
||||
price: {
|
||||
amount: 10,
|
||||
interval: 'month',
|
||||
billingUnits: 1,
|
||||
billingMethod: 'usage_based',
|
||||
},
|
||||
proration: {
|
||||
onIncrease: 'prorate',
|
||||
onDecrease: 'prorate',
|
||||
},
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
209
apps/docs/mintlify/documentation/modelling-pricing/rewards.mdx
Normal file
209
apps/docs/mintlify/documentation/modelling-pricing/rewards.mdx
Normal file
@@ -0,0 +1,209 @@
|
||||
---
|
||||
title: Rewards and Referrals
|
||||
description: Learn how to use rewards and referrals to incentivize your customers.
|
||||
---
|
||||
|
||||
Rewards like discounts, usage credits, and free products are a powerful way to improve the likelihood of customers purchasing a product.
|
||||
|
||||
You can give these rewards to customers yourselves, and also automatically to customers who refer your product to other users via a referral program.
|
||||
|
||||
## Rewards
|
||||
|
||||
Autumn's rewards are a enhanced layer over Stripe's coupons. In addition to standard fixed and percentage discounts, with Autumn you can:
|
||||
|
||||
- Create promo codes for invoice credits that rollover each billing period <br /> (eg, 500 USD free usage for early adopters)
|
||||
- Give away free products <br/> (eg 1000 additional AI messages for all users at an event)
|
||||
|
||||
You can create a reward from the Autumn dashboard:
|
||||
|
||||
1. Navigate to the products page, and click the rewards tab
|
||||
2. Click "+ Reward"
|
||||
3. Fill out the fields such as Name, Promo Code, Discount value
|
||||
4. Select which products it should apply to
|
||||
5. Click "Create"
|
||||
|
||||
#### Invoice credits
|
||||
|
||||
You can create promo codes which customers can enter on Stripe's checkout pages for invoice credits. When applied, these codes will grant the customer a monetary amount of "credits" that lasts until they run out.
|
||||
|
||||
<Info>
|
||||
**Example**
|
||||
|
||||
You have an AI translation product, that is normally billed at 20 USD per month, plus $1 per 100 words translated.
|
||||
|
||||
- For alpha adopters, you want to give away 50 USD of credits to apply across all invoices.
|
||||
- For beta adopters, you want to give away 50 USD of credits that only applies to the translated words usage-price.
|
||||
|
||||
</Info>
|
||||
|
||||
To create a code for invoice credits, when creating a reward, select the following:
|
||||
|
||||
- Type: fixed discount
|
||||
- Duration: one off
|
||||
- Select the option: "Rollover credits to the next invoice"
|
||||
|
||||
The promo code you create can either apply across all products (and the entire invoice), or you can select to only apply the invoice credits to specific usage-prices.
|
||||
|
||||
#### Free products
|
||||
|
||||
You can also give away any add-on product you create to customer with a promo code.
|
||||
|
||||
<Info>
|
||||
**Example**
|
||||
|
||||
If a customer has access to 50 AI messages per month, they can redeem a code for a free booster pack of additional 100 messages per month.
|
||||
|
||||
</Info>
|
||||
|
||||
To create a free product, under reward `type`, select "Free Product". Then choose the add-on product from the selector. You must have at least 1 add-on product created before doing this.
|
||||
|
||||
<Warning>
|
||||
Free product promo codes cannot be redeemed through Stripe's checkout page.
|
||||
You should use the redeem endpoint.
|
||||
</Warning>
|
||||
|
||||
## Referral Programs
|
||||
|
||||
Referral programs allow you to automatically grant rewards to customers who bring on new customers. You can define the referral program in the Dashboard.
|
||||
|
||||
1. Navigate to the products page, and click the rewards tab
|
||||
2. Click "+ Referral Program"
|
||||
3. Give the program an ID (you'll use this to refer to it in the API), and select a reward (see above) to be given away
|
||||
4. Decide whether the reward should be granted when the new customer signs up, or when the purchase a product
|
||||
5. Specify a max redemption number (a limit number of times one customer can be rewarded for referring another customer)
|
||||
6. Decide whether this reward should be granted to the referrer only, or both the referrer and the redeemer (new customer)
|
||||
|
||||
You can then implement the referral program from your application with just 2 routes.
|
||||
|
||||
### Creating a referral code
|
||||
|
||||
Generate a referral code for the customer making the referral:
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```jsx React
|
||||
import { useReferrals } from "autumn-js/react";
|
||||
|
||||
// Pass the program ID to the hook
|
||||
const { data, refetch } = useReferrals({ programId: "free-month" });
|
||||
|
||||
// Call refetch() to create/fetch the code
|
||||
await refetch();
|
||||
|
||||
// Access the code
|
||||
console.log(data?.code); // "4EXWV1"
|
||||
```
|
||||
|
||||
```typescript TypeScript
|
||||
import { Autumn } from "autumn-js";
|
||||
|
||||
const autumn = new Autumn({ secretKey: "am_sk_test_1234" });
|
||||
|
||||
const response = await autumn.referrals.createCode({
|
||||
customerId: "user_123",
|
||||
programId: "free-month",
|
||||
});
|
||||
|
||||
console.log(response.code); // "4EXWV1"
|
||||
```
|
||||
|
||||
```python Python
|
||||
from autumn_sdk import Autumn
|
||||
|
||||
autumn = Autumn("am_sk_test_1234")
|
||||
|
||||
response = await autumn.referrals.create_code(
|
||||
customer_id="user_123",
|
||||
program_id="free-month",
|
||||
)
|
||||
print(response.code) # "4EXWV1"
|
||||
```
|
||||
|
||||
```bash cURL
|
||||
curl -X POST 'https://api.useautumn.com/v1/referrals.create_code' \
|
||||
-H 'Authorization: Bearer am_sk_test_1234' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{
|
||||
"customer_id": "user_123",
|
||||
"program_id": "free-month"
|
||||
}'
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
<Expandable title="Response">
|
||||
```json
|
||||
{
|
||||
"code": "4EXWV1",
|
||||
"customerId": "user_123",
|
||||
"createdAt": 1744797427206
|
||||
}
|
||||
```
|
||||
</Expandable>
|
||||
|
||||
### Redeeming a referral code
|
||||
|
||||
From the new customer, redeem the referral code:
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```jsx React
|
||||
import { useReferrals } from "autumn-js/react";
|
||||
|
||||
const { redeemCode } = useReferrals({ programId: "free-month" });
|
||||
|
||||
const response = await redeemCode({ code: "4EXWV1" });
|
||||
|
||||
console.log(response.rewardId); // "free-month"
|
||||
```
|
||||
|
||||
```typescript TypeScript
|
||||
import { Autumn } from "autumn-js";
|
||||
|
||||
const autumn = new Autumn({ secretKey: "am_sk_test_1234" });
|
||||
|
||||
const response = await autumn.referrals.redeemCode({
|
||||
code: "4EXWV1",
|
||||
customerId: "new_user_123",
|
||||
});
|
||||
|
||||
console.log(response.rewardId); // "free-month"
|
||||
```
|
||||
|
||||
```python Python
|
||||
from autumn_sdk import Autumn
|
||||
|
||||
autumn = Autumn("am_sk_test_1234")
|
||||
|
||||
response = await autumn.referrals.redeem_code(
|
||||
code="4EXWV1",
|
||||
customer_id="new_user_123",
|
||||
)
|
||||
print(response.reward_id) # "free-month"
|
||||
```
|
||||
|
||||
```bash cURL
|
||||
curl -X POST 'https://api.useautumn.com/v1/referrals.redeem_code' \
|
||||
-H 'Authorization: Bearer am_sk_test_1234' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{
|
||||
"code": "4EXWV1",
|
||||
"customer_id": "new_user_123"
|
||||
}'
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
<Expandable title="Response">
|
||||
```json
|
||||
{
|
||||
"id": "rr_2vo3Jt9oqF6XgAlWI1MjYktv4dB",
|
||||
"customerId": "new_user_123",
|
||||
"rewardId": "free-month"
|
||||
}
|
||||
```
|
||||
</Expandable>
|
||||
|
||||
The reward will automatically apply on the event that you set (customer creation or product purchase).
|
||||
|
||||
In the customer details page, you'll be able to see which customers have made referrals and been referred.
|
||||
@@ -15,7 +15,7 @@ Free trials give customers temporary access to a paid plan before they're charge
|
||||
|
||||
Add a `freeTrial` object to your plan:
|
||||
|
||||
```ts autumn.config.ts
|
||||
```ts autumn.config.ts expandable
|
||||
import { feature, item, plan } from 'atmn';
|
||||
|
||||
export const messages = feature({
|
||||
@@ -143,15 +143,52 @@ curl -X POST "https://api.useautumn.com/v1/attach" \
|
||||
When the trial expires, the customer loses access unless they add a payment method. If a [free plan](/documentation/modelling-pricing/free-plans) with `autoEnable` exists in the same group, it's activated as a fallback.
|
||||
|
||||
<Tip>
|
||||
You can combine `autoEnable` with `cardRequired: false` to create an **auto-trial** plan. The trial starts automatically when a customer is created, and expires after the trial period.
|
||||
You can combine `autoEnable` with `cardRequired: false` to create an **auto-trial** plan. The trial starts automatically when a customer is created, and expires after the trial period — no API call needed.
|
||||
</Tip>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## Checking trial status
|
||||
|
||||
The customer's subscription includes a `trial_ends_at` timestamp when a trial is active. You can also expand `trials_used` to see which trials a customer has consumed:
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```typescript TypeScript
|
||||
const { data } = await autumn.customers.get("user_123");
|
||||
|
||||
for (const sub of data.subscriptions) {
|
||||
if (sub.trialEndsAt) {
|
||||
console.log(`Trialing until ${new Date(sub.trialEndsAt)}`);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```python Python
|
||||
response = await autumn.customers.get("user_123")
|
||||
|
||||
for sub in response.subscriptions:
|
||||
if sub.trial_ends_at:
|
||||
print(f"Trialing until {sub.trial_ends_at}")
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## Trial deduplication
|
||||
|
||||
Each customer can only use a plan's trial **once**. If they try to attach the same plan again, the trial is skipped and they're billed immediately.
|
||||
|
||||
### Fingerprint-based deduplication
|
||||
|
||||
To prevent trial abuse across multiple accounts, set a `fingerprint` when creating a customer (e.g., device ID, browser fingerprint). Autumn checks whether any customer with the same fingerprint has already used the trial.
|
||||
|
||||
<CodeGroup>
|
||||
@@ -188,37 +225,292 @@ curl -X POST "https://api.useautumn.com/v1/customers" \
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
## Cancelling a trial
|
||||
<Note>
|
||||
Custom trials passed via `customize.freeTrial` always **bypass** deduplication. Use this for support cases where you want to grant a second trial.
|
||||
</Note>
|
||||
|
||||
Cancel a trial using the same [cancel](/documentation/customers/managing-subscriptions#cancellations) flow as any subscription:
|
||||
|
||||
You can check which trials a customer has already used by expanding `trials_used` on the customer object:
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```typescript TypeScript
|
||||
await autumn.cancel({
|
||||
customer_id: "user_123",
|
||||
plan_id: "pro",
|
||||
cancel_immediately: true,
|
||||
const customer = await autumn.customers.getOrCreate({
|
||||
customerId: "user_123",
|
||||
expand: ["trials_used"],
|
||||
});
|
||||
```
|
||||
|
||||
```python Python
|
||||
await autumn.cancel(
|
||||
customer = await autumn.customers.get_or_create(
|
||||
customer_id="user_123",
|
||||
expand=["trials_used"],
|
||||
)
|
||||
|
||||
```
|
||||
|
||||
```bash cURL
|
||||
curl -X POST "https://api.useautumn.com/v1/customers" \
|
||||
-H "Authorization: Bearer am_sk_..." \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"id": "user_123",
|
||||
"expand": ["trials_used"]
|
||||
}'
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## Upgrades and Downgrades
|
||||
|
||||
When upgrading to a plan with a trial, the trial behavior depends on the customer's current state and whether the new plan has an unused trial:
|
||||
|
||||
| Current state | Unused trial? | Result |
|
||||
|---|---|---|
|
||||
| Trialing | Yes | Current trial ends. Fresh trial starts on new plan. |
|
||||
| Trialing | No | Current trial ends. Billing starts immediately. |
|
||||
| Active (not trialing) | Yes | Trial starts. Current cycle refunded. |
|
||||
| Active (not trialing) | No | No trial. Billing starts at new price. |
|
||||
|
||||
When a customer downgrades during a trial, the lower plan is scheduled to activate when the trial ends. The lower plan's own trial is not applied - you cannot get a new trial on a downgrade.
|
||||
|
||||
<Note>
|
||||
You can override any of these behaviors by passing `customize.freeTrial` on the attach call. See [Overriding trial behavior](#overriding-trial-behavior) below.
|
||||
</Note>
|
||||
|
||||
## Overriding trial behavior
|
||||
|
||||
You can override the default trial behavior on any `/attach` or `/update-subscription` call by passing `customize.freeTrial`:
|
||||
|
||||
<Tabs>
|
||||
<Tab title="Custom trial">
|
||||
|
||||
Pass a `freeTrial` object to start a trial with a custom duration. This **bypasses deduplication** — the customer always gets the trial, even if they've trialed this plan before.
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```typescript TypeScript
|
||||
await autumn.attach({
|
||||
customerId: "user_123",
|
||||
planId: "pro",
|
||||
customize: {
|
||||
freeTrial: {
|
||||
durationLength: 30,
|
||||
durationType: "day",
|
||||
cardRequired: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
```python Python
|
||||
await autumn.attach(
|
||||
customer_id="user_123",
|
||||
plan_id="pro",
|
||||
cancel_immediately=True,
|
||||
customize={
|
||||
"free_trial": {
|
||||
"duration_length": 30,
|
||||
"duration_type": "day",
|
||||
"card_required": True,
|
||||
}
|
||||
},
|
||||
)
|
||||
```
|
||||
|
||||
```bash cURL
|
||||
curl -X POST "https://api.useautumn.com/v1/cancel" \
|
||||
curl -X POST "https://api.useautumn.com/v1/attach" \
|
||||
-H "Authorization: Bearer am_sk_..." \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"customer_id": "user_123",
|
||||
"plan_id": "pro",
|
||||
"cancel_immediately": true
|
||||
"customize": {
|
||||
"free_trial": {
|
||||
"duration_length": 30,
|
||||
"duration_type": "day",
|
||||
"card_required": true
|
||||
}
|
||||
}
|
||||
}'
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
</CodeGroup>
|
||||
|
||||
</Tab>
|
||||
<Tab title="End / skip trial">
|
||||
|
||||
Pass `freeTrial: null` to skip the trial entirely and begin billing immediately — even if the plan has a trial configured.
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```typescript TypeScript
|
||||
await autumn.attach({
|
||||
customerId: "user_123",
|
||||
planId: "pro",
|
||||
customize: {
|
||||
freeTrial: null,
|
||||
},
|
||||
});
|
||||
// Charged immediately, no trial
|
||||
```
|
||||
|
||||
```python Python
|
||||
await autumn.attach(
|
||||
customer_id="user_123",
|
||||
plan_id="pro",
|
||||
customize={"free_trial": None},
|
||||
)
|
||||
```
|
||||
|
||||
```bash cURL
|
||||
curl -X POST "https://api.useautumn.com/v1/attach" \
|
||||
-H "Authorization: Bearer am_sk_..." \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"customer_id": "user_123",
|
||||
"plan_id": "pro",
|
||||
"customize": { "free_trial": null }
|
||||
}'
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
You can also pass `freeTrial: null` on `/update-subscription` to end an active trial early and start billing right away.
|
||||
|
||||
</Tab>
|
||||
<Tab title="Extend trial">
|
||||
|
||||
To extend a trial, call `/update-subscription` with a new `customize.freeTrial`. The new trial duration is computed **from now** — it replaces the current trial end date rather than adding to it.
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```typescript TypeScript
|
||||
// Customer is 5 days into a 14-day trial.
|
||||
// This gives them a fresh 14 days from now (not 14 + 9 remaining).
|
||||
await autumn.updateSubscription({
|
||||
customerId: "user_123",
|
||||
planId: "pro",
|
||||
customize: {
|
||||
freeTrial: {
|
||||
durationLength: 14,
|
||||
durationType: "day",
|
||||
},
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
```python Python
|
||||
await autumn.update_subscription(
|
||||
customer_id="user_123",
|
||||
plan_id="pro",
|
||||
customize={
|
||||
"free_trial": {
|
||||
"duration_length": 14,
|
||||
"duration_type": "day",
|
||||
}
|
||||
},
|
||||
)
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
<Warning>
|
||||
Trial extensions are **replacement**, not additive. If a customer is 5 days into a 14-day trial and you set a new 14-day trial, they get 14 days from today (19 days total from the original start), not 14 days added to the remaining 9.
|
||||
</Warning>
|
||||
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## Trials with shared subscriptions
|
||||
|
||||
When using [entities](/documentation/modelling-pricing/sub-entity-plans) or add-ons, trial state is shared across the same Stripe subscription. This is because Stripe manages trials at the subscription level.
|
||||
|
||||
<Tip>
|
||||
You can pass in `newBillingSubscription: true` to create a new subscription for each plan, rather than merging into the existing subscription.
|
||||
</Tip>
|
||||
|
||||
Here are some principles to keep in mind when using trials with shared subscriptions:
|
||||
|
||||
#### First entity gets the trial
|
||||
|
||||
When the first entity is attached with a trial plan, the trial starts on the shared subscription. Any subsequent entities attached to the same subscription **inherit the existing trial state** — they don't start their own independent trial.
|
||||
|
||||
#### Adding plans to a non-trialing subscription
|
||||
|
||||
If the subscription is **not** trialing, new plans are charged immediately — even if the product they're being attached to has a trial configured. The product's trial config is ignored for merges into an active subscription.
|
||||
|
||||
#### Shared trial state affects all plans
|
||||
|
||||
Because entities (by default) share a subscription, trial state changes affect **all** entities:
|
||||
|
||||
- **Entity upgrade to a plan with a trial**: a fresh trial starts, and all other entities on the subscription inherit the new trial end date.
|
||||
- **Entity upgrade to a plan without a trial**: the trial ends for **all** entities, and they're all billed immediately.
|
||||
- **Entity downgrade during trial**: the downgrade is scheduled for when the trial ends.
|
||||
|
||||
|
||||
Passing `customize.freeTrial` on an entity attach or upgrade affects the **shared subscription**, so all entities are affected. Similarly, passing `freeTrial: null` ends the trial for all entities on the subscription.
|
||||
|
||||
## Resetting usage after trial
|
||||
|
||||
<Note>
|
||||
This feature is coming soon.
|
||||
</Note>
|
||||
|
||||
By default, feature usage during a trial carries over into the paid period. If you want usage to **reset when billing starts**, pass `transition_rules.reset_after_trial_end` with the feature IDs to reset:
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```typescript TypeScript
|
||||
await autumn.attach({
|
||||
customerId: "user_123",
|
||||
planId: "pro",
|
||||
transitionRules: {
|
||||
resetAfterTrialEnd: ["messages"],
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
```python Python
|
||||
await autumn.attach(
|
||||
customer_id="user_123",
|
||||
plan_id="pro",
|
||||
transition_rules={
|
||||
"reset_after_trial_end": ["messages"],
|
||||
},
|
||||
)
|
||||
```
|
||||
|
||||
```bash cURL
|
||||
curl -X POST "https://api.useautumn.com/v1/attach" \
|
||||
-H "Authorization: Bearer am_sk_..." \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"customer_id": "user_123",
|
||||
"plan_id": "pro",
|
||||
"transition_rules": {
|
||||
"reset_after_trial_end": ["messages"]
|
||||
}
|
||||
}'
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
This sets the feature's reset cycle to begin when the trial ends rather than when the trial starts, so the customer gets a full fresh allowance once they start paying.
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
title: Pay-Per-Use
|
||||
title: Usage-Based Pricing
|
||||
description: Bill customers based on actual usage at the end of each billing period
|
||||
---
|
||||
|
||||
Reference in New Issue
Block a user