Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/Ishaq74/concordia/llms.txt

Use this file to discover all available pages before exploring further.

API Architecture

Concordia uses Astro API routes for server-side endpoints. All API routes are located in /src/pages/api/ and follow RESTful conventions.

Base URL Structure

All API endpoints are prefixed with /api/:
https://your-domain.com/api/{resource}

Endpoint Categories

  • Authentication: /api/auth/* - Better Auth endpoints (login, register, session)
  • Admin Blog: /api/admin/blog/* - Blog management (articles, authors, categories, comments, media)
  • Admin Services: /api/admin/services/* - Services management (services, categories, availability, bookings, media)
  • Admin Organizations: /api/admin/organizations/* - Organization and member management
  • Client Auth: /api/auth-client/* - Client-side auth helpers (verification, password reset)
  • Profile: /api/profile/* - User profile management

Request/Response Patterns

Request Format

All API endpoints accept JSON payloads:
{
  "action": "create",
  "field1": "value1",
  "field2": "value2"
}

Response Format

Successful responses return JSON with HTTP 200/201:
{
  "ok": true,
  "id": "xyz123",
  "data": { ... }
}
Error responses include descriptive error codes:
{
  "error": "not_found",
  "message": "Resource not found"
}

HTTP Status Codes

CodeMeaning
200Success
201Created
400Bad Request (invalid input)
401Unauthorized (not authenticated)
403Forbidden (insufficient permissions)
404Not Found
413Payload Too Large
415Unsupported Media Type
429Too Many Requests (rate limited)
500Internal Server Error

Authentication Requirements

Admin Endpoints

All /api/admin/* endpoints require:
  1. Active session (cookie or Bearer token)
  2. Admin role (checked via guardAdmin helper)
const guard = guardAdmin(locals);
if (guard) return guard; // Returns 403 if not admin

Public Endpoints

  • /api/auth/* - Open for authentication flows
  • /api/auth-client/* - Open for email verification and password reset

Session Management

Sessions are managed by Better Auth with:
  • Cookie-based sessions (default)
  • Bearer token support (for API clients)
  • Session duration: 7 days
  • Session refresh: Every 24 hours
  • Absolute timeout: 7 days

Rate Limiting

Concordia implements database-backed rate limiting through Better Auth.

Configuration

From /src/lib/auth/auth.ts:105-127:
rateLimit: {
  enabled: true,
  storage: "database",
  skipSuccessfulRequests: false,
  skipFailedRequests: false,
  windows: [
    {
      key: "global_ip",
      max: 100,
      window: 60 * 1000, // 1 minute
    },
    {
      key: "sign_in",
      max: 5,
      window: 15 * 60 * 1000, // 15 minutes
    },
    {
      key: "sign_up",
      max: 10,
      window: 60 * 60 * 1000, // 1 hour
    },
  ],
}

Rate Limits

Endpoint TypeMax RequestsWindow
Global (per IP)100 requests1 minute
Sign In5 attempts15 minutes
Sign Up10 attempts1 hour

Rate Limit Headers

When rate limited, responses include:
  • HTTP 429 Too Many Requests
  • Error message: "Too many login attempts" or similar

Error Handling

Common Error Codes

Error CodeDescription
invalid_bodyRequest body is not valid JSON
missing_actionRequired action field missing
missing_idRequired id field missing
not_foundResource does not exist
forbiddenUser lacks permission
unknown_actionInvalid action specified
internal_errorServer error occurred

Error Response Example

{
  "error": "missing_action",
  "message": "The 'action' field is required"
}

Security Headers

All API responses include security headers:
const securityHeaders = {
  'content-security-policy': "default-src 'none'; frame-ancestors 'none'; base-uri 'none';",
  'x-frame-options': 'DENY',
  'x-content-type-options': 'nosniff',
  'strict-transport-security': 'max-age=63072000; includeSubDomains; preload',
  'referrer-policy': 'no-referrer',
  'content-type': 'application/json',
};

Pagination

List endpoints support pagination via query parameters:
GET /api/admin/blog/articles?page=2&perPage=20

Parameters

page
integer
default:"1"
Page number (1-indexed)
perPage
integer
default:"20"
Items per page (max: 100)

Response Format

{
  "articles": [...],
  "total": 150,
  "page": 2,
  "perPage": 20,
  "totalPages": 8
}

Most list endpoints support filtering:
  • q - Text search (slug, title, email, etc.)
  • status - Filter by status (draft, published, etc.)
  • featured - Filter featured items (true/false)
  • category - Filter by category ID
  • organizationId - Filter by organization

Example

GET /api/admin/blog/articles?q=welcome&status=published&featured=true

Audit Logging

All admin actions are logged to the audit_log table:
await db.insert(auditLog).values({
  id: generateId(),
  action: "blog.article.create",
  userId,
  targetId: id,
  data: { slug, status },
  createdAt: new Date(),
});

Logged Actions

  • All CRUD operations (create, update, delete)
  • Authentication events (login, logout, signup)
  • Member management (invite, remove, role changes)
  • Content publication (publish, unpublish)

API Endpoints by Category

Authentication & Users

Content Management

  • Blog API - Articles, authors, categories, comments, media

Services & Bookings

Organizations


Next Steps

Authentication API

Login, register, and session management

Profile API

User profile CRUD operations

Blog API

Manage articles, authors, and categories

Services API

Service listings, bookings, and availability

Organizations API

Organization and member management

Users API

Admin user management and moderation

Build docs developers (and LLMs) love