AI Builders
How to integrate Autumn using an AI application builder
Using Autumn, you can reliably integrate Stripe with your AI application builder like Lovable, Bolt.new, Replit or v0 in just a couple prompts—no webhooks or server management required.
1. Create your products
Create your free Autumn account at useautumn.com. Then navigate to the Connect Stripe page and paste in your Test and Live Secret API keys.
Your Test and Live keys can be found in the Stripe Dashboard, under Developers > API keys.
Create the Pro plan in the Products tab.
Click on the ”+ Product” button and name the product “Pro”.
Click the ”+ Feature” button, and in the feature list, select “Create new feature”.
Back on the products page, create a new product and name it “Pro”. Click ”+ Feature” and add a limit of 10 messages per month.
Then click ”+ Price” and a price of $20 per month.
2. Setup
Use this prompt to setup Autumn. Make sure you have auth already handled first.
# Integrating Autumn for Billing
The user is using Autumn to manage their pricing, which is a layer over Stripe that controls entitlements and payment flows.
DO NOT touch or suggest using any of Stripe’s APIs
DO NOT implement any pricing logic (subscription statuses, feature gating) at this stage. That will be handled afterwards.
## Before Integration
1. Before starting the integration, check the user has Auth in place. If they don’t, do not proceed.
2. Prompt them for an Autumn TEST API key. This should be saved in supabase as AUTUMN_SECRET_KEY. The user can generate an Autumn API key from [https://app.useautumn.com/sandbox/dev](https://app.useautumn.com/sandbox/dev)
## Integration steps
1. Install autumn-js: `npm install autumn-js`
2. Create a supabase edge function called `autumn`. Inside the function, use this code to route the requests correctly, and resolve the `customerId`. This will be the user’s ID from Supabase Auth.
/supabase/functions/autumn/index.ts
import { autumnHandler } from "npm:autumn-js/supabase";
import { createClient } from "https://esm.sh/@supabase/supabase-js@2.49.9";
const corsHeaders = {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
"Access-Control-Allow-Headers": "Content-Type, Authorization",
};
Deno.serve(async (req: Request) => {
if (req.method === "OPTIONS") {
return new Response("ok", { headers: corsHeaders });
}
const supabaseClient = createClient(
Deno.env.get("SUPABASE_URL") ?? "",
Deno.env.get("SUPABASE_ANON_KEY") ?? "",
{
global: {
headers: { Authorization: req.headers.get("Authorization") },
},
}
);
const { data, error } = await supabaseClient.auth.getUser();
const handler = autumnHandler({
corsHeaders,
identify: async () => {
return {
customerId: data.user?.id,
customerData: {
email: data.user?.email,
},
};
},
});
return handler(req);
});
1. Wrap the application with <AutumnProvider />. The backendUrl should direct to the supabase function, set includeCredentials as false and pass in the bearerToken from supabase auth.
The backendUrl should look like <PROJECT_ID>. [supabase.co/functions/v1/autumn](https://supabase.co). You may be able to import a supabase URL from env.
<AutumnProvider
backendUrl={`https://<PROJECT_ID>.supabase.co/functions/v1/autumn`}
includeCredentials={false}
getBearerToken={async () => {
const { data } = await supabase.auth.getSession();
return data.session?.access_token;
}}
>
<App />
</AutumnProvider>
1. Now verify that everything works by calling useCustomer() on the frontend somewhere in the app, and logging the response. Ask the user to check if the customer has been created in Autumn.
import { useCustomer } from "autumn-js/react";
const { customer } = useCustomer();
console.log("Autumn Customer", customer);
3. Integrate your pricing model
Now you can describe to the AI the pricing plans you defined in Autumn (eg free tier has 3 messages, pro tier is 5 usd per month etc). Make sure to provide it with the productIds and featureIds (if you’re using usage pricing or limits). Then, paste in the prompt below.
I have a free and a pro tier. My free tier has 3 messages and pro has 100 messages for $10 per month. The product IDs are “free” and “pro”, and the feature ID is “messages”.
# Integrating Pricing Model
## Before Integration
1. Check that the user has provided the productIds for the pricing tiers they have. If they have not explicitly mentioned it, prompt them for it. Do not guess.
2. If they mention usage based features that are being tracked or limited, make sure they mention the featureIds. You may ask if you’re unsure whether it’s a usage-based feature.
## Pricing Logic integration
1. Use the `attach` hook to handle payments. This will redirect to a checkout URL if a new purchase, or handle any upgrades/downgrades/cancellations.
import ProductChangeDialog from "@components/autumn/product-change-dialog";
import { useAutumn } from "autumn-js/react";
<Button
onClick={async () =>
await attach({
productId: "pro",
dialog: ProductChangeDialog,
})
}
>
2. Build a productChangeDialog and pass it into the `attach` hook as above. This is a simplified version you can style to match the app’s theme.
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from '@/components/ui/dialog';
import { useAutumn } from "autumn-js/react"
const ProductChangeDialog = (params) => {
const [isLoading, setIsLoading] = useState(false);
const { attach } = useAutumn();
const { open, setOpen, preview } = params;
const handleConfirm = async () => {
setIsLoading(true);
await attach({productId: preview.product_id});
setOpen(false);
setIsLoading(false);
};
return (
<Dialog open={open} onOpenChange={setOpen}>
<DialogContent>
<DialogTitle>{preview?.title}</DialogTitle>
<div>{preview?.message}</div>
{preview?.due_today?.price && <div>Due today: ${preview?.due_today?.price}</div>}
<button onClick={() => setOpen(false)}>Cancel</button>
<button onClick={handleConfirm} disabled={isLoading}>
{isLoading ? 'Processing...' : 'Confirm'}
</button>
</DialogContent>
</Dialog>
);
};
export default ProductChangeDialog;
3. Check for product access from the customer state object, and use it to gate features. Replace “pro” with the provided productId.
DO NOT check for active status, as the product may be “trialing”.
import { useCustomer } from "autumn-js/react";
const premiumUser = customer.products.find((p) => p.id === "pro");
4. For usage-based features, you can use the check and track functions, to check access and then record usage. Replace “messages” with the provided featureId
import { useAutumn, useCustomer } from "autumn-js/react";
export default function SendChatMessage() {
const { check } = useAutumn();
const { customer, refetch } = useCustomer();
return (
<button
onClick={async () => {
let { data } = await check({ featureId: "messages" });
if (data?.allowed) {
//... send message, then
await track({ featureId: "messages" });
await refetch(); // refetch customer usage data
}
}}
>
Send Message
</button>
);
}
5. You can use the customer state hook to display any relevant information if the user needs
{
"created_at": 1677649423000,
“env": "production",
"id": "user_123",
"name": "John Yeo",
"email": "john@example.com",
"fingerprint": "",
"stripe_id": "cus_abc123",
"products": [
{
"id": "pro",
"name": "Pro Plan",
"group": "",
"status": "active",
"started_at": 1677649423000,
"canceled_at": null,
"subscription_ids": [
"sub_123"
],
"current_period_start": 1677649423000,
"current_period_end": 1680327823000
}
],
"features": {
"messages": {
"feature_id": "messages",
"unlimited": false,
"interval": "month",
"balance": 80,
"usage": 20,
"included_usage": 100,
"next_reset_at": 1680327823000
}
}
}
4. Handle failed payments and billing portal
Lastly, handle what should happen when a user’s payment fails and redirect them to the billing portal to manage or cancel their subscription.
# Handling failed payments with Autumn
1. If a payment is overdue, a customer’s product status will be `past_due`. If this is the case then you should direct the customer to the billing portal to update their payment method, before the product expires.
import { useCustomer } from "autumn-js/react";
const failed_payment = customer.products.find((p) => p.status === "past_due");
2. Billing portal
import { useAutumn } from "autumn-js/react";
export default function BillingSettings() {
const { openBillingPortal } = useAutumn();
return (
<button
onClick={async () => {
await openBillingPortal({
returnUrl: "https://google.com",
});
}}
>
Update Payment Method
</button>
);
}