Skip to main content

API Endpoints

SDD Classification: L3-Technical Authority: Engineering Team Review Cycle: Quarterly
This document provides a comprehensive reference for all API endpoints in Materi’s API Service, including request/response formats, authentication requirements, and usage examples.

Base URL

EnvironmentBase URL
Productionhttps://api.materi.dev/api/v1
Staginghttps://api.staging.materi.dev/api/v1
Developmenthttp://localhost:8080/api/v1

Document Endpoints

Create Document

Creates a new document in a workspace.
POST /api/v1/documents
Authentication: Required (JWT or API Key) Request Body:
{
  "title": "My Document",
  "content": "Initial content...",
  "workspace_id": "ws_abc123"
}
FieldTypeRequiredDescription
titlestringYesDocument title (1-255 chars)
contentstringNoInitial content (max 10MB)
workspace_idstringYesTarget workspace UUID
Response: 201 Created
{
  "success": true,
  "data": {
    "id": "doc_xyz789",
    "title": "My Document",
    "content": "Initial content...",
    "workspace_id": "ws_abc123",
    "owner_id": "user_abc123",
    "version": 1,
    "created_at": "2025-01-07T10:00:00Z",
    "updated_at": "2025-01-07T10:00:00Z"
  }
}
Errors:
CodeStatusDescription
VALIDATION_ERROR422Missing or invalid fields
FORBIDDEN403No write access to workspace
WORKSPACE_NOT_FOUND404Workspace doesn’t exist

Get Document

Retrieves a document by ID.
GET /api/v1/documents/{id}
Authentication: Required Path Parameters:
ParameterTypeDescription
idstringDocument UUID
Query Parameters:
ParameterTypeDefaultDescription
include_contentbooleantrueInclude full content
Response: 200 OK
{
  "success": true,
  "data": {
    "id": "doc_xyz789",
    "title": "My Document",
    "content": "Document content...",
    "workspace_id": "ws_abc123",
    "owner_id": "user_abc123",
    "version": 5,
    "created_at": "2025-01-07T10:00:00Z",
    "updated_at": "2025-01-07T14:30:00Z"
  }
}
Errors:
CodeStatusDescription
NOT_FOUND404Document doesn’t exist
FORBIDDEN403No read access

Update Document

Partially updates a document.
PATCH /api/v1/documents/{id}
Authentication: Required Request Body:
{
  "title": "Updated Title",
  "content": "Updated content...",
  "version": 5
}
FieldTypeRequiredDescription
titlestringNoNew title
contentstringNoNew content
versionintegerNoExpected version (optimistic lock)
Response: 200 OK
{
  "success": true,
  "data": {
    "id": "doc_xyz789",
    "title": "Updated Title",
    "content": "Updated content...",
    "version": 6,
    "updated_at": "2025-01-07T15:00:00Z"
  }
}
Errors:
CodeStatusDescription
CONFLICT409Version mismatch (concurrent edit)
FORBIDDEN403No write access
NOT_FOUND404Document doesn’t exist

Delete Document

Soft-deletes a document (recoverable for 30 days).
DELETE /api/v1/documents/{id}
Authentication: Required Response: 204 No Content Errors:
CodeStatusDescription
FORBIDDEN403Only owner can delete
NOT_FOUND404Document doesn’t exist

List Documents

Lists documents with pagination and filtering.
GET /api/v1/documents
Authentication: Required Query Parameters:
ParameterTypeDefaultDescription
workspace_idstring-Filter by workspace
pageinteger1Page number
limitinteger20Items per page (max 100)
sortstringupdated_atSort field
orderstringdescSort order (asc/desc)
owner_idstring-Filter by owner
created_afterdatetime-Filter by creation date
created_beforedatetime-Filter by creation date
Response: 200 OK
{
  "success": true,
  "data": [
    {
      "id": "doc_xyz789",
      "title": "My Document",
      "workspace_id": "ws_abc123",
      "owner_id": "user_abc123",
      "version": 5,
      "created_at": "2025-01-07T10:00:00Z",
      "updated_at": "2025-01-07T14:30:00Z"
    }
  ],
  "pagination": {
    "page": 1,
    "limit": 20,
    "total": 42,
    "total_pages": 3,
    "has_more": true
  }
}

