How to Integrate Next.js for payments with Vercel AI SDK for startups
Why this integration matters
If you’re building an AI agent for a startup, payments and model orchestration usually live in separate silos. Next.js handles the checkout and billing surface, while Vercel AI SDK handles the agent loop, tool calls, and streamed responses.
Connecting them gives you one clean flow: the agent can qualify a user request, generate a payment intent, confirm payment status, then unlock the paid workflow. That’s the pattern behind paywalled copilots, usage-based assistants, and automated service agents.
Prerequisites
- •Python 3.11+
- •A Next.js app with a payment provider wired in, typically:
- •Stripe Checkout or Payment Intents
- •A webhook endpoint for payment confirmation
- •A Vercel project using the AI SDK on the frontend or server layer
- •API keys configured in environment variables:
- •
STRIPE_SECRET_KEY - •
STRIPE_WEBHOOK_SECRET - •
OPENAI_API_KEYor another model provider key used by Vercel AI SDK
- •
- •A public webhook URL for local development via ngrok or Vercel preview URLs
- •Basic familiarity with:
- •
stripePython SDK - •HTTP requests in Python
- •calling Vercel AI endpoints from a backend service
- •
Integration Steps
1) Create a payment session from your Python backend
Your agent should not talk directly to Stripe from the browser. Keep payment creation behind a backend route, then return the checkout URL or client secret to your Next.js app.
import os
import stripe
stripe.api_key = os.environ["STRIPE_SECRET_KEY"]
def create_checkout_session(user_id: str, price_id: str):
session = stripe.checkout.Session.create(
mode="payment",
line_items=[{"price": price_id, "quantity": 1}],
success_url="https://yourapp.com/success?session_id={CHECKOUT_SESSION_ID}",
cancel_url="https://yourapp.com/cancel",
metadata={"user_id": user_id}
)
return {
"session_id": session.id,
"checkout_url": session.url,
}
if __name__ == "__main__":
result = create_checkout_session("user_123", "price_abc123")
print(result)
In Next.js, you’d call this backend from an API route or server action. The important part is that your agent gets back a stable payment reference it can track.
2) Expose a webhook to confirm payment
Do not trust the frontend redirect alone. Use Stripe webhooks to confirm that the payment succeeded, then update your app state and notify your agent layer.
import os
from fastapi import FastAPI, Request, HTTPException
import stripe
app = FastAPI()
stripe.api_key = os.environ["STRIPE_SECRET_KEY"]
webhook_secret = os.environ["STRIPE_WEBHOOK_SECRET"]
@app.post("/webhooks/stripe")
async def stripe_webhook(request: Request):
payload = await request.body()
sig_header = request.headers.get("stripe-signature")
try:
event = stripe.Webhook.construct_event(
payload=payload,
sig_header=sig_header,
secret=webhook_secret,
)
except Exception as e:
raise HTTPException(status_code=400, detail=str(e))
if event["type"] == "checkout.session.completed":
session = event["data"]["object"]
user_id = session["metadata"]["user_id"]
payment_status = session["payment_status"]
# Persist to your DB here
print(f"Payment confirmed for {user_id}: {payment_status}")
return {"received": True}
This is where you flip entitlement flags like paid=true, plan=pro, or credits=100. Your agent should read that state before allowing premium actions.
3) Call the Vercel AI SDK-powered agent after payment confirmation
Vercel AI SDK is usually used in Next.js with streamText, generateText, or tool calling on the server side. From Python, treat it as an HTTP-backed capability exposed by your app.
import os
import requests
VERCEL_AGENT_URL = os.environ["VERCEL_AGENT_URL"]
def ask_agent(prompt: str, user_id: str):
response = requests.post(
f"{VERCEL_AGENT_URL}/api/agent",
json={
"messages": [
{"role": "system", "content": "You are a startup billing assistant."},
{"role": "user", "content": prompt},
],
"userId": user_id,
},
timeout=30,
)
response.raise_for_status()
return response.json()
if __name__ == "__main__":
result = ask_agent("Unlock my premium report generation workflow.", "user_123")
print(result)
On the Next.js side, your /api/agent route would use Vercel AI SDK methods like streamText() or generateText(). The Python service just orchestrates when to call it.
4) Gate agent tools based on payment state
The key integration point is authorization. Before invoking expensive tools or premium model calls, check whether the user has paid.
import sqlite3
def has_active_access(user_id: str) -> bool:
conn = sqlite3.connect("app.db")
cursor = conn.cursor()
cursor.execute(
"SELECT paid FROM entitlements WHERE user_id = ? ORDER BY updated_at DESC LIMIT 1",
(user_id,),
)
row = cursor.fetchone()
conn.close()
return bool(row and row[0] == 1)
def run_paid_workflow(user_id: str, prompt: str):
if not has_active_access(user_id):
return {
"status": "blocked",
"message": "Payment required before running this workflow.",
}
# Call your Next.js + Vercel AI SDK endpoint here
return ask_agent(prompt, user_id)
print(run_paid_workflow("user_123", "Generate my tax summary"))
This keeps your agent honest. If you later add subscriptions or credits, this function becomes the single source of truth for access control.
5) Wire the full flow into a startup-ready purchase path
At this point you have three moving parts:
- •payment creation
- •webhook confirmation
- •paid agent execution
The final step is to map them into one request lifecycle.
def start_paid_request(user_id: str, price_id: str, prompt: str):
if not has_active_access(user_id):
checkout = create_checkout_session(user_id=user_id, price_id=price_id)
return {
"status": "requires_payment",
"checkout_url": checkout["checkout_url"],
"session_id": checkout["session_id"],
}
agent_response = ask_agent(prompt=prompt, user_id=user_id)
return {
"status": "ok",
"agent_response": agent_response,
}
That pattern works well for startups because it supports both self-serve checkout and post-payment automation without mixing business logic into UI code.
Testing the Integration
Use one test path for unpaid users and one for paid users. The goal is to verify that checkout is created first, then agent access opens after entitlement updates.
if __name__ == "__main__":
unpaid_result = start_paid_request(
user_id="user_999",
price_id="price_abc123",
prompt="Summarize my account activity.",
)
print(unpaid_result)
# Expected output:
# {
# 'status': 'requires_payment',
# 'checkout_url': 'https://checkout.stripe.com/...'
# }
After Stripe sends checkout.session.completed and your DB marks the user as paid:
paid_result = start_paid_request(
user_id="user_999",
price_id="price_abc123",
prompt="Summarize my account activity.",
)
print(paid_result)
# Expected output:
# {
# 'status': 'ok',
# 'agent_response': {
# 'text': 'Here is your summary...',
# ...
# }
# }
Real-World Use Cases
- •
Paid document agents
Users pay once to generate contracts, policy summaries, onboarding packs, or financial reports through an AI assistant. - •
Usage-based copilots
Charge per report generation, fraud review, claim triage run, or premium analysis request. - •
Subscription-gated workflows
Unlock higher-context agents for enterprise tiers while keeping free users on limited prompts and lower-cost models.
Keep learning
- •The complete AI Agents Roadmap — my full 8-step breakdown
- •Free: The AI Agent Starter Kit — PDF checklist + starter code
- •Work with me — I build AI for banks and insurance companies
By Cyprian Aarons, AI Consultant at Topiax.
Want the complete 8-step roadmap?
Grab the free AI Agent Starter Kit — architecture templates, compliance checklists, and a 7-email deep-dive course.
Get the Starter Kit