API Routes
indiegoon includes pre-built API routes for authentication, billing, teams, and more. Here's the complete reference.
Authentication
All auth endpoints are handled by Better Auth's catch-all route:
/api/auth/[...all]
This automatically provides:
| Endpoint | Method | Description |
|---|---|---|
/api/auth/sign-up/email | POST | Register with email/password |
/api/auth/sign-in/email | POST | Sign in with email/password |
/api/auth/sign-in/social | POST | OAuth sign-in (Google, GitHub, etc.) |
/api/auth/sign-in/magic-link | POST | Send magic link email |
/api/auth/sign-out | POST | End session |
/api/auth/get-session | GET | Get current session |
/api/auth/forget-password | POST | Request password reset |
/api/auth/reset-password | POST | Set new password |
/api/auth/verify-email | POST | Verify email token |
You never need to modify this route. Better Auth handles everything.
Billing
Create Checkout
POST /api/billing/checkout
Content-Type: application/json
{ "priceId": "price_..." }
ā { "url": "https://checkout.stripe.com/..." }
Creates a checkout session with the configured payment provider. Requires authentication.
Customer Portal
POST /api/billing/portal
ā { "url": "https://billing.stripe.com/..." }
Returns a URL to the customer's billing portal (manage subscription, update card, view invoices).
List Invoices
GET /api/billing/invoices
ā { "invoices": [{ "id": "...", "amount": 9900, "status": "paid", "date": "..." }] }
Webhooks
Payment Webhooks
POST /api/webhooks/payments
Universal webhook endpoint. Works with all payment providers:
- ā¢Reads raw request body
- ā¢Verifies HMAC signature (provider-specific)
- ā¢Parses event into standard format
- ā¢Syncs subscription status to database
Set this URL in your payment provider's webhook settings.
Legacy Stripe Webhook
POST /api/webhooks/stripe
Alias that redirects to /api/webhooks/payments. Exists for backwards compatibility.
Teams
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| GET | /api/teams | User | List your teams |
| POST | /api/teams | User | Create a team |
| GET | /api/teams/[teamId] | Member | Get team details + your role |
| PATCH | /api/teams/[teamId] | Admin | Update team name/logo |
| DELETE | /api/teams/[teamId] | Owner | Delete team |
| POST | /api/teams/[teamId]/invite | Admin | Invite member by email |
Create Team
POST /api/teams
Content-Type: application/json
{ "name": "Acme Corp" }
ā { "id": "...", "name": "Acme Corp", "slug": "acme-corp" }
Name must be 2-50 characters. Slug is auto-generated.
Invite Member
POST /api/teams/[teamId]/invite
Content-Type: application/json
{ "email": "new@member.com", "role": "member" }
ā { "invitation": { "id": "...", "token": "...", "expiresAt": "..." } }
Valid roles: admin, member. Owner role cannot be assigned via invitation.
Lead Capture
POST /api/lead
Content-Type: application/json
{ "email": "visitor@example.com", "source": "landing-page" }
ā { "success": true }
Idempotent ā won't duplicate if email already exists. Use this for waitlists, newsletter signups, etc.
OG Image Generation
GET /api/og?title=Hello+World
Generates a dynamic Open Graph image using @vercel/og (Edge Runtime). Used automatically by your metadata configuration.
Adding Your Own Routes
Create new routes in src/app/api/:
// src/app/api/projects/route.ts
import { auth } from "@/lib/auth"
import { db } from "@/lib/db"
export async function GET(request: Request) {
const session = await auth.api.getSession({ headers: request.headers })
if (!session) {
return Response.json({ error: "Unauthorized" }, { status: 401 })
}
const projects = await db.query.projects.findMany({
where: eq(projects.userId, session.user.id),
})
return Response.json({ projects })
}
export async function POST(request: Request) {
const session = await auth.api.getSession({ headers: request.headers })
if (!session) {
return Response.json({ error: "Unauthorized" }, { status: 401 })
}
const body = await request.json()
const project = await db.insert(projects).values({
id: crypto.randomUUID(),
name: body.name,
userId: session.user.id,
}).returning()
return Response.json({ project: project[0] }, { status: 201 })
}
Rate Limiting
All API routes (except /api/auth/* and /api/webhooks/*) are rate limited via middleware:
- ā¢Limit: 20 requests per 10 seconds per IP
- ā¢Algorithm: Sliding window (Upstash Redis)
- ā¢Fallback: If Redis is not configured, rate limiting is disabled (requests pass through)
The rate limiter returns 429 Too Many Requests when exceeded.
CORS & Security
- ā¢API routes are server-side only (no CORS issues for same-origin requests)
- ā¢Webhook routes skip auth and rate limiting (they verify signatures instead)
- ā¢All responses include security headers from
next.config.ts
Next Steps
- ā¢Authentication ā How auth works under the hood
- ā¢Payments ā Payment provider details
- ā¢Teams ā Team API in depth