* fix: dashboard bugs * latest * Add Elysia, Express, and Web Standard adapter docs Generated-By: mintlify-agent --------- Co-authored-by: John Yeo <johnyeocx@gmail.com> Co-authored-by: John Yeo <51376134+johnyeocx@users.noreply.github.com> Co-authored-by: mintlify[bot] <109931778+mintlify[bot]@users.noreply.github.com>
613 lines
14 KiB
Plaintext
613 lines
14 KiB
Plaintext
---
|
|
title: "Setup and payments"
|
|
description: "Implement your app's payments and pricing model"
|
|
---
|
|
|
|
import CreatePlans from "/snippets/create-plans.mdx";
|
|
|
|
In this example we'll create the pricing for a premium AI chatbot. We're going to have:
|
|
|
|
- A <Badge color="green">Free</Badge> plan that gives users 5 chat messages per month for free
|
|
- A <Badge color="blue">Pro</Badge> plan that gives users 100 chat messages per month for $20 per month.
|
|
|
|
{/* REACT DOCS */}
|
|
|
|
<View title="React hooks" icon="react">
|
|
|
|
<Info>
|
|
Autumn's client-side [hooks](/react/hooks/useCustomer) are supported for
|
|
fullstack TypeScript apps. Please use the Server SDK for other frameworks.
|
|
</Info>
|
|
|
|
<Steps>
|
|
<Step>
|
|
### Create your pricing plans
|
|
|
|
Create a plan for each pricing tier that your app offers. In our example we'll create a "Free" and "Pro" plan, and assign them features.
|
|
|
|
<CreatePlans />
|
|
|
|
</Step>
|
|
|
|
<Step>
|
|
### Installation
|
|
|
|
[Create an Autumn Secret key](https://app.useautumn.com/sandbox/dev?tab=api_keys), and paste it in your `.env` variables. Then, install the Autumn SDK. If you're using the CLI, this will be done for you.
|
|
|
|
```bash .env
|
|
AUTUMN_SECRET_KEY=am_sk_test_42424242...
|
|
```
|
|
|
|
<CodeGroup>
|
|
|
|
```bash bun
|
|
bun add autumn-js
|
|
```
|
|
|
|
```bash npm
|
|
npm install autumn-js
|
|
```
|
|
|
|
```bash pnpm
|
|
pnpm add autumn-js
|
|
```
|
|
|
|
```bash yarn
|
|
yarn add autumn-js
|
|
```
|
|
|
|
</CodeGroup>
|
|
|
|
<Note>
|
|
If you're using a separate backend and frontend, make sure to install the
|
|
library in both.
|
|
</Note>
|
|
|
|
</Step>
|
|
|
|
<Step>
|
|
### Add Endpoints Server-side
|
|
|
|
Server-side, mount the Autumn handler. This will create endpoints in the `/api/autumn/*` path, which will be called by Autumn's frontend React hooks. These endpoints in turn call Autumn's API.
|
|
|
|
The handler takes in an `identify` function where you should pass in the user ID or organization ID from your auth provider.
|
|
|
|
<CodeGroup>
|
|
|
|
```typescript Next.js
|
|
// app/api/autumn/[...all]/route.ts
|
|
|
|
import { autumnHandler } from "autumn-js/next";
|
|
import { auth } from "@/lib/auth";
|
|
|
|
export const { GET, POST } = autumnHandler({
|
|
identify: async (request) => {
|
|
// get the user from your auth provider (example: better-auth)
|
|
const session = await auth.api.getSession({
|
|
headers: request.headers,
|
|
});
|
|
|
|
return {
|
|
customerId: session?.user.id, // or org ID
|
|
customerData: {
|
|
name: session?.user.name,
|
|
email: session?.user.email,
|
|
},
|
|
};
|
|
},
|
|
});
|
|
```
|
|
|
|
```typescript Hono
|
|
// index.ts
|
|
|
|
import { autumnHandler } from "autumn-js/hono";
|
|
|
|
app.use(
|
|
"/api/autumn/*",
|
|
autumnHandler({
|
|
identify: async (c: Context) => {
|
|
// get the user from your auth provider (example: better-auth)
|
|
const session = await auth.api.getSession({
|
|
headers: c.req.raw.headers,
|
|
});
|
|
|
|
return {
|
|
customerId: session?.user.id,
|
|
customerData: {
|
|
name: session?.user.name,
|
|
email: session?.user.email,
|
|
},
|
|
};
|
|
},
|
|
}),
|
|
);
|
|
```
|
|
|
|
```typescript Elysia
|
|
import { autumnHandler } from "autumn-js/webStandard";
|
|
import { Elysia } from "elysia";
|
|
|
|
const app = new Elysia()
|
|
.mount(
|
|
autumnHandler({
|
|
identify: async (request) => {
|
|
// get the user from your auth provider (example: better-auth)
|
|
const session = await auth.api.getSession({
|
|
headers: request.headers,
|
|
});
|
|
|
|
return {
|
|
customerId: session?.user.id,
|
|
customerData: {
|
|
name: session?.user.name,
|
|
email: session?.user.email,
|
|
},
|
|
};
|
|
},
|
|
}),
|
|
)
|
|
.listen(3002);
|
|
```
|
|
|
|
```typescript Express
|
|
import express from "express";
|
|
import { autumnHandler } from "autumn-js/express";
|
|
|
|
const app = express();
|
|
|
|
// Body parser is required before the Autumn handler
|
|
app.use(express.json());
|
|
app.use(
|
|
"/api/autumn",
|
|
autumnHandler({
|
|
identify: async (req) => {
|
|
// get the user from your auth provider (example: better-auth)
|
|
const session = await auth.api.getSession({
|
|
headers: req.headers,
|
|
});
|
|
|
|
return {
|
|
customerId: session?.user.id,
|
|
customerData: {
|
|
name: session?.user.name,
|
|
email: session?.user.email,
|
|
},
|
|
};
|
|
},
|
|
}),
|
|
);
|
|
```
|
|
|
|
```typescript Elysia
|
|
import { autumnHandler } from "autumn-js/webStandard";
|
|
import { Elysia } from "elysia";
|
|
|
|
const app = new Elysia()
|
|
.mount(
|
|
autumnHandler({
|
|
identify: async (request) => {
|
|
// get the user from your auth provider (example: better-auth)
|
|
const session = await auth.api.getSession({
|
|
headers: request.headers,
|
|
});
|
|
|
|
return {
|
|
customerId: session?.user.id,
|
|
customerData: {
|
|
name: session?.user.name,
|
|
email: session?.user.email,
|
|
},
|
|
};
|
|
},
|
|
}),
|
|
)
|
|
.listen(3002);
|
|
```
|
|
|
|
```typescript Express
|
|
import express from "express";
|
|
import { autumnHandler } from "autumn-js/express";
|
|
|
|
const app = express();
|
|
|
|
// Body parser is required before the Autumn handler
|
|
app.use(express.json());
|
|
app.use(
|
|
"/api/autumn",
|
|
autumnHandler({
|
|
identify: async (req) => {
|
|
// get the user from your auth provider (example: better-auth)
|
|
const session = await auth.api.getSession({
|
|
headers: req.headers,
|
|
});
|
|
|
|
return {
|
|
customerId: session?.user.id,
|
|
customerData: {
|
|
name: session?.user.name,
|
|
email: session?.user.email,
|
|
},
|
|
};
|
|
},
|
|
}),
|
|
);
|
|
```
|
|
|
|
```typescript General (framework-agnostic)
|
|
// For any framework not listed above
|
|
|
|
import { autumnHandler } from "autumn-js/backend";
|
|
|
|
// Call this from your route handler
|
|
const result = await autumnHandler({
|
|
request: {
|
|
url: request.url, // Full URL or path (e.g., "/api/autumn/customer")
|
|
method: request.method,
|
|
body: await request.json(),
|
|
},
|
|
customerId: session?.user.id,
|
|
customerData: {
|
|
name: session?.user.name,
|
|
email: session?.user.email,
|
|
},
|
|
});
|
|
|
|
// Return the response
|
|
return new Response(JSON.stringify(result.response), {
|
|
status: result.statusCode,
|
|
headers: { "Content-Type": "application/json" },
|
|
});
|
|
```
|
|
|
|
</CodeGroup>
|
|
|
|
<Check>
|
|
Autumn's customer ID is the same as your internal user or org ID generated
|
|
from your auth provider. No need to store any extra IDs.
|
|
</Check>
|
|
|
|
</Step>
|
|
|
|
<Step>
|
|
|
|
### Add Provider Client-side
|
|
|
|
Client side, wrap your application with the `<AutumnProvider>` component.
|
|
|
|
```jsx
|
|
// layout.tsx
|
|
import { AutumnProvider } from "autumn-js/react";
|
|
|
|
export default function RootLayout({ children }: {
|
|
children: React.ReactNode,
|
|
}) {
|
|
return (
|
|
<html>
|
|
<body>
|
|
<AutumnProvider>
|
|
{children}
|
|
</AutumnProvider>
|
|
</body>
|
|
</html>
|
|
);
|
|
}
|
|
```
|
|
|
|
</Step>
|
|
|
|
<Step>
|
|
### Create an Autumn customer
|
|
|
|
From a frontend component, use the [`useCustomer()` hook](/react/hooks/useCustomer). This will automatically create an Autumn customer if they're a new user and enable the <Badge color="green">Free</Badge> plan for them, or get the customer's state for existing users.
|
|
|
|
```jsx React
|
|
import { useCustomer } from "autumn-js/react";
|
|
|
|
const App = () => {
|
|
const { data } = useCustomer();
|
|
|
|
console.log("Autumn customer:", data);
|
|
|
|
return <h1>My very profitable app</h1>;
|
|
};
|
|
```
|
|
|
|
<Expandable title="data object">
|
|
|
|
```json expandable
|
|
{
|
|
"id": "user_123",
|
|
"createdAt": 1764932560414,
|
|
"name": "My First Customer",
|
|
"email": null,
|
|
"fingerprint": null,
|
|
"stripeId": null,
|
|
"env": "sandbox",
|
|
"metadata": {},
|
|
"sendEmailReceipts": false,
|
|
"subscriptions": [
|
|
{
|
|
"planId": "free",
|
|
"autoEnable": true,
|
|
"addOn": false,
|
|
"status": "active",
|
|
"pastDue": false,
|
|
"canceledAt": null,
|
|
"expiresAt": null,
|
|
"trialEndsAt": null,
|
|
"startedAt": 1764932560519,
|
|
"currentPeriodStart": null,
|
|
"currentPeriodEnd": null,
|
|
"quantity": 1
|
|
}
|
|
],
|
|
"purchases": [],
|
|
"balances": {
|
|
"messages": {
|
|
"featureId": "messages",
|
|
"granted": 5,
|
|
"remaining": 5,
|
|
"usage": 0,
|
|
"unlimited": false,
|
|
"overageAllowed": false,
|
|
"maxPurchase": null,
|
|
"nextResetAt": 1767610960519
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
</Expandable>
|
|
|
|
You will see your user under the [customers](https://app.useautumn.com/customers) page in the Autumn dashboard.
|
|
|
|
</Step>
|
|
|
|
<Step>
|
|
|
|
### Stripe Payment Flow
|
|
|
|
Call `attach` when the customer wants to purchase the <Badge color="blue">Pro</Badge> plan. This will return a Stripe payment URL. Once they've paid, Autumn will grant access to "100 messages per month" defined in Step 1.
|
|
|
|
<Note>
|
|
Use Stripe's test card `4242 4242 4242 4242` to make a purchase in sandbox.
|
|
You can enter any Expiry and CVV.
|
|
</Note>
|
|
|
|
```jsx React
|
|
import { useCustomer } from "autumn-js/react";
|
|
|
|
export default function PurchaseButton() {
|
|
const { attach } = useCustomer();
|
|
|
|
return (
|
|
<button
|
|
onClick={async () => {
|
|
await attach({
|
|
planId: "pro",
|
|
redirectMode: "always",
|
|
});
|
|
}}
|
|
>
|
|
Select Pro Plan
|
|
</button>
|
|
);
|
|
}
|
|
```
|
|
|
|
This will handle any plan changes scenario (upgrades, downgrades, one-time topups, renewals, etc).
|
|
|
|
Upgrades will happen immediately, and downgrades will be scheduled for the next billing cycle.
|
|
|
|
<Note>
|
|
The **`redirectMode: "always"`** flag will always return a payment URL.
|
|
|
|
New purchases redirect to Stripe Checkout to enter payment details, and subsequent charges redirect to an Autumn hosted, one-click confirmation page.
|
|
|
|
You can build your own billing confirmation flows by using the [previewAttach](/api-reference/billing/previewAttach) function.
|
|
|
|
</Note>
|
|
|
|
</Step>
|
|
</Steps>
|
|
|
|
</View>
|
|
|
|
{/* SERVER SDK DOCS */}
|
|
|
|
<View title="Server SDK" icon="server">
|
|
|
|
<Steps>
|
|
<Step>
|
|
### Create your pricing plans
|
|
|
|
Create a plan for each pricing tier that your app offers. In our example we'll create a "Free" and "Pro" plan, and assign them features.
|
|
|
|
<CreatePlans />
|
|
|
|
</Step>
|
|
|
|
<Step>
|
|
### Installation
|
|
|
|
[Create an Autumn Secret key](https://app.useautumn.com/sandbox/dev?tab=api_keys), and paste it in your `.env` variables. Then, install the Autumn SDK. If you're using the CLI, this will be done for you.
|
|
|
|
```bash .env
|
|
AUTUMN_SECRET_KEY=am_sk_test_42424242...
|
|
```
|
|
|
|
<CodeGroup>
|
|
|
|
```bash bun
|
|
bun add autumn-js
|
|
```
|
|
|
|
```bash npm
|
|
npm install autumn-js
|
|
```
|
|
|
|
```bash pnpm
|
|
pnpm add autumn-js
|
|
```
|
|
|
|
```bash yarn
|
|
yarn add autumn-js
|
|
```
|
|
|
|
```bash pip
|
|
pip install autumn-sdk
|
|
```
|
|
|
|
</CodeGroup>
|
|
|
|
</Step>
|
|
|
|
<Step>
|
|
### Create an Autumn customer
|
|
|
|
When the customer signs up, create an Autumn customer for them. Autumn will automatically enable the <Badge color="green">Free</Badge> plan, since you marked it with the `auto-enable` flag.
|
|
|
|
<CodeGroup>
|
|
|
|
```typescript TypeScript
|
|
import { Autumn } from "autumn-js";
|
|
|
|
const autumn = new Autumn({
|
|
secretKey: "am_sk_42424242",
|
|
});
|
|
|
|
const customer = await autumn.customers.getOrCreate({
|
|
customerId: "user_or_org_id_from_auth",
|
|
name: "John Doe",
|
|
email: "john@example.com",
|
|
});
|
|
```
|
|
|
|
```python Python
|
|
import asyncio
|
|
from autumn_sdk import Autumn
|
|
|
|
autumn = Autumn('am_sk_42424242')
|
|
|
|
async def main():
|
|
customer = await autumn.customers.get_or_create(
|
|
customer_id="user_or_org_id_from_auth",
|
|
name="John Doe",
|
|
email="john@example.com",
|
|
)
|
|
|
|
asyncio.run(main())
|
|
```
|
|
|
|
```bash cURL
|
|
curl --request POST \
|
|
--url https://api.useautumn.com/v1/customers \
|
|
--header 'Authorization: Bearer am_sk_42424242' \
|
|
--header 'Content-Type: application/json' \
|
|
--data '{
|
|
"customer_id": "user_or_org_id_from_auth",
|
|
"name": "John Doe",
|
|
"email": "john@example.com"
|
|
}'
|
|
```
|
|
|
|
</CodeGroup>
|
|
|
|
<Check>
|
|
Autumn's customer ID is the same as your internal user or org ID generated
|
|
from your auth provider. No need to store any extra IDs.
|
|
</Check>
|
|
|
|
In the Autumn dashboard, you will see your user under the [customers](https://app.useautumn.com/customers) page.
|
|
|
|
</Step>
|
|
|
|
<Step>
|
|
|
|
### Stripe Payment Flow
|
|
|
|
Call `attach` when the customer wants to purchase the <Badge color="blue">Pro</Badge> plan. This will return a Stripe payment URL. Once they've paid, Autumn will grant access to "100 messages per month" defined in Step 1.
|
|
|
|
<CodeGroup>
|
|
|
|
```typescript TypeScript
|
|
import { Autumn } from "autumn-js";
|
|
|
|
const autumn = new Autumn({
|
|
secretKey: "am_sk_42424242",
|
|
});
|
|
|
|
const response = await autumn.billing.attach({
|
|
customerId: "user_or_org_id_from_auth",
|
|
planId: "pro",
|
|
redirectMode: "always",
|
|
});
|
|
|
|
// Redirect customer to complete payment or confirm plan change
|
|
redirect(response.paymentUrl);
|
|
```
|
|
|
|
```python Python
|
|
import asyncio
|
|
from autumn_sdk import Autumn
|
|
|
|
autumn = Autumn('am_sk_42424242')
|
|
|
|
async def main():
|
|
response = await autumn.billing.attach(
|
|
customer_id='user_or_org_id_from_auth',
|
|
plan_id='pro',
|
|
redirect_mode='always',
|
|
)
|
|
|
|
asyncio.run(main())
|
|
```
|
|
|
|
```bash cURL
|
|
curl -X POST 'https://api.useautumn.com/v1/attach' \
|
|
-H 'Authorization: Bearer am_sk_42424242' \
|
|
-H 'Content-Type: application/json' \
|
|
-d '{
|
|
"customer_id": "user_or_org_id_from_auth",
|
|
"plan_id": "pro",
|
|
"redirect_mode": "always"
|
|
}'
|
|
```
|
|
|
|
</CodeGroup>
|
|
|
|
<Note>
|
|
Use Stripe's test card `4242 4242 4242 4242` to make a purchase in sandbox.
|
|
You can enter any Expiry and CVV.
|
|
</Note>
|
|
|
|
This can be used for any plan changes scenario (upgrades, downgrades, one-time topups, renewals, etc).
|
|
|
|
Upgrades will happen immediately, and downgrades will be scheduled for the next billing cycle.
|
|
|
|
<Note>
|
|
The **`redirectMode: "always"`** flag will always return a payment URL.
|
|
|
|
New purchases redirect to Stripe Checkout to enter payment details, and subsequent charges redirect to an Autumn hosted, one-click confirmation page.
|
|
|
|
You can build your own billing confirmation flows by using the [previewAttach](/api-reference/billing/previewAttach) function.
|
|
|
|
</Note>
|
|
|
|
</Step>
|
|
</Steps>
|
|
</View>
|
|
|
|
**Next: Track and limit usage**
|
|
|
|
Now that the plan is enabled and you've handled payments, you can now make sure that customers have the access to the right features and limits based on their plan.
|
|
|
|
<Card
|
|
title="Track and limit usage"
|
|
href="/documentation/getting-started/gating"
|
|
>
|
|
Enforce usage limits and feature permissions using Autumn's `check` and
|
|
`track` functions
|
|
</Card>
|