API Documentation¶
This document describes the API endpoints available in the chat application.
Authentication¶
All API endpoints (except /api/auth/*) require authentication via NextAuth.js session tokens.
Rate Limiting¶
All requests are rate-limited to 5 requests per 10 seconds per IP address.
Rate limit headers are included in all responses:
X-RateLimit-Limit: Maximum number of requests allowedX-RateLimit-Remaining: Number of requests remaining in the current windowX-RateLimit-Reset: Unix timestamp when the rate limit resets
Endpoints¶
POST /api/chat¶
Stream AI responses for chat messages.
Request Body:
{
messages: Array<{
role: "user" | "assistant";
content: string;
image?: string; // Optional base64-encoded image data URL
}>;
modelId?: string; // Optional Vertex AI model ID (e.g., "gemini-1.5-flash-002")
}
Available Models:
gemini-1.5-flash-002(default) - Fast and efficientgemini-1.5-pro-002- Most capable for complex reasoninggemini-1.0-pro- Previous generationgemini-1.0-pro-vision- Multimodal with vision capabilities
Validation Rules:
- Minimum 1 message, maximum 100 messages
- Message content: 1-10,000 characters
- Images: Base64-encoded data URLs
- Model ID must be one of the available models (optional)
Response:
Streams text content as text/plain; charset=utf-8.
Headers:
Content-Type: text/plain; charset=utf-8Cache-Control: no-cacheConnection: keep-alive
Error Responses:
// 400 Bad Request
{
error: "Invalid request body";
}
// 500 Internal Server Error
{
error: "Internal server error";
}
Example:
const response = await fetch("/api/chat", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
messages: [{ role: "user", content: "Hello, how are you?" }],
modelId: "gemini-1.5-pro-002", // Optional: specify which model to use
}),
});
if (!response.ok) {
const error = await response.json();
console.error(error);
return;
}
// Stream the response
const reader = response.body.getReader();
const decoder = new TextDecoder();
while (true) {
const { done, value } = await reader.read();
if (done) break;
const chunk = decoder.decode(value);
console.log(chunk);
}
POST /api/auth/[...nextauth]¶
NextAuth.js authentication endpoints. See NextAuth.js documentation for details.
Available routes:
GET /api/auth/signin- Sign in pagePOST /api/auth/signin/credentials- Credentials sign in (available only whenENABLE_TEST_CREDENTIALS=true)GET /api/auth/signout- Sign out pagePOST /api/auth/signout- Sign out actionGET /api/auth/session- Get current sessionGET /api/auth/csrf- Get CSRF token
Error Handling¶
All API endpoints follow a consistent error format:
Common HTTP Status Codes¶
200 OK- Request succeeded400 Bad Request- Invalid request body or parameters401 Unauthorized- Authentication required429 Too Many Requests- Rate limit exceeded500 Internal Server Error- Server error
Security¶
Authentication¶
Authentication is handled by NextAuth.js using Google OAuth. Access is restricted to emails defined in the invite allowlist. A credentials provider is conditionally enabled for automated testing when the ENABLE_TEST_CREDENTIALS flag is set.
Rate Limiting¶
Implemented using Upstash Redis with sliding window algorithm:
- 5 requests per 10 seconds per IP
- Returns 429 status with retry information when exceeded
CORS¶
CORS is not enabled. The API is designed to be consumed by the same-origin frontend only.
Input Validation¶
All inputs are validated using Zod schemas:
- Message content length limits
- Message array size limits
- Image format validation (client-side)
Security Headers¶
The application includes comprehensive security headers:
- Strict-Transport-Security (HSTS)
- X-Frame-Options
- X-Content-Type-Options
- X-XSS-Protection
- Content-Security-Policy
- Referrer-Policy
Client-Side Usage¶
The application provides a custom useChat hook for easy integration:
import { useChat } from "@/lib/hooks/use-chat";
function ChatComponent() {
const {
messages,
input,
handleInputChange,
handleSubmit,
isLoading,
setImage,
} = useChat();
return (
<form onSubmit={handleSubmit}>
<input value={input} onChange={handleInputChange} />
<button type="submit" disabled={isLoading}>
Send
</button>
</form>
);
}