Skip to main content

REST API Reference

Complete reference for Stack9's auto-generated REST API endpoints. Every entity you define automatically gets a full CRUD REST API with filtering, pagination, sorting, and relationship loading.

Base URL

http://localhost:3000/api

Production:

https://your-app.stack9.cloud/api

Authentication

All API requests require authentication via Bearer token:

Authorization: Bearer YOUR_ACCESS_TOKEN

Get Access Token

POST /auth/login
Content-Type: application/json

{
"email": "user@example.com",
"password": "your_password"
}

Response:

{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"user": {
"id": 1,
"email": "user@example.com",
"name": "John Doe"
}
}

Entity Endpoints

For each entity (e.g., customer), Stack9 auto-generates these endpoints:

MethodEndpointDescription
GET/api/{entity}List all records
GET/api/{entity}/:idGet single record
POST/api/{entity}Create new record
PUT/api/{entity}/:idUpdate record
DELETE/api/{entity}/:idDelete record

Examples

List All Records

GET /api/customer
Authorization: Bearer YOUR_TOKEN

Response:

{
"data": [
{
"id": 1,
"email": "john@example.com",
"first_name": "John",
"last_name": "Doe",
"status": "active",
"_created_at": "2025-01-10T10:30:00Z",
"_updated_at": "2025-01-10T10:30:00Z"
},
{
"id": 2,
"email": "jane@example.com",
"first_name": "Jane",
"last_name": "Smith",
"status": "trial",
"_created_at": "2025-01-09T15:20:00Z",
"_updated_at": "2025-01-09T15:20:00Z"
}
],
"pagination": {
"page": 1,
"per_page": 20,
"total": 2,
"total_pages": 1
}
}

Get Single Record

GET /api/customer/1
Authorization: Bearer YOUR_TOKEN

Response:

{
"id": 1,
"email": "john@example.com",
"first_name": "John",
"last_name": "Doe",
"status": "active",
"company": "Acme Inc",
"phone": "+1234567890",
"_created_at": "2025-01-10T10:30:00Z",
"_updated_at": "2025-01-10T10:30:00Z",
"_created_by": 5,
"_updated_by": 5
}

Create Record

POST /api/customer
Authorization: Bearer YOUR_TOKEN
Content-Type: application/json

{
"email": "newcustomer@example.com",
"first_name": "Alice",
"last_name": "Johnson",
"status": "trial",
"company": "StartupCo"
}

Response:

{
"id": 3,
"email": "newcustomer@example.com",
"first_name": "Alice",
"last_name": "Johnson",
"status": "trial",
"company": "StartupCo",
"_created_at": "2025-01-11T08:15:00Z",
"_updated_at": "2025-01-11T08:15:00Z",
"_created_by": 5,
"_updated_by": 5
}

Update Record

PUT /api/customer/3
Authorization: Bearer YOUR_TOKEN
Content-Type: application/json

{
"status": "active",
"phone": "+1987654321"
}

Response:

{
"id": 3,
"email": "newcustomer@example.com",
"first_name": "Alice",
"last_name": "Johnson",
"status": "active",
"company": "StartupCo",
"phone": "+1987654321",
"_created_at": "2025-01-11T08:15:00Z",
"_updated_at": "2025-01-11T09:22:00Z",
"_created_by": 5,
"_updated_by": 5
}

Delete Record

DELETE /api/customer/3
Authorization: Bearer YOUR_TOKEN

Response:

{
"success": true,
"message": "Record deleted successfully"
}

Query Parameters

Filtering

Filter records using query parameters:

GET /api/customer?status=active
GET /api/customer?status=active&company=Acme Inc

Operators:

OperatorSyntaxExample
Equalsfield=valuestatus=active
Not equalsfield__ne=valuestatus__ne=inactive
Greater thanfield__gt=valueprice__gt=100
Less thanfield__lt=valueprice__lt=500
Greater or equalfield__gte=valueage__gte=18
Less or equalfield__lte=valueage__lte=65
Like (contains)field__like=valuename__like=John
In arrayfield__in=val1,val2status__in=active,trial
Not in arrayfield__nin=val1,val2status__nin=cancelled
Is nullfield__null=truedeleted_at__null=true
Is not nullfield__null=falseemail__null=false

Examples:

# Customers with active status
GET /api/customer?status=active

# Orders with total greater than $100
GET /api/order?total__gt=100

