---
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 Free plan that gives users 5 chat messages per month for free
- A Pro plan that gives users 100 chat messages per month for $20 per month.
{/* REACT DOCS */}
Autumn's client-side [hooks](/react/hooks/useCustomer) are supported for
fullstack TypeScript apps. Please use the Server SDK for other frameworks.
### 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.
### 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...
```
```bash bun
bun add autumn-js
```
```bash npm
npm install autumn-js
```
```bash pnpm
pnpm add autumn-js
```
```bash yarn
yarn add autumn-js
```
If you're using a separate backend and frontend, make sure to install the
library in both.
### 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.
```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 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 Web Standard (Elysia, CF Workers, etc...)
// Works with any fetch()-compatible WinterTC environment
import { autumnHandler } from "autumn-js/fetch";
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 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" },
});
```
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.
### Add Provider Client-side
Client side, wrap your application with the `` component.
```jsx
// layout.tsx
import { AutumnProvider } from "autumn-js/react";
export default function RootLayout({ children }: {
children: React.ReactNode,
}) {
return (
{children}
);
}
```
### 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 Free 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
My very profitable app
;
};
```
```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
}
}
}
```
You will see your user under the [customers](https://app.useautumn.com/customers) page in the Autumn dashboard.
### Stripe Payment Flow
Call `attach` when the customer wants to purchase the Pro 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.
Use Stripe's test card `4242 4242 4242 4242` to make a purchase in sandbox.
You can enter any Expiry and CVV.
```jsx React
import { useCustomer } from "autumn-js/react";
export default function PurchaseButton() {
const { attach } = useCustomer();
return (
);
}
```
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.
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.
{/* SERVER SDK DOCS */}
### 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.
### 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...
```
```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
```
### Create an Autumn customer
When the customer signs up, create an Autumn customer for them. Autumn will automatically enable the Free plan, since you marked it with the `auto-enable` flag.
```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"
}'
```
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.
In the Autumn dashboard, you will see your user under the [customers](https://app.useautumn.com/customers) page.
### Stripe Payment Flow
Call `attach` when the customer wants to purchase the Pro 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.
```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"
}'
```
Use Stripe's test card `4242 4242 4242 4242` to make a purchase in sandbox.
You can enter any Expiry and CVV.
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.
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.
**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.
Enforce usage limits and feature permissions using Autumn's `check` and
`track` functions