API Reference
Complete reference for all API endpoints
API Reference
Complete reference for all API endpoints in the starter kit.
Base URL
Development: http://localhost:3000/api
Production: https://yourdomain.com/apiAuthentication
Most API routes require authentication. Include credentials in requests:
// Client-side (automatic with fetch from same origin)
const response = await fetch("/api/protected-route");
// Server-side
import { auth } from "@/lib/auth";
const session = await auth.api.getSession({
headers: request.headers,
});Response Format
All responses follow this format:
// Success
{
data: T, // Response data
success: true
}
// Error
{
error: string, // Error message
success: false
}Rate Limiting
Rate limits apply to sensitive endpoints:
| Endpoint | Limit |
|---|---|
/api/auth/* | 5 requests / 15 min |
/api/contact | 3 requests / 15 min |
| General API | 100 requests / 15 min |
Authentication Endpoints
Sign In
POST /api/auth/sign-inHeaders:
Content-Type: application/jsonBody:
{
"email": "user@example.com",
"password": "password123"
}Response (200):
{
"session": {
"token": "...",
"user": {
"id": "...",
"email": "user@example.com",
"name": "John Doe",
"role": "user"
}
}
}Sign Up
POST /api/auth/sign-upBody:
{
"email": "newuser@example.com",
"password": "securepassword",
"name": "New User"
}Response (201):
{
"user": {
"id": "...",
"email": "newuser@example.com",
"emailVerified": false
},
"message": "Verification email sent"
}Sign Out
POST /api/auth/sign-outResponse (200):
{
"success": true
}Blog Endpoints
Get All Posts
GET /api/blogQuery Parameters:
page(number): Page number (default: 1)limit(number): Items per page (default: 10)category(string): Filter by category slugtag(string): Filter by tag slugsearch(string): Search in title/contentstatus(string):publishedordraft(admin only)
Response (200):
{
"posts": [
{
"id": 1,
"title": "My Post",
"slug": "my-post",
"excerpt": "Short summary...",
"content": "Full content...",
"featuredImage": "https://...",
"published": true,
"publishedAt": "2024-01-01T00:00:00Z",
"viewCount": 100,
"likeCount": 10,
"author": {
"id": "...",
"name": "Author Name",
"image": "https://..."
},
"categories": [...],
"tags": [...]
}
],
"pagination": {
"page": 1,
"limit": 10,
"total": 50,
"totalPages": 5
}
}Get Single Post
GET /api/blog/{slug}Response (200):
{
"post": {
"id": 1,
"title": "My Post",
"slug": "my-post",
"content": "...",
"author": {...},
"categories": [...],
"tags": [...]
}
}Create Post (Admin)
POST /api/blogHeaders:
Authorization: Required (admin role)
Content-Type: application/jsonBody:
{
"title": "New Post",
"slug": "new-post",
"content": "Post content...",
"excerpt": "Short summary...",
"featuredImage": "https://...",
"categoryIds": [1, 2],
"tagIds": [1, 2, 3],
"published": false,
"seoTitle": "SEO Title",
"seoDescription": "SEO Description"
}Response (201):
{
"post": {
"id": 1,
"title": "New Post",
"slug": "new-post",
...
}
}Update Post (Admin)
PUT /api/blog/{id}Body: Same as create
Response (200): Updated post
Delete Post (Admin)
DELETE /api/blog/{id}Response (200):
{
"success": true,
"message": "Post deleted"
}Like Post
POST /api/blog/{id}/likeResponse (200):
{
"liked": true,
"likeCount": 11
}Subscription Endpoints
Create Checkout Session
POST /api/subscription/checkoutBody:
{
"priceId": "price_xxxxx",
"billingCycle": "monthly"
}Response (200):
{
"url": "https://checkout.stripe.com/..."
}Create Portal Session
POST /api/subscription/portalResponse (200):
{
"url": "https://billing.stripe.com/..."
}Get User Subscription
GET /api/subscriptionResponse (200):
{
"subscription": {
"id": "...",
"status": "active",
"plan": {
"name": "Pro",
"priceMonthly": 1999
},
"currentPeriodEnd": "2024-02-01T00:00:00Z"
}
}User Endpoints
Get Current User
GET /api/meResponse (200):
{
"user": {
"id": "...",
"email": "user@example.com",
"name": "John Doe",
"role": "user",
"subscription": {...}
}
}Update Profile
PUT /api/meBody:
{
"name": "New Name",
"image": "https://..."
}Response (200):
{
"user": {
"id": "...",
"name": "New Name",
...
}
}Admin Endpoints
Get All Users (Admin)
GET /api/admin/usersQuery Parameters:
page,limit,search,role
Response (200):
{
"users": [...],
"pagination": {...}
}Promote User (Admin)
POST /api/admin/users/promoteBody:
{
"userId": "user_123"
}Response (200):
{
"success": true,
"user": {
"id": "user_123",
"role": "admin"
}
}Ban User (Admin)
POST /api/admin/users/banBody:
{
"userId": "user_123",
"reason": "Violation of terms",
"expires": "2024-12-31T00:00:00Z"
}Contact Endpoints
Submit Contact Form
POST /api/contactBody:
{
"fullName": "John Doe",
"email": "john@example.com",
"phone": "+1234567890",
"company": "Acme Inc",
"subject": "Inquiry",
"message": "Hello..."
}Response (200):
{
"success": true,
"message": "Message sent successfully"
}Get Submissions (Admin)
GET /api/admin/contact-submissionsFile Upload Endpoints
Handled by UploadThing. See File Uploads for details.
POST /api/uploadthingWaitlist Endpoints
Join Waitlist
POST /api/waitlistBody:
{
"email": "user@example.com",
"name": "John Doe"
}Stripe Webhook
POST /api/stripe/webhookHeaders:
Stripe-Signature: ...Body: Stripe event payload
Error Codes
| Code | Meaning |
|---|---|
| 200 | Success |
| 201 | Created |
| 400 | Bad Request |
| 401 | Unauthorized |
| 403 | Forbidden |
| 404 | Not Found |
| 429 | Too Many Requests |
| 500 | Internal Server Error |
Example Usage
Fetch Blog Posts
const response = await fetch("/api/blog?page=1&limit=10");
const { posts, pagination } = await response.json();Create Blog Post (Admin)
const response = await fetch("/api/blog", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
title: "New Post",
content: "...",
published: false,
}),
});
const { post } = await response.json();Handle Errors
const response = await fetch("/api/blog");
if (!response.ok) {
const error = await response.json();
throw new Error(error.error || "Request failed");
}
const data = await response.json();Rate Limit Headers
Responses include rate limit headers:
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 99
X-RateLimit-Reset: 1640000000