AI Agent API
xPandorax Developer Documentation — v2.0
Connect your AI agent to xPandorax and programmatically manage your producer channel. Create, read, update, and delete videos, cuts, pictures, models, and your producer profile — all via a simple REST API. This documentation covers authentication, all endpoints, request/response schemas, error handling, and best practices.
Overview
The xPandorax AI Agent API enables automated content management for producer accounts. Whether you're building a Python scraper, an n8n workflow, a LangChain agent, or a custom integration, this API gives you full CRUD access to your producer's content.
Content ownership: Before using this API, ensure you have the legal right to upload and distribute all content. xPandorax enforces DMCA compliance and will suspend accounts found violating third-party copyrights.
Authentication
All API requests require a Bearer token in the Authorization header. Tokens are generated from the AI Department in your Creator Studio.
Token Format
Authorization: Bearer xpx_yo...tokenGetting a Token
- Navigate to Creator Studio → AI Department
- Click New Token
- Give your token a descriptive name (e.g. "My Scraper Bot")
- Accept the warranty terms
- Copy the raw token immediately — it is shown only once
Security note: Store your token as an environment variable (e.g. XPANDORAX_API_TOKEN). Never hardcode tokens in source code or expose them in client-side JavaScript. Revoke compromised tokens immediately from the AI Department dashboard.
Base URL
https://xpandorax.comAll endpoints are relative to this base URL. Example: https://xpandorax.com/api/agent/v2/content/videos
Endpoints
All content management endpoints are under /api/agent/v2/content/*. These endpoints manage content under your active producer profile. The legacy upload endpoints are under /api/agent/*.
Producer Profile
/api/agent/v2/content/producer/api/agent/v2/content/producerVideos
/api/agent/v2/content/videos/api/agent/v2/content/videos/api/agent/v2/content/videos/:id/api/agent/v2/content/videos/:idCuts (Short Clips)
/api/agent/v2/content/cuts/api/agent/v2/content/cuts/api/agent/v2/content/cuts/:id/api/agent/v2/content/cuts/:idPictures
/api/agent/v2/content/pictures/api/agent/v2/content/pictures/api/agent/v2/content/pictures/:id/api/agent/v2/content/pictures/:idModels
/api/agent/v2/content/models/api/agent/v2/content/models/api/agent/v2/content/models/:id/api/agent/v2/content/models/:idProducer Profile
Get or update your active producer profile. Each API token is tied to the producer associated with your account.
GET /api/agent/v2/content/producer
// Response (200)
{
"id": "uuid",
"name": "My Studio",
"slug": "my-studio",
"description": "Premium content producer",
"logo_url": "https://media.xpandorax.com/logos/...",
"cover_url": "https://media.xpandorax.com/covers/...",
"website": "https://example.com",
"social_links": {
"twitter": "@mystudio",
"instagram": "@mystudio"
},
"is_verified": true,
"content_count": {
"videos": 42,
"cuts": 15,
"pictures": 8,
"models": 5
},
"created_at": "2026-01-15T00:00:00Z",
"updated_at": "2026-05-17T00:00:00Z"
}PATCH /api/agent/v2/content/producer
Partial update — send only the fields you want to change.
| Field | Type | Required | Description |
|---|---|---|---|
| name | string | No | Studio name |
| description | string | No | Bio / description |
| logo_url | string | No | Logo image URL |
| cover_url | string | No | Cover/banner image URL |
| website | string | No | Producer website URL |
| social_links | object | No | Social media URLs object |
Videos
GET /api/agent/v2/content/videos
Query parameters: ?page=1 ?limit=50 ?sort=created_at ?order=desc
POST /api/agent/v2/content/videos
| Field | Type | Required | Description |
|---|---|---|---|
| title | string | Yes | Video title (max 255 chars) |
| description | string | No | Video description |
| video_url | string | Yes | Direct CDN URL to the video file |
| thumbnail_url | string | No | URL to the video thumbnail image |
| tags | string[] | No | Array of tag strings |
| categories | string[] | No | Category names (must exist on platform) |
| models | string[] | No | Model IDs to associate |
| duration_hours | number | No | Duration hours component (0-23) |
| duration_minutes | number | No | Duration minutes component (0-59) |
| duration_seconds | number | No | Duration seconds component (0-59) |
| is_hd | boolean | No | Mark as HD content |
| is_exclusive | boolean | No | Mark as exclusive content |
| is_private | boolean | No | Hide from public listings |
// Request body
{
"title": "Filipina Amateur Couple - Sarapbabe Exclusive",
"description": "Amateur couple filmed in Manila. High quality exclusive content.",
"video_url": "https://cdn.example.com/videos/filipina-couple.mp4",
"thumbnail_url": "https://cdn.example.com/thumbs/filipina-couple.jpg",
"tags": ["filipina", "amateur", "couple", "exclusive"],
"categories": ["Filipina", "Amateur", "Couples"],
"models": ["model-uuid-1"],
"duration_hours": 0,
"duration_minutes": 12,
"duration_seconds": 34,
"is_hd": true,
"is_exclusive": true
}
// Response (201)
{
"id": "new-video-uuid",
"title": "Filipina Amateur Couple - Sarapbabe Exclusive",
"status": "published",
"slug": "filipina-amateur-couple-sarapbabe-exclusive",
"created_at": "2026-05-18T08:30:00Z"
}PATCH /api/agent/v2/content/videos/:id
Partial update — supports same fields as POST except video_url (immutable after creation).
DELETE /api/agent/v2/content/videos/:id
Soft-deletes the video. Returns 204 No Content on success.
Cuts (Short Clips)
Cuts are short video clips (typically under 60 seconds). Similar schema to videos but optimised for short-form content.
| Field | Type | Required | Description |
|---|---|---|---|
| title | string | Yes | Cut title |
| description | string | No | Short description |
| cut_url | string | Yes | CDN URL to the clip file |
| thumbnail_url | string | No | Thumbnail image URL |
| tags | string[] | No | Array of tags |
| categories | string[] | No | Category names |
| models | string[] | No | Associated model IDs |
| source_video_id | string | No | ID of the parent video if this is a clip |
| is_private | boolean | No | Hide from public |
Pictures (Galleries)
Picture entries represent galleries or individual images. Each entry can have multiple image URLs.
| Field | Type | Required | Description |
|---|---|---|---|
| title | string | Yes | Gallery title |
| description | string | No | Gallery description |
| image_urls | string[] | Yes | Array of image CDN URLs |
| thumbnail_url | string | No | Cover thumbnail URL |
| tags | string[] | No | Array of tags |
| categories | string[] | No | Category names |
| models | string[] | No | Associated model IDs |
| is_private | boolean | No | Hide from public |
Models
Models are the performers / talent associated with your content. Each model entry stores biographical data and appearance attributes.
| Field | Type | Required | Description |
|---|---|---|---|
| name | string | Yes | Model's display name |
| bio | string | No | Short biography / description |
| image_url | string | No | Profile image URL |
| age | number | No | Age (must be 18+) |
| ethnicity | string | No | Ethnicity (e.g. Filipina, Latina) |
| hair_color | string | No | Hair color |
| eye_color | string | No | Eye color |
| height_cm | number | No | Height in centimeters |
| weight_kg | number | No | Weight in kilograms |
| measurements | string | No | Body measurements (e.g. 34C-24-36) |
| tags | string[] | No | Array of descriptive tags |
| social_links | object | No | Object with social URLs e.g. {"instagram":"..."} |
// Request body
{
"name": "Mia Santos",
"bio": "Filipina model from Manila. 5ft 5in, athletic build.",
"image_url": "https://cdn.example.com/models/mia-santos.jpg",
"age": 24,
"ethnicity": "Filipina",
"hair_color": "Black",
"eye_color": "Brown",
"height_cm": 165,
"weight_kg": 55,
"measurements": "34C-24-36",
"tags": ["filipina", "athletic", "brunette"],
"social_links": {
"instagram": "https://instagram.com/mia_santos",
"twitter": "https://twitter.com/mia_santos"
}
}
// Response (201)
{
"id": "new-model-uuid",
"name": "Mia Santos",
"slug": "mia-santos",
"created_at": "2026-05-18T08:30:00Z"
}Legacy Upload Flow (Video Uploads)
The legacy upload flow is a three-step process for direct video file uploads. Use the v2 Content Management API (above) for videos already hosted elsewhere.
Request Upload URL
/api/agent/upload-urlSend file metadata to receive a presigned Backblaze B2 URL and upload log ID.
// Request
{
"filename": "my-video.mp4",
"filesize": 104857600, // bytes (max 5 GB)
"content_type": "video/mp4" // video/mp4 | video/webm | video/quicktime
}
// Response
{
"upload_log_id": "uuid",
"presigned_url": "https://s3.us-east-005.backblazeb2.com/...",
"b2_key": "agent-uploads/2026/05/my-video.mp4",
"cdn_url": "https://media.xpandorax.com/agent-uploads/...",
"expires_at": "2026-05-18T08:45:00Z",
"quota_used": 1,
"quota_limit": 10
}Upload Binary to B2
Presigned URL (external)PUT the video binary file directly to the presigned URL. No auth header required for this step.
curl -X PUT \
-H "Content-Type: video/mp4" \
--data-binary @/path/to/video.mp4 \
"https://s3.us-east-005.backblazeb2.com/..."Confirm with Metadata
/api/agent/confirm-uploadProvide title, tags, categories and source URL. Gemini validates the content; if approved, the video enters the admin review queue.
// Request
{
"upload_log_id": "uuid-from-step-1",
"metadata": {
"title": "Filipina Amateur Couple",
"description": "Amateur couple video",
"tags": ["filipina", "amateur"],
"categories": ["Filipina", "Amateur"],
"original_source_url": "https://sarapbabe.com/video/123",
"thumbnail_url": "https://sarapbabe.com/thumb/123.jpg",
"duration_hours": 0,
"duration_minutes": 12,
"duration_seconds": 34
}
}
// Approved response
{
"success": true,
"video_id": "uuid",
"status": "pending_review",
"gemini_confidence": 0.95,
"cleaned_title": "Filipina Amateur Couple"
}
// Rejected response
{
"success": false,
"rejected": true,
"reason": "Content flags detected",
"issues": ["Title appears clickbait", "Source URL domain not recognized"],
"gemini_confidence": 0.30
}Code Examples
curl
# List videos
curl -H "Authorization: Bearer xpx_your_token_here" \
https://xpandorax.com/api/agent/v2/content/videos
# Create a video
curl -X POST \
-H "Authorization: Bearer xpx_your_token_here" \
-H "Content-Type: application/json" \
-d '{
"title": "My Agent Uploaded Video",
"video_url": "https://cdn.example.com/video.mp4",
"tags": ["exclusive", "hd"]
}' \
https://xpandorax.com/api/agent/v2/content/videos
# Update a video
curl -X PATCH \
-H "Authorization: Bearer xpx_your_token_here" \
-H "Content-Type: application/json" \
-d '{"title": "Updated Title", "is_hd": true}' \
https://xpandorax.com/api/agent/v2/content/videos/video-uuid
# Delete a video
curl -X DELETE \
-H "Authorization: Bearer xpx_your_token_here" \
https://xpandorax.com/api/agent/v2/content/videos/video-uuidPython (requests)
import requests
import os
API_TOKEN = os.environ["XPANDORAX_API_TOKEN"]
BASE = "https://xpandorax.com/api/agent/v2"
HEADERS = {"Authorization": f"Bearer {API_TOKEN}"}
# ── List videos ──
resp = requests.get(f"{BASE}/content/videos", headers=HEADERS)
videos = resp.json()
print(f"Found {len(videos)} videos")
# ── Create a video ──
video_data = {
"title": "My Agent Uploaded Video",
"description": "Created via AI Agent API",
"video_url": "https://cdn.example.com/video.mp4",
"thumbnail_url": "https://cdn.example.com/thumb.jpg",
"tags": ["exclusive", "hd"],
"duration_minutes": 15,
"is_hd": True,
}
resp = requests.post(f"{BASE}/content/videos", headers=HEADERS, json=video_data)
print(resp.json())
# ── Add a model ──
model_data = {
"name": "Mia Santos",
"ethnicity": "Filipina",
"height_cm": 165,
"tags": ["brunette", "athletic"],
}
resp = requests.post(f"{BASE}/content/models", headers=HEADERS, json=model_data)
print(resp.json())
# ── Full upload flow (legacy) ──
video_path = "/path/to/video.mp4"
file_size = os.path.getsize(video_path)
# Step 1: request presigned URL
r1 = requests.post(f"{BASE.rsplit('/v2',1)[0]}/upload-url",
headers=HEADERS,
json={"filename": "video.mp4", "filesize": file_size, "content_type": "video/mp4"})
r1.raise_for_status()
data = r1.json()
# Step 2: upload to B2
with open(video_path, "rb") as f:
r2 = requests.put(data["presigned_url"],
data=f, headers={"Content-Type": "video/mp4"})
r2.raise_for_status()
# Step 3: confirm with metadata
r3 = requests.post(f"{BASE.rsplit('/v2',1)[0]}/confirm-upload",
headers=HEADERS,
json={
"upload_log_id": data["upload_log_id"],
"metadata": {
"title": "Filipina Amateur",
"tags": ["filipina", "amateur"],
"original_source_url": "https://example.com/video/1",
}
})
print(r3.json())JavaScript (fetch)
const API_TOKEN = process.env.XPANDORAX_API_TOKEN;
const BASE = "https://xpandorax.com/api/agent/v2";
const headers = {
Authorization: `Bearer ${API_TOKEN}`,
"Content-Type": "application/json",
};
// ── List videos ──
const resp = await fetch(`${BASE}/content/videos`, { headers });
const videos = await resp.json();
console.log(`Found ${videos.length} videos`);
// ── Create a video ──
const createResp = await fetch(`${BASE}/content/videos`, {
method: "POST",
headers,
body: JSON.stringify({
title: "My Agent Uploaded Video",
video_url: "https://cdn.example.com/video.mp4",
tags: ["exclusive", "hd"],
is_hd: true,
}),
});
const newVideo = await createResp.json();
console.log("Created:", newVideo.id);
// ── Update producer profile ──
const updateResp = await fetch(`${BASE}/content/producer`, {
method: "PATCH",
headers,
body: JSON.stringify({
description: "Updated bio from my AI agent",
}),
});
console.log(await updateResp.json());
// ── Delete a video ──
await fetch(`${BASE}/content/videos/video-uuid`, {
method: "DELETE",
headers,
});Response Formats
Success Response
// Single resource
GET /api/agent/v2/content/videos/video-id
{
"id": "uuid",
"title": "Video Title",
"description": "...",
"slug": "video-title",
"video_url": "https://...",
"thumbnail_url": "https://...",
"tags": ["tag1", "tag2"],
"categories": ["Category1"],
"models": [{ "id": "uuid", "name": "Model Name" }],
"duration": { "hours": 0, "minutes": 12, "seconds": 34 },
"is_hd": true,
"views": 1520,
"status": "published",
"created_at": "2026-05-18T08:30:00Z",
"updated_at": "2026-05-18T09:00:00Z"
}
// List response
GET /api/agent/v2/content/videos
{
"data": [ { ... }, { ... } ],
"pagination": {
"page": 1,
"limit": 50,
"total": 142,
"total_pages": 3
}
}Error Response
{
"error": {
"code": "validation_error",
"message": "Title is required",
"details": {
"field": "title",
"reason": "missing_required_field"
}
}
}Error Codes
Rate Limits
120 requests per minute
Per API token. The rate limit resets every 60 seconds. If you exceed this limit, subsequent requests will return 429 Too Many Requests. Implement exponential backoff with jitter in your agent to handle rate limits gracefully. Contact support if you need a higher limit.
Best Practices
Retry with Backoff
Implement exponential backoff (1s → 2s → 4s → 8s) with jitter for 429 and 5xx responses. This prevents hammering the API during transient failures.
Idempotent Operations
PATCH and DELETE operations are idempotent. Calling PATCH with the same data multiple times produces the same result. Use this to safely retry on network errors.
Content Compliance
Ensure all uploaded content complies with xPandorax's Terms of Service. Gemini validates content metadata in the upload flow — titles should be descriptive, not clickbait. All models must be 18+ verified.
Rate Limit Headers
Monitor response headers: X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset. These tell you exactly when the window resets.
Tags & Categories
Use existing categories where possible. Tags are free-form but should be lowercase, single words. Consistent tagging improves content discoverability.
Batch Updates
For bulk operations, batch your requests with reasonable concurrency (5-10 concurrent requests). Each request is independently rate-limited against your token's 120 req/min.
Framework Integrations
DMCA / Content Disputes
To report a content ownership dispute or request a takedown, use the DMCA API endpoint. All reports are reviewed by our admin team within 72 hours.
/api/agent/dmca{
"reporter_name": "Your Full Legal Name",
"reporter_email": "you@example.com",
"claim_description": "I own this content and did not authorise its upload. [min 50 chars]",
"video_id": "optional-video-uuid",
"original_url": "https://original-source.com/video"
}Note: False DMCA claims may result in legal liability. Only submit claims for content you own or represent. xPandorax follows the DMCA safe harbor provisions.
Changelog
- Complete v2 Content Management API released
- New endpoints for Producer, Videos, Cuts, Pictures, Models
- Structured request/response schemas with validation
- Token scope system for fine-grained access control
- This documentation site launched
- Added Gemini content validation on upload confirmation
- Rate limit increased to 120 req/min
- Added test-validation endpoint for pre-flight checks
- Initial AI Agent API release
- Three-step upload flow (upload-url → B2 → confirm)
- Daily quota tracking per token
Ready to Connect Your AI Agent?
Head to the AI Department in your Creator Studio to generate your API token and start managing your content programmatically.
