Introduction

The VoidForge REST API provides full CRUD (Create, Read, Update, Delete) operations for posts, pages, media, users, and taxonomies. All requests and responses use JSON format.

Features

  • Full CRUD operations for all content types
  • API key authentication with granular permissions
  • Pagination and filtering support
  • JSON request and response format
  • Consistent error handling
Version: This documentation covers API v1, included in VoidForge CMS 0.2.1+

Authentication

All API requests require authentication using an API key and secret. Include these in your request headers:

X-API-Key: your_api_key_here
X-API-Secret: your_api_secret_here
Content-Type: application/json

Example Request

curl -X GET "https://yoursite.com/api/v1/posts" \
  -H "X-API-Key: vf_abc123..." \
  -H "X-API-Secret: vfs_xyz789..."
Security: Never expose your API secret in client-side code. Always make API calls from a server.

API Key Management

Create and manage API keys from the admin panel at Admin → Tools → API Keys.

Creating an API Key

  1. Go to Admin → Tools → API Keys
  2. Click "Generate New Key"
  3. Enter a descriptive name (e.g., "Mobile App", "External Service")
  4. Select permissions (Read, Write, Delete)
  5. Optionally set an expiration date
  6. Copy and securely store both the Key and Secret

Permissions

PermissionAllows
readGET requests to retrieve content
writePOST and PUT requests to create/update content
deleteDELETE requests to remove content
Important: The API Secret is only shown once when created. Store it securely!

Base URL

All API endpoints are relative to the base URL:

https://yoursite.com/api/v1/

For example, to get all posts:

GET https://yoursite.com/api/v1/posts

Posts

Manage blog posts and custom post type content.

GET /posts

Retrieve a list of posts with optional filtering and pagination.

Query Parameters

ParameterTypeDescription
per_pageintegerItems per page (default: 10, max: 100)
pageintegerPage number (default: 1)
statusstringFilter by status: published, draft, trash
post_typestringFilter by post type (default: post)
orderbystringSort field: date, title, id
orderstringSort direction: asc, desc

Example Request

curl "https://yoursite.com/api/v1/posts?per_page=5&status=published" \
  -H "X-API-Key: your_key" \
  -H "X-API-Secret: your_secret"

Response

{
  "success": true,
  "data": [
    {
      "id": 1,
      "title": "Hello World",
      "slug": "hello-world",
      "content": "<p>Welcome to VoidForge!</p>",
      "excerpt": "Welcome to VoidForge!",
      "status": "published",
      "post_type": "post",
      "author_id": 1,
      "created_at": "2024-12-15 10:30:00",
      "updated_at": "2024-12-15 10:30:00",
      "published_at": "2024-12-15 10:30:00",
      "url": "https://yoursite.com/hello-world"
    }
  ],
  "pagination": {
    "total": 25,
    "per_page": 5,
    "current_page": 1,
    "total_pages": 5
  }
}
GET /posts/{id}

Retrieve a single post by ID.

POST /posts

Create a new post. Requires write permission.

Request Body

{
  "title": "My New Post",
  "content": "<p>Post content here...</p>",
  "excerpt": "A short summary",
  "status": "published",
  "post_type": "post"
}
PUT /posts/{id}

Update an existing post. Requires write permission.

DELETE /posts/{id}

Delete a post (moves to trash). Requires delete permission.

Pages

Manage static pages. Pages use the same structure as posts with post_type: page.

GET /pages

Retrieve a list of pages.

GET /pages/{id}

Retrieve a single page by ID.

POST /pages

Create a new page.

PUT /pages/{id}

Update an existing page.

DELETE /pages/{id}

Delete a page.

Media

Manage uploaded files and images.

GET /media

Retrieve a list of media files.

Response

{
  "success": true,
  "data": [
    {
      "id": 1,
      "filename": "photo.jpg",
      "url": "https://yoursite.com/uploads/2024/12/photo.jpg",
      "mime_type": "image/jpeg",
      "size": 245678,
      "width": 1920,
      "height": 1080,
      "alt_text": "A beautiful sunset",
      "created_at": "2024-12-15 10:30:00"
    }
  ]
}
GET /media/{id}

Retrieve a single media item by ID.

POST /media

Upload a new media file via base64 encoding.

Request Body

{
  "filename": "photo.jpg",
  "data": "base64_encoded_file_content...",
  "alt_text": "Description of the image"
}
DELETE /media/{id}

Delete a media file.

Users

Retrieve user information (read-only for security).

GET /users

Retrieve a list of users (excludes sensitive data).

Response

