REST API
Comprehensive REST API with 50+ documented endpoints, OpenAPI specification, and Swagger UI.
Overview
The AI SaaS Starter Kit provides a complete REST API for managing users, blogs, categories, subscriptions, and payments. All endpoints are documented with Swagger/OpenAPI and include authentication, validation, and error handling.
Authentication
Session-Based Auth
The API uses NextAuth session cookies for authentication:
// Sign in first
POST /api/auth/signin
// Session cookie is automatically set
// Subsequent requests include the cookie automaticallyMaking Authenticated Requests
fetch('/api/users', {
credentials: 'include', // Include session cookie
headers: {
'Content-Type': 'application/json',
},
})API Endpoints
Authentication
/api/auth/registerRegister a new user with email and password
/api/auth/sessionGet current user session
Users
/api/usersList all users (Admin only, with pagination and search)
/api/usersCreate a new user (Admin only)
/api/users/:idGet user details by ID
/api/users/:idUpdate user details
/api/users/:idDelete a user
/api/users/:id/rolesAssign role to user (Super Admin only)
/api/users/:id/rolesRemove role from user (Super Admin only)
Blogs
/api/blogsList all blog posts (public: published only)
/api/blogsCreate a new blog post (Admin only)
/api/blogs/:idGet blog post by ID or slug
/api/blogs/:idUpdate blog post (Admin only)
/api/blogs/:idDelete blog post (Admin only)
Categories
/api/categoriesList all categories (public)
/api/categoriesCreate a new category (Admin only)
/api/categories/:idGet category by ID or slug
/api/categories/:idUpdate category (Admin only)
/api/categories/:idDelete category (Admin only, if no posts)
Subscriptions
/api/subscriptionsList subscriptions (own or all for admin)
/api/subscriptions/:idGet subscription details
/api/subscriptions/:idCancel subscription
Payments
/api/paymentsList payments (own or all for admin)
/api/payments/:idGet payment details
Plans
/api/plansList all subscription plans (public)
Request/Response Format
Example Request
// Create a blog post
POST /api/blogs
Content-Type: application/json
{
"title": "Getting Started with Next.js 15",
"slug": "getting-started-nextjs-15",
"content": "Next.js 15 brings exciting new features...",
"excerpt": "A comprehensive guide to Next.js 15",
"featuredImage": "https://example.com/image.jpg",
"published": true,
"categoryIds": ["clx123..."]
}Success Response
HTTP/1.1 201 Created
Content-Type: application/json
{
"message": "Blog post created successfully",
"blog": {
"id": "clx456...",
"title": "Getting Started with Next.js 15",
"slug": "getting-started-nextjs-15"
}
}Error Response
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"error": "A blog post with this slug already exists"
}Pagination
List endpoints support pagination with query parameters:
GET /api/users?page=1&perPage=10
// Response
{
"users": [...],
"pagination": {
"total": 42,
"page": 1,
"perPage": 10,
"totalPages": 5
}
}Query Parameters
page- Page number (default: 1)perPage- Items per page (default: 10, max: 100)search- Search queryfilter- Filter by specific fields
Filtering
// Filter users by role
GET /api/users?role=ADMIN
// Filter blogs by category
GET /api/blogs?category=clx123...
// Filter subscriptions by status
GET /api/subscriptions?status=active
// Combine filters
GET /api/payments?userId=clx456...&status=succeededSearching
// Search users by name or email
GET /api/users?search=john
// Search blogs by title or content
GET /api/blogs?search=nextjs
// Search categories by name
GET /api/categories?search=technologyError Codes
| Code | Meaning |
|---|---|
200 | Success |
201 | Created |
400 | Bad Request (validation error) |
401 | Unauthorized (not signed in) |
403 | Forbidden (insufficient permissions) |
404 | Not Found |
500 | Internal Server Error |
Rate Limiting
Consider implementing rate limiting for production:
// Example with upstash/ratelimit
import { Ratelimit } from "@upstash/ratelimit";
import { Redis } from "@upstash/redis";
const ratelimit = new Ratelimit({
redis: Redis.fromEnv(),
limiter: Ratelimit.slidingWindow(10, "10 s"),
});
// In API route
const { success } = await ratelimit.limit(userId);
if (!success) {
return NextResponse.json(
{ error: "Rate limit exceeded" },
{ status: 429 }
);
}CORS
If you need to allow cross-origin requests:
// Add to API route
export async function GET(req: Request) {
const headers = new Headers();
headers.set("Access-Control-Allow-Origin", "*");
headers.set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
headers.set("Access-Control-Allow-Headers", "Content-Type");
// Your response
return NextResponse.json(data, { headers });
}Webhook Security
Stripe webhooks include signature verification:
// POST /api/webhooks/stripe
const signature = req.headers.get("stripe-signature");
const event = stripe.webhooks.constructEvent(
body,
signature!,
process.env.STRIPE_WEBHOOK_SECRET!
);Best Practices
- Always validate input with Zod schemas
- Use proper HTTP status codes
- Implement authentication checks first
- Return consistent error formats
- Log all errors for debugging
- Use database transactions for multiple operations
- Implement idempotency for critical operations
Testing APIs
With cURL
curl -X POST http://localhost:3000/api/auth/register \
-H "Content-Type: application/json" \
-d '{"name":"John Doe","email":"john@example.com","password":"password123"}'With JavaScript
const response = await fetch('/api/blogs', {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
title: 'My Blog Post',
slug: 'my-blog-post',
content: 'Content here...',
published: true,
}),
});
const data = await response.json();OpenAPI Specification
The complete OpenAPI/Swagger specification is automatically generated from JSDoc comments and available at:
/api-docs- Interactive Swagger UI/api/swagger- JSON specification
You can import the spec into tools like Postman or Insomnia for API testing.