REST API Documentation
Total CMS provides a RESTful API for accessing content and schemas. This documentation covers all available endpoints with examples and response formats.
API Overview
Section titled “API Overview”- Base URL: Your site’s root URL (e.g.,
https://yoursite.com) - Content Type:
application/json - Authentication: API keys (Pro edition) or session-based
Authentication
Section titled “Authentication”Total CMS supports two authentication methods for API access: API Keys (recommended for external applications, Pro edition required) and Session Authentication (for same-origin admin panel requests).
📖 For comprehensive API key documentation, see API Keys Guide
API Key Authentication (Pro Edition)
Section titled “API Key Authentication (Pro Edition)”API keys provide secure, token-based authentication ideal for headless CMS implementations, mobile apps, and third-party integrations.
Using the X-API-Key header (recommended):
curl -H "X-API-Key: tcms_1234567890abcdef1234567890abcdef" \ -H "Content-Type: application/json" \ https://yoursite.com/collections/blogUsing query parameter:
curl "https://yoursite.com/collections/blog?api_key=tcms_1234567890abcdef1234567890abcdef"Key Features:
- Scope-based permissions - Control HTTP methods (GET, POST, PUT, DELETE, PATCH)
- Path restrictions - Limit access to specific collections or endpoints
- Usage tracking - Monitor last used timestamps
- Easy revocation - Delete keys to immediately revoke access
Creating API Keys:
Navigate to Utilities → API Keys in the admin interface, or visit /admin/utils/api-keys.
For detailed information on scopes, permissions, and best practices, see the API Keys documentation.
Session Authentication
Section titled “Session Authentication”For admin panel and same-origin requests using cookies:
// Include CSRF token for session-based requestsfetch('/collections/blog', { headers: { 'X-CSRF-Token': document.querySelector('meta[name="csrf-token"]').content, 'Content-Type': 'application/json' }});When to use session authentication:
- Admin panel JavaScript
- Same-origin web applications
- Browser-based tools running on the same domain
When to use API keys:
- Mobile applications
- Third-party integrations
- Headless CMS implementations
- Automated scripts and workflows
Collections API
Section titled “Collections API”Get All Collections
Section titled “Get All Collections”GET /collectionsResponse:
{ "collections": [ { "name": "blog", "title": "Blog Posts", "count": 25, "schema": "/schemas/blog" }, { "name": "products", "title": "Products", "count": 150, "schema": "/schemas/products" } ]}Get Collection Objects
Section titled “Get Collection Objects”GET /collections/{collection}Query Parameters:
limit- Number of results (default: 50, max: 100)offset- Starting position (default: 0)sort- Sort field (default: created)order- Sort direction:ascordesc(default: desc)filter- Filter by field valuessearch- Full-text search
Examples:
# Get all blog postscurl https://yoursite.com/collections/blog
# Get published posts onlycurl "https://yoursite.com/collections/blog?filter[status]=published"
# Get latest 10 postscurl "https://yoursite.com/collections/blog?limit=10&sort=date&order=desc"
# Search postscurl "https://yoursite.com/collections/blog?search=tutorial"
# Paginationcurl "https://yoursite.com/collections/blog?limit=20&offset=40"Response:
{ "collection": "blog", "total": 25, "count": 10, "limit": 10, "offset": 0, "objects": [ { "id": "my-first-post", "title": "My First Post", "content": "Post content here...", "author": "john-doe", "status": "published", "date": "2024-01-15", "created": "2024-01-15T09:00:00Z", "modified": "2024-01-16T10:30:00Z" } ]}Get Single Object
Section titled “Get Single Object”GET /collections/{collection}/{id}Example:
curl https://yoursite.com/collections/blog/my-first-postResponse:
{ "id": "my-first-post", "title": "My First Post", "content": "Post content here...", "author": "john-doe", "status": "published", "date": "2024-01-15", "tags": ["tutorial", "beginner"], "image": { "url": "/media/images/post-image.jpg", "alt": "Post featured image", "width": 1200, "height": 630 }, "created": "2024-01-15T09:00:00Z", "modified": "2024-01-16T10:30:00Z"}Create Object
Section titled “Create Object”POST /collections/{collection}Request Body:
{ "title": "New Blog Post", "content": "This is the content of my new blog post.", "author": "jane-doe", "status": "draft", "tags": ["announcement", "news"]}Response (201 Created):
{ "id": "new-blog-post", "title": "New Blog Post", "content": "This is the content of my new blog post.", "author": "jane-doe", "status": "draft", "tags": ["announcement", "news"], "created": "2024-01-20T14:30:00Z", "modified": "2024-01-20T14:30:00Z"}Update Object
Section titled “Update Object”PUT /collections/{collection}/{id}Request Body:
{ "title": "Updated Blog Post Title", "status": "published"}Response (200 OK):
{ "id": "new-blog-post", "title": "Updated Blog Post Title", "content": "This is the content of my new blog post.", "author": "jane-doe", "status": "published", "tags": ["announcement", "news"], "created": "2024-01-20T14:30:00Z", "modified": "2024-01-20T15:45:00Z"}Partial Update
Section titled “Partial Update”PATCH /collections/{collection}/{id}Updates only specified fields:
{ "status": "published"}Delete Object
Section titled “Delete Object”DELETE /collections/{collection}/{id}Response (204 No Content)
Schemas API
Section titled “Schemas API”Get All Schemas
Section titled “Get All Schemas”GET /schemasResponse:
{ "schemas": [ { "name": "blog", "title": "Blog Posts", "description": "Blog post collection", "url": "/schemas/blog" } ]}Get Schema Definition
Section titled “Get Schema Definition”GET /schemas/{collection}Response:
{ "name": "blog", "title": "Blog Posts", "description": "Blog post collection", "properties": { "title": { "type": "string", "required": true, "maxLength": 255 }, "content": { "type": "string", "format": "html" }, "author": { "type": "string", "reference": "users" }, "status": { "type": "string", "enum": ["draft", "published", "archived"], "default": "draft" }, "tags": { "type": "array", "items": { "type": "string" } }, "date": { "type": "string", "format": "date" } }}File Downloads & Streaming
Section titled “File Downloads & Streaming”Download File (Forces Download)
Section titled “Download File (Forces Download)”Download a file from a specific collection with Content-Disposition: attachment.
GET /download/{collection}/{id}/{property}POST /download/{collection}/{id}/{property}Path Parameters:
collection- Collection name (e.g., ‘files’, ‘documents’)id- Object IDproperty- Property name containing the file
Query Parameters:
pwd- Encrypted password for protected files
Examples:
# Basic file downloadcurl -O https://yoursite.com/download/files/manual/file
# Download with custom collection/propertycurl -O https://yoursite.com/download/documents/guide/pdf
# Password-protected file (password must be encrypted)curl -O "https://yoursite.com/download/private/secret/file?pwd=ENCRYPTED_PASSWORD"Download Depot File
Section titled “Download Depot File”Download a specific file from a depot (multi-file) property.
GET /download/{collection}/{id}/{property}/{filename}POST /download/{collection}/{id}/{property}/{filename}Path Parameters:
collection- Collection nameid- Object IDproperty- Depot property namefilename- Specific file to download
Query Parameters:
path- Subfolder path within depotpwd- Encrypted password for protected files
Examples:
# Download specific depot filecurl -O https://yoursite.com/download/depot/assets/files/document.pdf
# Download from subfoldercurl -O "https://yoursite.com/download/depot/assets/files/image.jpg?path=photos/vacation"
# Password-protected depot filecurl -O "https://yoursite.com/download/depot/private/files/secret.zip?pwd=ENCRYPTED_PASSWORD"Stream File (Plays in Browser)
Section titled “Stream File (Plays in Browser)”Stream a file with Content-Disposition: inline and HTTP range request support. Ideal for video/audio files.
GET /stream/{collection}/{id}/{property}Path Parameters:
collection- Collection nameid- Object IDproperty- Property name containing the file
Query Parameters:
pwd- Encrypted password for protected files
Headers:
Range- HTTP range request (e.g., “bytes=0-1023”)
Response Headers:
Accept-Ranges: bytesContent-Range- For partial content responses (206)Content-Length- File or range size
Examples:
# Stream video filecurl https://yoursite.com/stream/videos/movie/video
# Range request for video seekingcurl -H "Range: bytes=0-1023" https://yoursite.com/stream/videos/movie/video
# Password-protected streamingcurl "https://yoursite.com/stream/private/secret/video?pwd=ENCRYPTED_PASSWORD"Stream Depot File
Section titled “Stream Depot File”Stream a specific file from a depot property.
GET /stream/{collection}/{id}/{property}/{filename}Path Parameters:
collection- Collection nameid- Object IDproperty- Depot property namefilename- Specific file to stream
Query Parameters:
path- Subfolder path within depotpwd- Encrypted password for protected files
Examples:
# Stream depot videocurl https://yoursite.com/stream/media/playlist/videos/movie.mp4
# Stream with subfolder pathcurl "https://yoursite.com/stream/media/playlist/videos/song.mp3?path=albums/rock"HTML5 Media Integration
Section titled “HTML5 Media Integration”Video Streaming:
<video controls> <source src="/stream/videos/movie/video" type="video/mp4"></video>Audio Streaming:
<audio controls> <source src="/stream/audio/song/file" type="audio/mpeg"></audio>Download vs Stream Comparison
Section titled “Download vs Stream Comparison”| Feature | Download | Stream |
|---|---|---|
| Content-Disposition | attachment | inline |
| Browser Behavior | Forces download dialog | Plays/displays in browser |
| Range Requests | No | Yes (HTTP 206) |
| Video/Audio Support | Basic | Full seeking/scrubbing |
| Safari Compatibility | Standard | Enhanced for media |
| Use Cases | Documents, archives | Video, audio, PDFs |
Password Protection
Section titled “Password Protection”Both download and stream endpoints support password protection:
- Frontend: Use Twig functions that auto-encrypt passwords
- API: Passwords must be encrypted using the Cipher class
- URLs: Encrypted passwords are URL-encoded in query parameters
Twig Examples:
{# Auto-encrypts plain password #}{{ cms.download('id', {pwd: 'plaintext'}) }}{{ cms.stream('id', {pwd: 'plaintext'}) }}
{# Already encrypted passwords work too #}{{ cms.download('id', {pwd: encrypted_pwd}) }}Image Processing (ImageWorks)
Section titled “Image Processing (ImageWorks)”Basic Image Manipulation
Section titled “Basic Image Manipulation”GET /imageworks/{collection}/{id}/{property}.{format}Parameters:
w- Width in pixelsh- Height in pixelsfit- Resize mode:crop,contain,cover,fill,inside,outsideformat- Output format:jpg,png,webp,avifquality- JPEG quality (1-100)blur- Blur amount (1-100)brightness- Brightness (-100 to 100)contrast- Contrast (-100 to 100)gamma- Gamma correction (0.1 to 3.0)sharpen- Sharpen amount (1-100)grayscale- Convert to grayscale (true/false)sepia- Apply sepia effect (true/false)
Examples:
# Resize to 800x600curl "https://yoursite.com/imageworks/gallery/hero/image.jpg?w=800&h=600"
# Crop to square thumbnailcurl "https://yoursite.com/imageworks/products/laptop/image.jpg?w=300&h=300&fit=crop"
# Convert to WebP with qualitycurl "https://yoursite.com/imageworks/blog/featured/image.webp?quality=80"
# Apply filterscurl "https://yoursite.com/imageworks/portfolio/photo/image.jpg?grayscale=true&contrast=20"
# Responsive image with blurcurl "https://yoursite.com/imageworks/hero/banner/image.jpg?w=1200&blur=5"Gallery Images
Section titled “Gallery Images”GET /imageworks/{collection}/{id}/{property}/{name}.{format}Fetch a specific image from a gallery property.
Dynamic Gallery Images
Section titled “Dynamic Gallery Images”GET /imageworks/{collection}/{id}/{property}/{action}Actions:
first- Get the first imagelast- Get the last imagerandom- Get a random imagefeatured- Get the featured image
Error Handling
Section titled “Error Handling”Error Response Format
Section titled “Error Response Format”{ "error": { "code": 400, "message": "Validation failed", "details": { "title": ["Title is required"], "email": ["Invalid email format"] } }}HTTP Status Codes
Section titled “HTTP Status Codes”200 OK- Successful request201 Created- Resource created successfully204 No Content- Successful request with no response body400 Bad Request- Invalid request data401 Unauthorized- Authentication required403 Forbidden- Insufficient permissions404 Not Found- Resource not found422 Unprocessable Entity- Validation errors429 Too Many Requests- Rate limit exceeded500 Internal Server Error- Server error
Rate Limiting
Section titled “Rate Limiting”Headers:
X-RateLimit-Limit- Request limit per windowX-RateLimit-Remaining- Remaining requestsX-RateLimit-Reset- Time when limit resets
Example Response Headers:
X-RateLimit-Limit: 60X-RateLimit-Remaining: 45X-RateLimit-Reset: 1705751400Pagination
Section titled “Pagination”For endpoints that return multiple items:
Headers:
X-Total-Count- Total number of itemsLink- Pagination links (next, prev, first, last)
Example:
X-Total-Count: 150Link: </collections/blog?offset=20&limit=20>; rel="next", </collections/blog?offset=0&limit=20>; rel="first", </collections/blog?offset=140&limit=20>; rel="last"CORS Support
Section titled “CORS Support”The API supports Cross-Origin Resource Sharing (CORS) for browser-based requests:
// Example browser requestfetch('https://yoursite.com/collections/blog', { method: 'GET', headers: { 'X-API-Key': 'tcms_your_api_key_here', 'Content-Type': 'application/json' }});