Overview
The Next.js adapter enables seamless integration between Autumn and Next.js applications using the App Router. It provides a clean API for handling Autumn requests in your Next.js route handlers.
Installation
Install the Autumn JS SDK which includes the Next.js adapter:
Quick Start
Create a catch-all route handler in your Next.js app:
app/api/autumn/[...autumn]/route.ts
import { nextAutumnHandler } from "autumn-js/adapters" ;
import { auth } from "@/lib/auth" ;
const handler = nextAutumnHandler ({
identify : async ( request ) => {
// Get the authenticated user
const session = await auth ();
if ( ! session ?. user ) return null ;
return {
customerId: session . user . id ,
customerData: {
name: session . user . name ,
email: session . user . email ,
},
};
},
secretKey: process . env . AUTUMN_SECRET_KEY ,
});
export const { GET , POST , DELETE } = handler ;
Configuration
The nextAutumnHandler accepts the following options:
Options
identify
(request: Request) => AuthResult
required
Function to identify the customer from the Next.js request. Return null for unauthenticated requests. Returns: { customerId: string; customerData?: { name?: string; email?: string; ... } } or null
secretKey
string
default: "process.env.AUTUMN_SECRET_KEY"
Your Autumn API secret key. Defaults to the AUTUMN_SECRET_KEY environment variable.
autumnURL
string
default: "https://api.useautumn.com/v1"
The Autumn API base URL. Only change this if you’re self-hosting Autumn.
pathPrefix
string
default: "/api/autumn"
The path prefix for all Autumn routes. Should match your route file location.
Route Handler Structure
The adapter returns an object with HTTP method handlers that you can export:
const handler = nextAutumnHandler ({ /* options */ });
// Export the methods you need
export const { GET , POST , DELETE } = handler ;
Supported methods:
GET - For read operations
POST - For create/update operations
DELETE - For delete operations
Integration with Next-Auth
Using Next-Auth v5 (Auth.js)
app/api/autumn/[...autumn]/route.ts
import { nextAutumnHandler } from "autumn-js/adapters" ;
import { auth } from "@/auth" ;
const handler = nextAutumnHandler ({
identify : async ( request ) => {
const session = await auth ();
if ( ! session ?. user ) return null ;
return {
customerId: session . user . id ,
customerData: {
name: session . user . name ?? undefined ,
email: session . user . email ?? undefined ,
},
};
},
});
export const { GET , POST , DELETE } = handler ;
Using Next-Auth v4
app/api/autumn/[...autumn]/route.ts
import { nextAutumnHandler } from "autumn-js/adapters" ;
import { getServerSession } from "next-auth" ;
import { authOptions } from "@/lib/auth" ;
const handler = nextAutumnHandler ({
identify : async ( request ) => {
const session = await getServerSession ( authOptions );
if ( ! session ?. user ) return null ;
return {
customerId: session . user . id ,
customerData: {
name: session . user . name ,
email: session . user . email ,
},
};
},
});
export const { GET , POST , DELETE } = handler ;
Integration with Clerk
app/api/autumn/[...autumn]/route.ts
import { nextAutumnHandler } from "autumn-js/adapters" ;
import { auth } from "@clerk/nextjs/server" ;
const handler = nextAutumnHandler ({
identify : async ( request ) => {
const { userId } = await auth ();
if ( ! userId ) return null ;
return {
customerId: userId ,
};
},
});
export const { GET , POST , DELETE } = handler ;
Integration with Custom JWT Auth
app/api/autumn/[...autumn]/route.ts
import { nextAutumnHandler } from "autumn-js/adapters" ;
import { verify } from "jsonwebtoken" ;
const handler = nextAutumnHandler ({
identify : async ( request ) => {
const authHeader = request . headers . get ( "authorization" );
if ( ! authHeader ?. startsWith ( "Bearer " )) return null ;
const token = authHeader . substring ( 7 );
try {
const payload = verify ( token , process . env . JWT_SECRET ! ) as {
sub : string ;
email : string ;
name : string ;
};
return {
customerId: payload . sub ,
customerData: {
email: payload . email ,
name: payload . name ,
},
};
} catch {
return null ;
}
},
});
export const { GET , POST , DELETE } = handler ;
Integration with Cookies
app/api/autumn/[...autumn]/route.ts
import { nextAutumnHandler } from "autumn-js/adapters" ;
import { cookies } from "next/headers" ;
import { getUser } from "@/lib/session" ;
const handler = nextAutumnHandler ({
identify : async ( request ) => {
const cookieStore = await cookies ();
const sessionId = cookieStore . get ( "session" )?. value ;
if ( ! sessionId ) return null ;
const user = await getUser ( sessionId );
return user
? {
customerId: user . id ,
customerData: {
name: user . name ,
email: user . email ,
},
}
: null ;
},
});
export const { GET , POST , DELETE } = handler ;
Available Routes
Once configured with the catch-all route [...autumn], the following endpoints are automatically available:
Customer Routes
POST /api/autumn/getOrCreateCustomer - Get or create customer
Billing Routes
POST /api/autumn/attach - Attach a plan to customer
POST /api/autumn/previewAttach - Preview plan attachment
POST /api/autumn/updateSubscription - Update subscription
POST /api/autumn/previewUpdateSubscription - Preview subscription update
POST /api/autumn/openCustomerPortal - Open customer billing portal
POST /api/autumn/multiAttach - Attach multiple plans
POST /api/autumn/previewMultiAttach - Preview multiple plan attachments
POST /api/autumn/setupPayment - Setup payment method
Plan Routes
POST /api/autumn/listPlans - List available plans
Event Routes
POST /api/autumn/listEvents - List customer events
POST /api/autumn/aggregateEvents - Aggregate event data
Referral Routes
POST /api/autumn/createReferralCode - Create referral code
POST /api/autumn/redeemReferralCode - Redeem referral code
File Structure
Place your Autumn handler in a catch-all route:
app/
└── api/
└── autumn/
└── [...autumn]/
└── route.ts
This structure captures all requests under /api/autumn/*.
How It Works
The adapter:
Receives requests to your catch-all route
Parses request method and body from the Next.js Request object
Calls your identify function to determine customer identity
Routes to the appropriate handler based on the URL path
Returns NextResponse with JSON body and proper status codes
TypeScript Support
The adapter is fully typed:
import type { NextAutumnHandlerOptions } from "autumn-js/adapters" ;
const options : NextAutumnHandlerOptions = {
identify : async ( request ) => {
// request is typed as Request
const auth = request . headers . get ( "authorization" );
// ...
},
secretKey: process . env . AUTUMN_SECRET_KEY ,
};
Error Handling
The adapter automatically handles errors:
401 Unauthorized - When identify returns null for protected routes
404 Not Found - When the route doesn’t exist
400 Bad Request - For invalid request bodies
500 Internal Server Error - For SDK errors
All errors return JSON:
{
"code" : "error_code" ,
"message" : "Human-readable error message"
}
Custom Path Prefix
If you place your route in a different location, update the pathPrefix:
app/api/billing/[...billing]/route.ts
const handler = nextAutumnHandler ({
identify : async ( request ) => { /* ... */ },
pathPrefix: "/api/billing" ,
});
export const { GET , POST , DELETE } = handler ;
Environment Variables
Create a .env.local file:
# Required: Your Autumn secret key
AUTUMN_SECRET_KEY = sk_...
# Optional: Custom Autumn API URL (for self-hosted instances)
AUTUMN_API_URL = https://api.useautumn.com/v1
Middleware Integration
You can use Next.js middleware to protect your Autumn routes:
import { NextResponse } from "next/server" ;
import type { NextRequest } from "next/server" ;
export function middleware ( request : NextRequest ) {
// Your auth logic here
const token = request . cookies . get ( "session" )?. value ;
if ( ! token && request . nextUrl . pathname . startsWith ( "/api/autumn" )) {
return NextResponse . json (
{ code: "unauthorized" , message: "Authentication required" },
{ status: 401 }
);
}
return NextResponse . next ();
}
export const config = {
matcher: "/api/autumn/:path*" ,
};
Complete Example
Here’s a complete setup with Next-Auth:
app/api/autumn/[...autumn]/route.ts
import { nextAutumnHandler } from "autumn-js/adapters" ;
import { auth } from "@/auth" ;
const handler = nextAutumnHandler ({
identify : async ( request ) => {
const session = await auth ();
if ( ! session ?. user ?. id ) return null ;
return {
customerId: session . user . id ,
customerData: {
name: session . user . name ?? undefined ,
email: session . user . email ?? undefined ,
},
};
},
secretKey: process . env . AUTUMN_SECRET_KEY ,
autumnURL: process . env . AUTUMN_API_URL ,
});
// Export all supported methods
export const { GET , POST , DELETE } = handler ;
AUTUMN_SECRET_KEY = sk_test_ ...
AUTUMN_API_URL = https : //api.useautumn.com/v1
Server Components
Since route handlers run on the server, you can safely use server-only code:
import { nextAutumnHandler } from "autumn-js/adapters" ;
import { db } from "@/lib/db" ;
import "server-only" ;
const handler = nextAutumnHandler ({
identify : async ( request ) => {
// Direct database access is safe here
const session = await db . session . findUnique ({ /* ... */ });
return session
? {
customerId: session . userId ,
customerData: {
name: session . user . name ,
email: session . user . email ,
},
}
: null ;
},
});
export const { GET , POST , DELETE } = handler ;
Next Steps
Better Auth Integration Use Autumn with Better Auth for authentication
React Hooks Call Autumn endpoints from your React components
API Reference Explore all available API endpoints
Billing Integration Learn about attaching plans and billing