{
  "success": true,
  "data": [
    {
      "id": 1,
      "username": "admin",
      "display_name": "Administrator",
      "role": "admin",
      "avatar_url": "https://gravatar.com/...",
      "created_at": "2024-12-01 09:00:00"
    }
  ]
}
GET /users/{id}

Retrieve a single user by ID.

Note: User creation and modification is not available via API for security reasons.

Taxonomies

Retrieve taxonomy terms (categories, tags, custom taxonomies).

GET /taxonomies/{type}

Retrieve terms for a taxonomy type.

Taxonomy Types

  • category — Post categories
  • tag — Post tags
  • {custom} — Any custom taxonomy slug

Example Request

curl "https://yoursite.com/api/v1/taxonomies/category" \
  -H "X-API-Key: your_key" \
  -H "X-API-Secret: your_secret"

Response

{
  "success": true,
  "data": [
    {
      "id": 1,
      "name": "Technology",
      "slug": "technology",
      "description": "Tech-related posts",
      "parent_id": 0,
      "count": 15
    }
  ]
}

Query Parameters

Common query parameters available on list endpoints:

ParameterDefaultDescription
per_page10Number of items per page (max: 100)
page1Page number for pagination
statuspublishedFilter by status
orderbydateField to sort by
orderdescSort direction (asc/desc)
post_typepostFilter by post type

Example with Multiple Parameters

GET /api/v1/posts?per_page=20&page=2&status=published&orderby=title&order=asc

Response Format

All API responses follow a consistent JSON structure:

Success Response

{
  "success": true,
  "data": { ... },
  "pagination": {
    "total": 100,
    "per_page": 10,
    "current_page": 1,
    "total_pages": 10
  }
}

Error Response

{
  "success": false,
  "error": "Error message here"
}

HTTP Status Codes

CodeDescription
200Success
201Created (POST requests)
400Bad Request (invalid parameters)
401Unauthorized (invalid or missing API key)
403Forbidden (insufficient permissions)
404Not Found
500Server Error

Error Handling

Handle API errors gracefully in your application:

// JavaScript example
async function getPosts() {
  try {
    const response = await fetch('https://yoursite.com/api/v1/posts', {
      headers: {
        'X-API-Key': 'your_key',
        'X-API-Secret': 'your_secret'
      }
    });
    
    const data = await response.json();
    
    if (!data.success) {
      throw new Error(data.error);
    }
    
    return data.data;
  } catch (error) {
    console.error('API Error:', error.message);
  }
}

Common Errors

ErrorCauseSolution
Missing API credentialsHeaders not includedAdd X-API-Key and X-API-Secret headers
Invalid API keyKey doesn't exist or is inactiveCheck key in Admin → Tools → API Keys
Permission deniedKey lacks required permissionUpdate key permissions in admin
API key expiredKey past expiration dateGenerate a new API key

Code Examples

JavaScript (Fetch)

// Get all published posts
const response = await fetch('https://yoursite.com/api/v1/posts', {
  headers: {
    'X-API-Key': 'your_key',
    'X-API-Secret': 'your_secret'
  }
});
const posts = await response.json();

// Create a new post
const newPost = await fetch('https://yoursite.com/api/v1/posts', {
  method: 'POST',
  headers: {
    'X-API-Key': 'your_key',
    'X-API-Secret': 'your_secret',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    title: 'My New Post',
    content: '<p>Hello World!</p>',
    status: 'published'
  })
});

PHP (cURL)

// Get all posts
$ch = curl_init('https://yoursite.com/api/v1/posts');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'X-API-Key: your_key',
    'X-API-Secret: your_secret'
]);
$response = curl_exec($ch);
$posts = json_decode($response, true);

// Create a post
$ch = curl_init('https://yoursite.com/api/v1/posts');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'X-API-Key: your_key',
    'X-API-Secret: your_secret',
    'Content-Type: application/json'
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
    'title' => 'My New Post',
    'content' => '<p>Hello World!</p>',
    'status' => 'published'
]));
$response = curl_exec($ch);

Python (Requests)

import requests

headers = {
    'X-API-Key': 'your_key',
    'X-API-Secret': 'your_secret'
}

# Get all posts
response = requests.get('https://yoursite.com/api/v1/posts', headers=headers)
posts = response.json()

# Create a post
response = requests.post(
    'https://yoursite.com/api/v1/posts',
    headers={**headers, 'Content-Type': 'application/json'},
    json={
        'title': 'My New Post',
        'content': '<p>Hello World!</p>',
        'status': 'published'
    }
)
Ready to integrate! See the Plugin Development Guide for extending the API with custom endpoints.