Complete reference for the Composter REST API.
Production: https://composter.onrender.com/api
Self-hosted: Configure in your .env file
All API endpoints (except auth) require JWT authentication.
Use Better Auth's sign-in endpoint to get a JWT token:
curl -X POST https://composter.onrender.com/api/auth/sign-in/email \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com",
"password": "yourpassword"
}'Response:
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"user": {
"id": "user_123",
"email": "user@example.com",
"name": "John Doe"
}
}Include the JWT token in the Authorization header:
curl -H "Authorization: Bearer YOUR_JWT_TOKEN" \
https://composter.onrender.com/api/categoriesCreate a new account.
Request:
{
"email": "user@example.com",
"password": "securepassword",
"name": "John Doe"
}Response (201):
{
"user": {
"id": "user_123",
"email": "user@example.com",
"name": "John Doe"
},
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}Login to existing account.
Request:
{
"email": "user@example.com",
"password": "yourpassword"
}Response (200):
{
"user": {
"id": "user_123",
"email": "user@example.com",
"name": "John Doe"
},
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}Get current session info.
Headers:
Authorization: Bearer YOUR_JWT_TOKEN
Response (200):
{
"user": {
"id": "user_123",
"email": "user@example.com",
"name": "John Doe"
},
"session": {
"expiresAt": "2025-01-20T10:30:00Z"
}
}List all user's categories.
Headers:
Authorization: Bearer YOUR_JWT_TOKEN
Response (200):
{
"categories": [
{
"id": "cat_123",
"name": "buttons",
"userId": "user_123",
"createdAt": "2024-12-01T10:00:00Z",
"componentCount": 5
},
{
"id": "cat_124",
"name": "forms",
"userId": "user_123",
"createdAt": "2024-12-02T14:30:00Z",
"componentCount": 3
}
]
}Create a new category.
Headers:
Authorization: Bearer YOUR_JWT_TOKEN
Content-Type: application/json
Request:
{
"name": "buttons"
}Response (201):
{
"category": {
"id": "cat_123",
"name": "buttons",
"userId": "user_123",
"createdAt": "2024-12-01T10:00:00Z"
}
}Errors:
400- Category name already exists401- Unauthorized422- Invalid category name
Delete a category and all its components.
Headers:
Authorization: Bearer YOUR_JWT_TOKEN
Response (200):
{
"message": "Category deleted successfully"
}Errors:
404- Category not found401- Unauthorized
List all user's components (optionally filtered by category).
Headers:
Authorization: Bearer YOUR_JWT_TOKEN
Query Parameters:
category(optional) - Filter by category namesearch(optional) - Search in title and codelimit(optional) - Max results (default: 50)offset(optional) - Pagination offset
Example:
GET /api/components?category=buttons&limit=10Response (200):
{
"components": [
{
"id": "comp_123",
"title": "PrimaryButton",
"category": "buttons",
"code": "export default function PrimaryButton() { ... }",
"userId": "user_123",
"createdAt": "2024-12-01T10:00:00Z",
"updatedAt": "2024-12-15T08:30:00Z"
}
],
"total": 1,
"limit": 10,
"offset": 0
}Get a specific component.
Headers:
Authorization: Bearer YOUR_JWT_TOKEN
Response (200):
{
"component": {
"id": "comp_123",
"title": "PrimaryButton",
"category": "buttons",
"code": "export default function PrimaryButton({ children, onClick }) {\n return (\n <button onClick={onClick}>\n {children}\n </button>\n );\n}",
"userId": "user_123",
"createdAt": "2024-12-01T10:00:00Z",
"updatedAt": "2024-12-15T08:30:00Z"
}
}Errors:
404- Component not found401- Unauthorized
Create or update a component.
Headers:
Authorization: Bearer YOUR_JWT_TOKEN
Content-Type: application/json
Request:
{
"title": "PrimaryButton",
"category": "buttons",
"code": "export default function PrimaryButton({ children }) {\n return <button>{children}</button>;\n}"
}Response (201 or 200):
{
"component": {
"id": "comp_123",
"title": "PrimaryButton",
"category": "buttons",
"code": "export default function PrimaryButton({ children }) { ... }",
"userId": "user_123",
"createdAt": "2024-12-01T10:00:00Z",
"updatedAt": "2024-12-15T08:30:00Z"
}
}Errors:
400- Invalid request body404- Category not found401- Unauthorized
Delete a component.
Headers:
Authorization: Bearer YOUR_JWT_TOKEN
Response (200):
{
"message": "Component deleted successfully"
}Errors:
404- Component not found401- Unauthorized
Get current user information.
Headers:
Authorization: Bearer YOUR_JWT_TOKEN
Response (200):
{
"user": {
"id": "user_123",
"email": "user@example.com",
"name": "John Doe",
"createdAt": "2024-11-01T10:00:00Z"
},
"stats": {
"totalComponents": 15,
"totalCategories": 4,
"lastActivity": "2024-12-20T14:30:00Z"
}
}All errors follow this format:
{
"error": {
"message": "Error description",
"code": "ERROR_CODE",
"status": 400
}
}| Status | Code | Description |
|---|---|---|
| 400 | BAD_REQUEST | Invalid request parameters |
| 401 | UNAUTHORIZED | Missing or invalid authentication |
| 403 | FORBIDDEN | Insufficient permissions |
| 404 | NOT_FOUND | Resource not found |
| 409 | CONFLICT | Resource already exists |
| 422 | VALIDATION_ERROR | Request validation failed |
| 500 | INTERNAL_ERROR | Server error |
- Rate limit: 100 requests per minute per user
- Headers returned:
X-RateLimit-Limit: Maximum requests allowedX-RateLimit-Remaining: Requests remainingX-RateLimit-Reset: Time when limit resets (Unix timestamp)
Example:
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1703088000
When rate limit is exceeded:
{
"error": {
"message": "Rate limit exceeded. Please try again later.",
"code": "RATE_LIMIT_EXCEEDED",
"status": 429,
"retryAfter": 60
}
}(Coming soon) Subscribe to events like:
- Component created
- Component updated
- Component deleted
- Category created
const fetch = require('node-fetch');
const BASE_URL = 'https://composter.onrender.com/api';
let token = null;
// Login
async function login(email, password) {
const response = await fetch(`${BASE_URL}/auth/sign-in/email`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email, password })
});
const data = await response.json();
token = data.token;
return data;
}
// Get categories
async function getCategories() {
const response = await fetch(`${BASE_URL}/categories`, {
headers: { 'Authorization': `Bearer ${token}` }
});
return response.json();
}
// Create component
async function createComponent(category, title, code) {
const response = await fetch(`${BASE_URL}/components`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ category, title, code })
});
return response.json();
}
// Usage
(async () => {
await login('user@example.com', 'password');
const categories = await getCategories();
console.log(categories);
})();If you're developing integrations or testing the API locally, run the API server and point clients (CLI/frontend) to the local base URL.
cd api
npm install
npm run dev
# Base URL when running locally:
# http://localhost:3000/apiWhen debugging MCP or CLI flows, ensure the API server is running and that COMPOSTER_API_URL / COMPOSTER_API_URL env variables used by the CLI and MCP point to the local API base URL.
import requests
BASE_URL = 'https://composter.onrender.com/api'
class ComposterAPI:
def __init__(self):
self.token = None
def login(self, email, password):
response = requests.post(
f'{BASE_URL}/auth/sign-in/email',
json={'email': email, 'password': password}
)
data = response.json()
self.token = data['token']
return data
def get_categories(self):
response = requests.get(
f'{BASE_URL}/categories',
headers={'Authorization': f'Bearer {self.token}'}
)
return response.json()
def create_component(self, category, title, code):
response = requests.post(
f'{BASE_URL}/components',
headers={'Authorization': f'Bearer {self.token}'},
json={'category': category, 'title': title, 'code': code}
)
return response.json()
# Usage
api = ComposterAPI()
api.login('user@example.com', 'password')
categories = api.get_categories()
print(categories)# Login
curl -X POST https://composter.onrender.com/api/auth/sign-in/email \
-H "Content-Type: application/json" \
-d '{"email":"user@example.com","password":"password"}'
# List categories
curl -H "Authorization: Bearer YOUR_TOKEN" \
https://composter.onrender.com/api/categories
# Create component
curl -X POST https://composter.onrender.com/api/components \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"category": "buttons",
"title": "PrimaryButton",
"code": "export default function PrimaryButton() { return <button>Click</button>; }"
}'Official SDKs planned for:
- JavaScript/TypeScript
- Python
- Go
- Rust