# Products with price between $50 and $200
GET /api/product?price__gte=50&price__lte=200

# Customers whose name contains "John"
GET /api/customer?first_name__like=John

# Orders with status pending or processing
GET /api/order?status__in=pending,processing

# Products not deleted (deleted_at is null)
GET /api/product?deleted_at__null=true

Pagination

Control pagination with page and per_page parameters:

GET /api/customer?page=1&per_page=20

Parameters:

ParameterDefaultMaxDescription
page1-Page number (starts at 1)
per_page20100Records per page

Response includes pagination metadata:

{
"data": [...],
"pagination": {
"page": 2,
"per_page": 20,
"total": 150,
"total_pages": 8
}
}

Sorting

Sort results using sort parameter:

# Sort by single field (ascending)
GET /api/customer?sort=first_name

# Sort descending (prefix with -)
GET /api/customer?sort=-created_at

# Sort by multiple fields
GET /api/customer?sort=status,-created_at

Examples:

# Newest customers first
GET /api/customer?sort=-_created_at

# Active customers, alphabetically
GET /api/customer?status=active&sort=first_name

# Orders by total (highest first), then by date
GET /api/order?sort=-total,-created_at

Field Selection

Select specific fields using fields parameter:

# Only return id, email, and status
GET /api/customer?fields=id,email,status

Response:

{
"data": [
{
"id": 1,
"email": "john@example.com",
"status": "active"
},
{
"id": 2,
"email": "jane@example.com",
"status": "trial"
}
],
"pagination": {...}
}

Including Relationships

Load related entities using include parameter:

# Load customer's orders
GET /api/customer/1?include=orders

# Load multiple relationships
GET /api/order/1?include=customer,order_items

# Nested relationships
GET /api/order/1?include=order_items.product

Response with relationships:

{
"id": 1,
"order_number": "ORD-20250110-0001",
"total": 150.00,
"customer": {
"id": 5,
"email": "customer@example.com",
"first_name": "John",
"last_name": "Doe"
},
"order_items": [
{
"id": 1,
"quantity": 2,
"unit_price": 50.00,
"product": {
"id": 10,
"name": "Widget",
"sku": "WDG-001"
}
},
{
"id": 2,
"quantity": 1,
"unit_price": 50.00,
"product": {
"id": 11,
"name": "Gadget",
"sku": "GDG-002"
}
}
]
}

Full-text search using search parameter:

# Search customers by name or email
GET /api/customer?search=john

# Search with filters
GET /api/customer?search=john&status=active

The search looks in text fields defined in your entity configuration.

Complex Queries

Combine multiple query parameters:

# Active customers named John, newest first, with orders
GET /api/customer?status=active&first_name__like=John&sort=-_created_at&include=orders

# Orders over $100, pending or processing, with items and customer
GET /api/order?total__gt=100&status__in=pending,processing&include=order_items,customer

# Products in specific categories, in stock, sorted by price
GET /api/product?category_id__in=5,8,12&stock__gt=0&sort=price

Bulk Operations

Bulk Create

POST /api/customer/bulk
Authorization: Bearer YOUR_TOKEN
Content-Type: application/json

{
"records": [
{
"email": "customer1@example.com",
"first_name": "Customer",
"last_name": "One"
},
{
"email": "customer2@example.com",
"first_name": "Customer",
"last_name": "Two"
}
]
}

Response:

{
"success": true,
"created": 2,
"ids": [10, 11]
}

Bulk Update

PUT /api/customer/bulk
Authorization: Bearer YOUR_TOKEN
Content-Type: application/json

{
"filter": {
"status": "trial"
},
"update": {
"onboarding_email_sent": true
}
}

Response:

{
"success": true,
"updated": 25
}

Bulk Delete

DELETE /api/customer/bulk
Authorization: Bearer YOUR_TOKEN
Content-Type: application/json

{
"ids": [10, 11, 12]
}

Response:

{
"success": true,
"deleted": 3
}

Error Responses

400 Bad Request

Invalid request parameters or validation errors:

{
"error": "Validation Error",
"message": "Request validation failed",
"errors": [
{
"field": "email",
"message": "Email is required"
},
{
"field": "status",
"message": "Invalid status value"
}
]
}

401 Unauthorized

Missing or invalid authentication:

{
"error": "Unauthorized",
"message": "Authentication required"
}

