351 lines
7.9 KiB
Plaintext
351 lines
7.9 KiB
Plaintext
---
|
|
title: Prepaid top-ups
|
|
description: Let customers purchase prepaid packages and top-ups.
|
|
---
|
|
|
|
If a user hits a usage limit you granted them, they may be willing to purchase a top-up.
|
|
|
|
These are typically one-time purchases (or less commonly, recurring add-ons) that grant a fixed usage of a feature.
|
|
|
|
This gives users full spend control and allows your business to be paid upfront. For these reasons, it tends to be a more popular alternative to usage-based pricing -- eg, OpenAI uses this model for their API.
|
|
|
|
## Example case
|
|
|
|
In this example, we have an AI chatbot that offers:
|
|
|
|
- 10 premium messages for free
|
|
- An option for customers to top-up premium messages in packages of $10 per 100 messages.
|
|
|
|
## Configure Pricing
|
|
|
|
<Steps>
|
|
<Step>
|
|
#### Create Features
|
|
|
|
Create a `metered` `consumable` feature for our premium messages, so we can track its balance.
|
|
|
|
<Frame>
|
|
<img src="/assets/guides/prepaid/features-light.png" className="block dark:hidden" />
|
|
<img src="/assets/guides/prepaid/features-dark.png" className="hidden dark:block" />
|
|
</Frame>
|
|
</Step>
|
|
|
|
<Step>
|
|
#### Create Free and Top-up Plans
|
|
|
|
Create our free plan, and assign 10 premium messages to it. These are "one-off" credits, that will not reset periodically.
|
|
|
|
<Tip>
|
|
Make sure to set the `auto-enable` flag on the free plan, so that it is automatically assigned to new customers.
|
|
</Tip>
|
|
<Frame>
|
|
<img src="/assets/guides/prepaid/free-light.png" className="block dark:hidden" />
|
|
<img src="/assets/guides/prepaid/free-dark.png" className="hidden dark:block" />
|
|
</Frame>
|
|
|
|
Now we'll create our top-up plan. We'll add a price to our premium messages feature, at $10 per 100 messages. These are "one-off" purchases, with a `prepaid` billing method.
|
|
|
|
`prepaid` features require a `quantity` to be sent in when a customer attaches this product, so the customer can specify how many premium messages they want to top up with.
|
|
|
|
<Frame>
|
|
<img src="/assets/guides/prepaid/topup-light.png" className="block dark:hidden" />
|
|
<img src="/assets/guides/prepaid/topup-dark.png" className="hidden dark:block" />
|
|
</Frame>
|
|
|
|
</Step>
|
|
</Steps>
|
|
|
|
## Implementation
|
|
|
|
<Steps>
|
|
<Step>
|
|
#### Create an Autumn Customer
|
|
|
|
When your user signs up, create an Autumn customer. This will automatically assign them the Free plan, and grant them 10 premium messages.
|
|
|
|
<CodeGroup>
|
|
|
|
```jsx React
|
|
import { useCustomer } from "autumn-js/react";
|
|
|
|
const App = () => {
|
|
const { data: customer } = useCustomer();
|
|
|
|
console.log("Autumn customer:", customer);
|
|
|
|
return <h1>Welcome, {customer?.name || "user"}!</h1>;
|
|
};
|
|
```
|
|
|
|
```typescript TypeScript
|
|
import { Autumn } from "autumn-js";
|
|
|
|
const autumn = new Autumn({ secretKey: "am_sk_test_1234" });
|
|
|
|
const customer = await autumn.customers.getOrCreate({
|
|
customerId: "user_123",
|
|
name: "John Yeo",
|
|
email: "john@example.com",
|
|
});
|
|
```
|
|
|
|
```python Python
|
|
from autumn_sdk import Autumn
|
|
|
|
autumn = Autumn("am_sk_test_1234")
|
|
|
|
customer = await autumn.customers.get_or_create(
|
|
customer_id="user_123",
|
|
name="John Yeo",
|
|
email="john@example.com",
|
|
)
|
|
```
|
|
|
|
```bash cURL
|
|
curl -X POST "https://api.useautumn.com/v1/customers" \
|
|
-H "Authorization: Bearer am_sk_test_1234" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"customer_id": "user_123",
|
|
"name": "John Yeo",
|
|
"email": "john@example.com"
|
|
}'
|
|
```
|
|
|
|
</CodeGroup>
|
|
</Step>
|
|
|
|
<Step>
|
|
#### Checking for access
|
|
|
|
Every time our user wants to send a premium message, we'll first check if they have enough premium messages remaining.
|
|
|
|
<CodeGroup>
|
|
|
|
```jsx React
|
|
import { useCustomer } from "autumn-js/react";
|
|
|
|
export function CheckPremiumMessage() {
|
|
const { check, refetch } = useCustomer();
|
|
|
|
const handleCheckAccess = async () => {
|
|
const { allowed } = check({ featureId: "premium_messages" });
|
|
|
|
if (!allowed) {
|
|
alert("You've run out of premium messages");
|
|
} else {
|
|
// proceed with sending message
|
|
await refetch();
|
|
}
|
|
};
|
|
}
|
|
```
|
|
|
|
```typescript TypeScript
|
|
import { Autumn } from "autumn-js";
|
|
|
|
const autumn = new Autumn({ secretKey: "am_sk_test_1234" });
|
|
|
|
const response = await autumn.customers.check({
|
|
customerId: "user_123",
|
|
featureId: "premium_messages",
|
|
});
|
|
|
|
if (!response.allowed) {
|
|
console.log("User has run out of premium messages");
|
|
return;
|
|
}
|
|
```
|
|
|
|
```python Python
|
|
from autumn_sdk import Autumn
|
|
|
|
autumn = Autumn("am_sk_test_1234")
|
|
|
|
response = await autumn.customers.check(
|
|
customer_id="user_123",
|
|
feature_id="premium_messages",
|
|
)
|
|
|
|
if not response.allowed:
|
|
print("User has run out of premium messages")
|
|
```
|
|
|
|
```bash cURL
|
|
curl -X POST "https://api.useautumn.com/v1/check" \
|
|
-H "Authorization: Bearer am_sk_test_1234" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"customer_id": "user_123",
|
|
"feature_id": "premium_messages"
|
|
}'
|
|
```
|
|
|
|
</CodeGroup>
|
|
|
|
<Expandable title="check response">
|
|
```json
|
|
{
|
|
"allowed": true,
|
|
"customerId": "user_123",
|
|
"requiredBalance": 1,
|
|
"balance": {
|
|
"featureId": "premium_messages",
|
|
"granted": 10,
|
|
"remaining": 10,
|
|
"usage": 0,
|
|
"unlimited": false,
|
|
"overageAllowed": false,
|
|
"nextResetAt": null
|
|
}
|
|
}
|
|
```
|
|
</Expandable>
|
|
</Step>
|
|
|
|
<Step>
|
|
#### Tracking premium messages
|
|
|
|
Now let's implement our usage tracking and use up our premium messages. In this example, we're using 5 premium messages.
|
|
|
|
<CodeGroup>
|
|
|
|
```typescript TypeScript
|
|
import { Autumn } from "autumn-js";
|
|
|
|
const autumn = new Autumn({ secretKey: "am_sk_test_1234" });
|
|
|
|
await autumn.customers.track({
|
|
customerId: "user_123",
|
|
featureId: "premium_messages",
|
|
value: 5,
|
|
});
|
|
```
|
|
|
|
```python Python
|
|
from autumn_sdk import Autumn
|
|
|
|
autumn = Autumn("am_sk_test_1234")
|
|
|
|
await autumn.customers.track(
|
|
customer_id="user_123",
|
|
feature_id="premium_messages",
|
|
value=5,
|
|
)
|
|
```
|
|
|
|
```bash cURL
|
|
curl -X POST "https://api.useautumn.com/v1/track" \
|
|
-H "Authorization: Bearer am_sk_test_1234" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"customer_id": "user_123",
|
|
"feature_id": "premium_messages",
|
|
"value": 5
|
|
}'
|
|
```
|
|
|
|
</CodeGroup>
|
|
|
|
<Expandable title="track response">
|
|
```json
|
|
{
|
|
"customerId": "user_123",
|
|
"value": 5,
|
|
"balance": {
|
|
"featureId": "premium_messages",
|
|
"granted": 10,
|
|
"remaining": 5,
|
|
"usage": 5,
|
|
"unlimited": false,
|
|
"overageAllowed": false,
|
|
"nextResetAt": null
|
|
}
|
|
}
|
|
```
|
|
</Expandable>
|
|
</Step>
|
|
|
|
<Step>
|
|
#### Purchasing top-ups
|
|
|
|
When users run out of premium messages, they can purchase additional messages using our top-up plan. In this example, the user is purchasing 200 premium messages, which will cost them $20.
|
|
|
|
<CodeGroup>
|
|
|
|
```jsx React
|
|
import { useCustomer } from "autumn-js/react";
|
|
|
|
export default function TopUpButton() {
|
|
const { attach } = useCustomer();
|
|
|
|
return (
|
|
<button
|
|
onClick={() => attach({
|
|
planId: "top_up",
|
|
featureQuantities: [{
|
|
featureId: "premium_messages",
|
|
quantity: 200,
|
|
}],
|
|
})}
|
|
>
|
|
Buy More Messages
|
|
</button>
|
|
);
|
|
}
|
|
```
|
|
|
|
```typescript TypeScript
|
|
import { Autumn } from "autumn-js";
|
|
|
|
const autumn = new Autumn({ secretKey: "am_sk_test_1234" });
|
|
|
|
const response = await autumn.billing.attach({
|
|
customerId: "user_123",
|
|
planId: "top_up",
|
|
featureQuantities: [{
|
|
featureId: "premium_messages",
|
|
quantity: 200,
|
|
}],
|
|
});
|
|
|
|
redirect(response.paymentUrl);
|
|
```
|
|
|
|
```python Python
|
|
from autumn_sdk import Autumn
|
|
|
|
autumn = Autumn("am_sk_test_1234")
|
|
|
|
response = await autumn.billing.attach(
|
|
customer_id="user_123",
|
|
plan_id="top_up",
|
|
feature_quantities=[{
|
|
"feature_id": "premium_messages",
|
|
"quantity": 200,
|
|
}],
|
|
)
|
|
# Redirect to response.payment_url
|
|
```
|
|
|
|
```bash cURL
|
|
curl -X POST "https://api.useautumn.com/v1/attach" \
|
|
-H "Authorization: Bearer am_sk_test_1234" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"customer_id": "user_123",
|
|
"plan_id": "top_up",
|
|
"feature_quantities": [{
|
|
"feature_id": "premium_messages",
|
|
"quantity": 200
|
|
}]
|
|
}'
|
|
```
|
|
|
|
</CodeGroup>
|
|
|
|
Once the customer completes the payment, they will have an additional 200 premium messages available to use. You can display this to the user by getting balances from the customer endpoint.
|
|
|
|
</Step>
|
|
</Steps>
|