Custom Integrations
Build custom frontends, external tools, and third-party integrations using the Orbem Studio REST API.
Table of Contents
- Overview
- Authentication
- Building a Custom Frontend
- Mobile Client Integration
- External Admin Tools
- Analytics Integration
- Best Practices
Overview
Orbem Studio's REST API enables building custom interfaces and integrations beyond the default WordPress frontend.
Use Cases
- Mobile Apps: Native iOS/Android game clients
- Alternative Frontends: React, Vue, or Angular SPAs
- Admin Dashboards: Custom game management interfaces
- Analytics Tools: Player behavior tracking and reporting
- Third-Party Integrations: Discord bots, Twitch extensions, etc.
Authentication
WordPress Application Passwords
For external applications, use WordPress Application Passwords (WP 5.6+).
Setup:
- Navigate to Users → Profile
- Scroll to "Application Passwords"
- Create new password for your application
- Store securely (shown only once)
Usage:
curl -X POST \
-u "username:application_password" \
-H "Content-Type: application/json" \
-d '{"area":"level-1"}' \
https://yoursite.com/wp-json/orbemorder/v1/area/OAuth Integration
For user-facing applications, implement OAuth flow:
- Use WordPress OAuth plugin
- Implement authorization flow
- Store access tokens securely
- Refresh tokens as needed
Building a Custom Frontend
Architecture
graph TB
Custom[Custom Frontend] --> API[Orbem Studio REST API]
API --> WP[WordPress Backend]
WP --> DB[Database]
Custom --> Assets[Load Game Assets]
Custom --> Render[Render Game State]
Custom --> Input[Handle User Input]
API --> State[Player State]
API --> Objects[Game Objects]
API --> Progress[Mission Progress]Initial Data Loading
1. Load Area Data:
async function loadArea(areaSlug) {
const response = await fetch('/wp-json/orbemorder/v1/area/', {
method: 'POST',
headers: {
'Authorization': 'Basic ' + btoa('username:app_password'),
'Content-Type': 'application/json'
},
body: JSON.stringify({ area: areaSlug })
});
const result = await response.json();
return result.data;
}2. Parse Game Objects:
function parseGameObjects(areaData) {
const characters = areaData.posts.filter(p => p.post_type === 'explore-character');
const enemies = areaData.posts.filter(p => p.post_type === 'explore-enemy');
const items = areaData.posts.filter(p => p.post_type === 'explore-point');
return { characters, enemies, items };
}3. Render Game State:
function renderGame(areaData) {
const canvas = document.getElementById('game-canvas');
const ctx = canvas.getContext('2d');
// Load and draw map
const map = new Image();
map.src = areaData.meta['explore-map'];
map.onload = () => {
ctx.drawImage(map, 0, 0);
// Render game objects
renderObjects(ctx, areaData.posts);
};
}Player State Management
Save Player Position:
async function savePosition(area, top, left) {
await fetch('/wp-json/orbemorder/v1/coordinates/', {
method: 'POST',
headers: {
'Authorization': 'Basic ' + credentials,
'Content-Type': 'application/json'
},
body: JSON.stringify({ area, top, left })
});
}Update Player Stats:
async function updateStat(type, value, add = true) {
await fetch('/wp-json/orbemorder/v1/add-explore-points/', {
method: 'POST',
headers: {
'Authorization': 'Basic ' + credentials,
'Content-Type': 'application/json'
},
body: JSON.stringify({ type, value, add })
});
}Mission System Integration
Complete Mission:
async function completeMission(missionSlug) {
const response = await fetch('/wp-json/orbemorder/v1/mission/', {
method: 'POST',
headers: {
'Authorization': 'Basic ' + credentials,
'Content-Type': 'application/json'
},
body: JSON.stringify({ mission: missionSlug })
});
return response.json();
}Mobile Client Integration
React Native Example
import AsyncStorage from '@react-native-async-storage/async-storage';
class OrbemGameClient {
constructor(baseUrl, username, appPassword) {
this.baseUrl = baseUrl;
this.credentials = btoa(`${username}:${appPassword}`);
}
async loadArea(areaSlug) {
try {
const response = await fetch(`${this.baseUrl}/wp-json/orbemorder/v1/area/`, {
method: 'POST',
headers: {
'Authorization': `Basic ${this.credentials}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ area: areaSlug })
});
const result = await response.json();
// Cache for offline access
await AsyncStorage.setItem(`area_${areaSlug}`, JSON.stringify(result.data));
return result.data;
} catch (error) {
// Load from cache if offline
const cached = await AsyncStorage.getItem(`area_${areaSlug}`);
return cached ? JSON.parse(cached) : null;
}
}
async saveProgress(data) {
// Queue for sync when online
const queue = await AsyncStorage.getItem('sync_queue') || '[]';
const updates = JSON.parse(queue);
updates.push(data);
await AsyncStorage.setItem('sync_queue', JSON.stringify(updates));
}
}Unity Integration
using UnityEngine;
using UnityEngine.Networking;
using System.Collections;
public class OrbemAPIClient : MonoBehaviour
{
private string baseUrl = "https://yoursite.com";
private string credentials; // Base64 encoded "username:password"
public IEnumerator LoadArea(string areaSlug)
{
string url = $"{baseUrl}/wp-json/orbemorder/v1/area/";
string jsonData = $"{{\"area\":\"{areaSlug}\"}}";
using (UnityWebRequest request = UnityWebRequest.Post(url, jsonData))
{
request.SetRequestHeader("Authorization", $"Basic {credentials}");
request.SetRequestHeader("Content-Type", "application/json");
yield return request.SendWebRequest();
if (request.result == UnityWebRequest.Result.Success)
{
string responseText = request.downloadHandler.text;
// Parse and use data
ProcessAreaData(responseText);
}
}
}
}External Admin Tools
Game Dashboard Example
// React admin dashboard component
import React, { useState, useEffect } from 'react';
function GameDashboard({ apiUrl, credentials }) {
const [areas, setAreas] = useState([]);
const [characters, setCharacters] = useState([]);
useEffect(() => {
loadGameData();
}, []);
async function loadGameData() {
// Load all areas
const areasResponse = await fetch(`${apiUrl}/wp/v2/explore-area?per_page=100`, {
headers: { 'Authorization': `Basic ${credentials}` }
});
setAreas(await areasResponse.json());
// Load all characters
const charsResponse = await fetch(`${apiUrl}/wp/v2/explore-character?per_page=100`, {
headers: { 'Authorization': `Basic ${credentials}` }
});
setCharacters(await charsResponse.json());
}
return (
<div className="dashboard">
<h2>Game Statistics</h2>
<div className="stats">
<StatCard title="Total Areas" value={areas.length} />
<StatCard title="Total Characters" value={characters.length} />
</div>
<AreaList areas={areas} />
<CharacterList characters={characters} />
</div>
);
}Analytics Integration
Tracking Player Behavior
class GameAnalytics {
constructor(apiUrl, credentials) {
this.api = apiUrl;
this.auth = credentials;
}
async trackEvent(eventType, eventData) {
// Send to your analytics service
await fetch('https://analytics.yourservice.com/event', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
event: eventType,
data: eventData,
timestamp: new Date().toISOString()
})
});
}
async trackAreaVisit(area) {
await this.trackEvent('area_visit', { area });
}
async trackMissionComplete(mission) {
await this.trackEvent('mission_complete', { mission });
}
async trackCombatEncounter(enemy, outcome) {
await this.trackEvent('combat', { enemy, outcome });
}
}
// Usage
const analytics = new GameAnalytics(apiUrl, credentials);
analytics.trackAreaVisit('level-1');Best Practices
Performance
Caching:
- Cache area data locally
- Implement aggressive caching for static assets
- Use service workers for offline support
Batch Requests:
// Instead of multiple individual requests
const updates = [
savePosition(area, top, left),
updateStat('health', 25, true),
completeMission('mission-1')
];
await Promise.all(updates);Error Handling
async function apiRequest(endpoint, data) {
try {
const response = await fetch(endpoint, {
method: 'POST',
headers: {
'Authorization': credentials,
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
const result = await response.json();
if (!result.success) {
throw new Error(result.data);
}
return result.data;
} catch (error) {
console.error('API request failed:', error);
// Implement retry logic or queue for later
return null;
}
}Security
Secure Credentials:
- Never expose credentials in client-side code
- Use environment variables
- Implement OAuth for user-facing apps
- Rotate application passwords regularly
Input Validation:
- Validate all data before sending to API
- Sanitize user input
- Implement rate limiting
HTTPS Only:
- Always use HTTPS for API requests
- Validate SSL certificates
- Don't accept self-signed certificates in production
Testing Integrations
Test Environment
const TEST_CONFIG = {
baseUrl: 'https://test.yoursite.com',
credentials: btoa('test_user:test_password')
};
describe('Orbem API Integration', () => {
test('should load area data', async () => {
const data = await loadArea('test-area');
expect(data).toHaveProperty('posts');
expect(data).toHaveProperty('meta');
});
test('should save player position', async () => {
const result = await savePosition('test-area', 100, 200);
expect(result.success).toBe(true);
});
});Related Documentation
- API Overview - REST API architecture
- Gameplay Endpoints - Available endpoints
- Extensibility Overview - Other extension methods
- Hooks and Filters - WordPress hooks