403 Forbidden

User doesn't have permission:

{
"error": "Forbidden",
"message": "You don't have permission to access this resource"
}

404 Not Found

Resource doesn't exist:

{
"error": "Not Found",
"message": "Customer with id 999 not found"
}

422 Unprocessable Entity

Entity hook validation failed:

{
"error": "Validation Error",
"message": "Entity validation failed",
"errors": [
"Insufficient stock for Product ABC",
"Invalid status transition from pending to delivered"
]
}

500 Internal Server Error

Server error:

{
"error": "Internal Server Error",
"message": "An unexpected error occurred",
"request_id": "req_abc123"
}

Rate Limiting

API requests are rate limited:

LimitWindowHeaders
1000 requestsper hourX-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset

Response headers:

X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 847
X-RateLimit-Reset: 1610123400

Rate limit exceeded (429):

{
"error": "Rate Limit Exceeded",
"message": "Too many requests. Please try again in 15 minutes.",
"retry_after": 900
}

Webhooks

Register webhooks to receive real-time notifications:

POST /api/webhooks
Authorization: Bearer YOUR_TOKEN
Content-Type: application/json

{
"url": "https://your-app.com/webhook",
"events": ["customer.created", "customer.updated", "order.created"],
"secret": "your_webhook_secret"
}

Webhook payload:

{
"event": "customer.created",
"entity": "customer",
"data": {
"id": 15,
"email": "new@example.com",
"first_name": "New",
"last_name": "Customer",
"_created_at": "2025-01-11T10:30:00Z"
},
"timestamp": "2025-01-11T10:30:01Z",
"signature": "sha256=abc123..."
}

Verify Webhook Signature

const crypto = require('crypto');

function verifyWebhookSignature(payload, signature, secret) {
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(JSON.stringify(payload))
.digest('hex');

return `sha256=${expectedSignature}` === signature;
}

Code Examples

JavaScript/TypeScript

// Using fetch
const response = await fetch('https://your-app.stack9.cloud/api/customer', {
method: 'GET',
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json',
},
});

const data = await response.json();

// Create customer
const newCustomer = await fetch('https://your-app.stack9.cloud/api/customer', {
method: 'POST',
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
email: 'new@example.com',
first_name: 'New',
last_name': 'Customer',
}),
});

Python

import requests

# Get customers
response = requests.get(
'https://your-app.stack9.cloud/api/customer',
headers={
'Authorization': f'Bearer {access_token}',
'Content-Type': 'application/json',
},
params={
'status': 'active',
'page': 1,
'per_page': 20,
}
)

customers = response.json()

# Create customer
response = requests.post(
'https://your-app.stack9.cloud/api/customer',
headers={
'Authorization': f'Bearer {access_token}',
'Content-Type': 'application/json',
},
json={
'email': 'new@example.com',
'first_name': 'New',
'last_name': 'Customer',
}
)

new_customer = response.json()

cURL

# Get customers
curl -X GET 'https://your-app.stack9.cloud/api/customer?status=active' \
-H 'Authorization: Bearer YOUR_TOKEN'

# Create customer
curl -X POST 'https://your-app.stack9.cloud/api/customer' \
-H 'Authorization: Bearer YOUR_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"email": "new@example.com",
"first_name": "New",
"last_name": "Customer"
}'

# Update customer
curl -X PUT 'https://your-app.stack9.cloud/api/customer/1' \
-H 'Authorization: Bearer YOUR_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"status": "active"
}'

# Delete customer
curl -X DELETE 'https://your-app.stack9.cloud/api/customer/1' \
-H 'Authorization: Bearer YOUR_TOKEN'

Best Practices

  1. Use field selection - Only request fields you need
  2. Paginate large datasets - Don't fetch all records at once
  3. Cache responses - Reduce API calls with client-side caching
  4. Handle errors gracefully - Implement retry logic for transient failures
  5. Respect rate limits - Implement backoff strategies
  6. Use bulk operations - More efficient for multiple records
  7. Include relationships wisely - Only load what you need
  8. Validate on client - Reduce validation errors
  9. Use webhooks - Get real-time updates instead of polling
  10. Monitor usage - Track API calls and performance

Next Steps

  • Query Syntax - Advanced query patterns
  • Entity Configuration - Entity field types and options
  • SDK Reference - TypeScript SDK for action types and hooks