Search Documents

Full-text search across documents.
GET /api/v1/documents/search
Authentication: Required Query Parameters:
ParameterTypeRequiredDescription
qstringYesSearch query
workspace_idstringNoFilter by workspace
limitintegerNoMax results (default 20, max 50)
Response: 200 OK
{
  "success": true,
  "data": [
    {
      "id": "doc_xyz789",
      "title": "My Document",
      "snippet": "...matching <mark>content</mark> here...",
      "relevance": 0.95,
      "created_at": "2025-01-07T10:00:00Z"
    }
  ],
  "meta": {
    "query": "content",
    "total_results": 5,
    "search_time_ms": 45
  }
}

Workspace Endpoints

Create Workspace

POST /api/v1/workspaces
Authentication: Required Request Body:
{
  "name": "My Team",
  "slug": "my-team"
}
Response: 201 Created
{
  "success": true,
  "data": {
    "id": "ws_abc123",
    "name": "My Team",
    "slug": "my-team",
    "owner_id": "user_abc123",
    "settings": {
      "default_permission": "read",
      "allow_public_links": false,
      "ai_enabled": true
    },
    "created_at": "2025-01-07T10:00:00Z"
  }
}

Get Workspace

GET /api/v1/workspaces/{id}
Response: 200 OK
{
  "success": true,
  "data": {
    "id": "ws_abc123",
    "name": "My Team",
    "slug": "my-team",
    "owner_id": "user_abc123",
    "member_count": 5,
    "document_count": 42,
    "settings": {
      "default_permission": "read",
      "allow_public_links": false,
      "ai_enabled": true
    },
    "created_at": "2025-01-07T10:00:00Z"
  }
}

List Workspace Members

GET /api/v1/workspaces/{id}/members
Response: 200 OK
{
  "success": true,
  "data": [
    {
      "user_id": "user_abc123",
      "email": "[email protected]",
      "name": "John Doe",
      "role": "owner",
      "joined_at": "2025-01-07T10:00:00Z"
    },
    {
      "user_id": "user_def456",
      "email": "[email protected]",
      "name": "Jane Smith",
      "role": "member",
      "joined_at": "2025-01-08T10:00:00Z"
    }
  ]
}

Invite Member

POST /api/v1/workspaces/{id}/members
Authentication: Required (Admin or Owner) Request Body:
{
  "email": "[email protected]",
  "role": "member"
}
Response: 201 Created
{
  "success": true,
  "data": {
    "invitation_id": "inv_abc123",
    "email": "[email protected]",
    "role": "member",
    "expires_at": "2025-01-14T10:00:00Z"
  }
}

AI Endpoints

Generate Content

Generates content using AI with streaming response.
POST /api/v1/ai/generate
Authentication: Required Headers:
HeaderRequiredDescription
Idempotency-KeyRecommendedPrevent duplicate requests
AcceptNotext/event-stream for streaming
Request Body:
{
  "prompt": "Write an introduction about...",
  "max_tokens": 500,
  "document_id": "doc_xyz789",
  "model": "claude-3-sonnet"
}
FieldTypeRequiredDescription
promptstringYesGeneration prompt
max_tokensintegerNoMax tokens (default 500)
document_idstringNoContext document
modelstringNoAI model to use
temperaturefloatNoCreativity (0-1)
Streaming Response: 200 OK (text/event-stream)
event: content
data: {"text": "Here is ", "done": false}

event: content
data: {"text": "the generated ", "done": false}

event: content
data: {"text": "content.", "done": false}

event: done
data: {"tokens_used": 45, "model": "claude-3-sonnet", "finish_reason": "stop"}
Batch Response: 200 OK (application/json)
{
  "success": true,
  "data": {
    "content": "Here is the generated content.",
    "tokens_used": 45,
    "model": "claude-3-sonnet",
    "finish_reason": "stop"
  }
}
Errors:
CodeStatusDescription
RATE_LIMITED429AI quota exceeded
AI_SERVICE_UNAVAILABLE503AI provider down
CONTENT_POLICY_VIOLATION400Content flagged

Get AI Usage

GET /api/v1/ai/usage
Authentication: Required Query Parameters:
ParameterTypeDescription
periodstringday, week, month
workspace_idstringFilter by workspace
Response: 200 OK
{
  "success": true,
  "data": {
    "period": "month",
    "requests": 150,
    "tokens_used": 75000,
    "cost_usd": 1.50,
    "limit": {
      "requests": 1000,
      "tokens": 500000
    },
    "reset_at": "2025-02-01T00:00:00Z"
  }
}

File Endpoints

Upload File

Get a pre-signed URL for file upload.
POST /api/v1/files/upload
Authentication: Required Request Body:
{
  "filename": "image.png",
  "content_type": "image/png",
  "size": 1048576,
  "document_id": "doc_xyz789"
}
Response: 200 OK
{
  "success": true,
  "data": {
    "upload_url": "https://storage.materi.dev/upload?...",
    "file_id": "file_abc123",
    "expires_at": "2025-01-07T11:00:00Z"
  }
}

Get File

GET /api/v1/files/{id}
Response: 200 OK
{
  "success": true,
  "data": {
    "id": "file_abc123",
    "filename": "image.png",
    "content_type": "image/png",
    "size": 1048576,
    "url": "https://cdn.materi.dev/files/...",
    "thumbnail_url": "https://cdn.materi.dev/thumbs/...",
    "created_at": "2025-01-07T10:00:00Z"
  }
}

Authentication Endpoints

Refresh Token

POST /api/v1/auth/refresh
Authentication: Refresh token in HTTP-only cookie Response: 200 OK
{
  "success": true,
  "data": {
    "access_token": "eyJhbGciOiJSUzI1NiIs...",
    "expires_in": 900
  }
}

Logout

POST /api/v1/auth/logout
Authentication: Required Response: 204 No Content

Health Endpoints

Health Check

GET /health
Authentication: None Response: 200 OK
{
  "status": "healthy",
  "version": "1.2.3",
  "uptime": 86400
}

Readiness Check

GET /ready
Authentication: None Response: 200 OK
{
  "status": "ready",
  "checks": {
    "database": "ok",
    "redis": "ok",
    "shield": "ok"
  }
}
Response: 503 Service Unavailable (if dependencies unhealthy)
{
  "status": "not_ready",
  "checks": {
    "database": "ok",
    "redis": "error: connection refused",
    "shield": "ok"
  }
}

Metrics

GET /metrics
Authentication: None (internal network only) Response: 200 OK (text/plain, Prometheus format)
# HELP materi_http_requests_total Total HTTP requests
# TYPE materi_http_requests_total counter
materi_http_requests_total{method="GET",endpoint="/api/v1/documents",status="200"} 12345
materi_http_requests_total{method="POST",endpoint="/api/v1/documents",status="201"} 678

# HELP materi_http_duration_seconds HTTP request duration
# TYPE materi_http_duration_seconds histogram
materi_http_duration_seconds_bucket{method="GET",endpoint="/api/v1/documents",le="0.1"} 11000
materi_http_duration_seconds_bucket{method="GET",endpoint="/api/v1/documents",le="0.25"} 12000

Error Response Format

All errors follow a consistent format:
{
  "success": false,
  "error": {
    "code": "ERROR_CODE",
    "message": "Human-readable description",
    "details": {
      "field": "Additional context"
    }
  },
  "meta": {
    "request_id": "req_xyz789"
  }
}

Common Error Codes

CodeStatusDescription
UNAUTHORIZED401Missing or invalid auth
FORBIDDEN403Insufficient permissions
NOT_FOUND404Resource not found
VALIDATION_ERROR422Invalid request body
CONFLICT409Resource conflict
RATE_LIMITED429Too many requests
INTERNAL_ERROR500Server error
SERVICE_UNAVAILABLE503Dependency unavailable


Document Status: Complete Version: 2.0