X-Pilot API Reference
Developer Documentation · v2.0

X-Pilot API Reference

Build powerful AI-driven course video workflows with X-Pilot's REST API. Authenticate with Bearer tokens, generate videos, manage async pipelines, and integrate via MCP tools or Skills.

Base URL https://api.x-pilot.ai
Auth Bearer Token
Format application/json

Overview

X-Pilot exposes a RESTful HTTP API organized into eight functional groups. All requests require Content-Type: application/json. Protected endpoints require Authorization: Bearer <access_token>.

GroupBase PathDescription
Auth & Identity/auth · /usersSign-in, sign-up, Google OAuth, user profile
Video Projects/api/video/projectsCreate, read, update, delete projects; chat & message history
Export & Delivery/api/video/projects/{id}Generate audio, export video, share links
Async Tasks/api/tasksCreate, list, poll, regenerate background tasks
Knowledge Base/knowledgeBaseCreate KB, list, upload files, list files
Files & Parsing/file · /api/documentUpload, parse documents, convert Word to HTML
Voice Models/api/audio/modelList, create, get, update, delete voice models
Payments/api/paymentsCheckout sessions, billing portal

Quickstart

Go from zero to a running video project in five steps.

  1. 1

    Sign in and obtain an access token

    POST to /auth/sign_in with your email and password. The response includes access_token (short-lived) and refresh_token.

  2. 2

    Create a video project

    POST to /api/video/projects with a title and optional knowledge base reference. Returns a project_id.

  3. 3

    Send a generation request via chat

    POST to /api/video/projects/{id}/chat-message describing your video content. The AI orchestrator creates async tasks.

  4. 4

    Poll until complete

    GET /api/tasks/{task_id} every 3–5 seconds until status === "completed".

  5. 5

    Export the video

    POST to /api/video/projects/{id}/export-video and poll the same URL (GET) until the export URL is ready.

Chapter 01

Authentication

X-Pilot uses JWT Bearer tokens. Sign in to receive an access_token; include it as Authorization: Bearer <token> on every protected request. Tokens expire — use the refresh_token to obtain a new access token without re-authenticating.

POST /auth/sign_in Sign in with email + password

Request Body

FieldTypeRequired
emailstringrequired
passwordstringrequired

Response Fields

FieldTypeNotes
access_tokenstringJWT, ~1h expiry
refresh_tokenstringLong-lived
token_typestring"bearer"
expires_innumberSeconds
# Sign in and capture the access token
TOKEN=$(curl -s -X POST https://api.x-pilot.ai/auth/sign_in \
  -H "Content-Type: application/json" \
  -d '{"email":"[email protected]","password":"yourpassword"}' \
  | jq -r '.access_token')

# Use in subsequent requests
curl -X GET https://api.x-pilot.ai/users/me \
  -H "Authorization: Bearer $TOKEN"
POST /auth/sign_up Create a new account
FieldTypeRequiredNotes
emailstringrequiredMust be valid email format
passwordstringrequiredMin 8 characters
namestringoptionalDisplay name
invite_codestringoptionalReferral or invite code
curl -X POST https://api.x-pilot.ai/auth/sign_up \
  -H "Content-Type: application/json" \
  -d '{"email":"[email protected]","password":"securepass","name":"Jane Dev"}'
POST /api/auth/google Exchange Google ID token for X-Pilot token
FieldTypeRequiredNotes
tokenstringrequiredGoogle Sign-In ID token (from credential callback)
// In Google Sign-In callback handler
function handleCredentialResponse(response) {
  const googleToken = response.credential;
  fetch('https://api.x-pilot.ai/api/auth/google', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ token: googleToken })
  })
  .then(r => r.json())
  .then(({ access_token }) => {
    localStorage.setItem('xpilot_token', access_token);
  });
}
GET /users/me Get current authenticated user

No request body. Returns the authenticated user's profile including subscription tier, usage stats, and preferences.

Response FieldTypeDescription
idstringUser UUID
emailstringUser email
namestringDisplay name
planstring"free" | "pro" | "team" | "enterprise"
creditsnumberRemaining generation credits
created_atstringISO 8601 timestamp
curl https://api.x-pilot.ai/users/me \
  -H "Authorization: Bearer $TOKEN"
Chapter 02

Video Projects

Video projects are the core resource. Each project holds a conversation history with the AI, rendering configuration, and generated video assets. Projects are scoped to the authenticated user.

GET /api/video/projects List all projects
Query ParamTypeDefaultDescription
pagenumber1Page number
limitnumber20Items per page (max 100)
sortstring"updated_at""created_at" | "updated_at" | "title"
curl "https://api.x-pilot.ai/api/video/projects?page=1&limit=20" \
  -H "Authorization: Bearer $TOKEN"
POST /api/video/projects Create a new video project
FieldTypeRequiredDescription
titlestringrequiredProject display title
knowledge_base_idstringoptionalAttach an existing KB for context
voice_model_idstringoptionalDefault voice model UUID
languagestringoptionalISO language code, default "en"
curl -X POST https://api.x-pilot.ai/api/video/projects \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"title":"Python Async Course","language":"en"}'
GET /api/video/projects/{id} Get project details
curl https://api.x-pilot.ai/api/video/projects/proj_abc123 \
  -H "Authorization: Bearer $TOKEN"
POST /api/video/projects/{id}/chat-message Send AI generation instruction

This is the primary generation trigger. Describe the video content you want; the AI orchestrator will plan and queue async tasks. Returns a task_id for polling.

FieldTypeRequiredDescription
messagestringrequiredNatural language instruction for the video AI
context_filesstring[]optionalFile IDs to include as generation context
modestringoptional"generate" (default) | "refine" | "regenerate"
curl -X POST https://api.x-pilot.ai/api/video/projects/proj_abc123/chat-message \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"message":"Create a 5-slide explainer on Python async/await with code examples and animations"}'
GET /api/video/projects/{id}/messages Get conversation history
curl "https://api.x-pilot.ai/api/video/projects/proj_abc123/messages?limit=50" \
  -H "Authorization: Bearer $TOKEN"
Chapter 03

Export & Delivery

Export endpoints trigger rendering jobs. Both audio generation and video export are asynchronous — POST to start, then GET the same URL to poll for completion.

POST /api/video/projects/{id}/generate-audio Trigger audio generation

Triggers TTS rendering for all slides in the project. Poll via GET on the same path.

FieldTypeRequiredDescription
voice_model_idstringoptionalOverride default voice
speednumberoptionalPlayback speed 0.5–2.0 (default 1.0)
slide_idsstring[]optionalRegenerate specific slides only
# Trigger
curl -X POST https://api.x-pilot.ai/api/video/projects/proj_abc123/generate-audio \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"speed":1.1}'

# Poll
curl https://api.x-pilot.ai/api/video/projects/proj_abc123/generate-audio \
  -H "Authorization: Bearer $TOKEN"
POST /api/video/projects/{id}/export-video Trigger video export (returns job ID)
FieldTypeDefaultDescription
resolutionstring"1080p""720p" | "1080p" | "4k"
formatstring"mp4""mp4" | "webm"
fpsnumber3024 | 30 | 60
include_captionsbooleanfalseBurn-in subtitles
Response FieldDescription
job_idExport job identifier for polling
state"queued" | "rendering" | "completed" | "failed"
download_urlPre-signed download URL (present when completed)
expires_atISO timestamp for download URL expiry
# 1. Trigger export
JOB=$(curl -s -X POST https://api.x-pilot.ai/api/video/projects/proj_abc123/export-video \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"resolution":"1080p","fps":30}' | jq -r '.job_id')

# 2. Poll until done
while true; do
  RESULT=$(curl -s https://api.x-pilot.ai/api/video/projects/proj_abc123/export-video \
    -H "Authorization: Bearer $TOKEN")
  STATE=$(echo $RESULT | jq -r '.state')
  [ "$STATE" = "completed" ] && echo $RESULT | jq -r '.download_url' && break
  sleep 5
done
POST /api/v1/user_case/share-simple Create a shareable link
FieldTypeRequired
project_idstringrequired
expires_hoursnumberoptional (default 168 = 7 days)
passwordstringoptional
curl -X POST https://api.x-pilot.ai/api/v1/user_case/share-simple \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"project_id":"proj_abc123","expires_hours":72}'
Chapter 04

Async Task Pipeline

Long-running operations (script generation, code rendering, audio synthesis) run as async tasks. Each task transitions through states: queuedrunningcompleted | failed. Poll at 3–5 second intervals.

POST /api/tasks/create Manually create a task
FieldTypeRequiredDescription
project_idstringrequiredParent project UUID
typestringrequired"script_gen" | "code_render" | "audio_sync" | "full_pipeline"
payloadobjectoptionalType-specific configuration
prioritynumberoptional1–10 (default 5, higher = sooner)
curl -X POST https://api.x-pilot.ai/api/tasks/create \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"project_id":"proj_abc123","type":"full_pipeline","priority":8}'
GET /api/tasks/{task_id} Poll task status
Response FieldTypeDescription
idstringTask UUID
statusstring"queued" | "running" | "completed" | "failed"
progressnumber0–100 percentage
resultobjectOutput data (present when completed)
errorstringError message (present when failed)
created_atstringISO timestamp
completed_atstringISO timestamp (when done)
curl https://api.x-pilot.ai/api/tasks/task_xyz789 \
  -H "Authorization: Bearer $TOKEN"
POST /api/tasks/regenerate Retry a failed or specific task
FieldTypeRequired
task_idstringrequired
override_payloadobjectoptional — override original task params
curl -X POST https://api.x-pilot.ai/api/tasks/regenerate \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"task_id":"task_xyz789"}'
Chapter 05

Knowledge Base

Knowledge bases store course-specific reference documents that guide the AI during generation. Attach a KB to a project to improve accuracy and context relevance.

POST /knowledgeBase/create Create a new knowledge base
FieldTypeRequired
namestringrequired
descriptionstringoptional
tagsstring[]optional
curl -X POST https://api.x-pilot.ai/knowledgeBase/create \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name":"Python Fundamentals","description":"Core Python language concepts","tags":["python","programming"]}'
POST /knowledgeBase/file/upload/single Upload a file to a knowledge base

Multipart form upload. Supported formats: PDF, DOCX, PPTX, TXT, MD. Max file size: 50MB.

Form FieldTypeRequired
fileFile (binary)required
knowledge_base_idstringrequired
namestringoptional (defaults to filename)
curl -X POST https://api.x-pilot.ai/knowledgeBase/file/upload/single \
  -H "Authorization: Bearer $TOKEN" \
  -F "file=@/path/to/course-notes.pdf" \
  -F "knowledge_base_id=kb_abc123"
Chapter 06

Files & Parsing

Upload raw files, parse documents into structured content, or convert Word documents to HTML for downstream processing.

POST /file/upload Upload a file for use across the platform
curl -X POST https://api.x-pilot.ai/file/upload \
  -H "Authorization: Bearer $TOKEN" \
  -F "file=@/path/to/slides.pptx"
POST /api/document/parse/multiple Parse documents into structured text
FieldTypeRequired
file_idsstring[]required
extract_imagesbooleanoptional (default false)
output_formatstring"markdown" (default) | "json" | "plain"
curl -X POST https://api.x-pilot.ai/api/document/parse/multiple \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"file_ids":["file_abc","file_def"],"output_format":"markdown"}'
Chapter 07

Voice Models

Manage custom and built-in voice models for narration. Clone voices by uploading reference audio, then assign a voice model to any project or generation task.

GET /api/audio/model/list List available voice models
curl https://api.x-pilot.ai/api/audio/model/list \
  -H "Authorization: Bearer $TOKEN"
POST /api/audio/model Create / clone a custom voice
Form FieldTypeRequiredNotes
namestringrequiredDisplay name
reference_audioFile (binary)requiredWAV or MP3, 30s–10min, clear voice
languagestringoptionalISO language code (auto-detected if omitted)
descriptionstringoptionalInternal notes
curl -X POST https://api.x-pilot.ai/api/audio/model \
  -H "Authorization: Bearer $TOKEN" \
  -F "name=My Lecturer Voice" \
  -F "reference_audio=@/path/to/sample.wav" \
  -F "language=en"
PUT /api/audio/model/{model_id} · DELETE /api/audio/model/{model_id}

Update a voice model's metadata or permanently delete it. Deleting a model removes it from all future generations.

# Update name
curl -X PUT https://api.x-pilot.ai/api/audio/model/vm_abc123 \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name":"Updated Voice Name"}'

# Delete
curl -X DELETE https://api.x-pilot.ai/api/audio/model/vm_abc123 \
  -H "Authorization: Bearer $TOKEN"
Chapter 08

Payments

Manage subscriptions and billing via Stripe-backed endpoints. Redirect users to the returned URL to complete the checkout or manage their billing portal.

POST /api/payments/create-checkout-session Create a Stripe checkout session
FieldTypeRequiredNotes
price_idstringrequiredStripe price ID (e.g. "price_pro_monthly")
success_urlstringrequiredRedirect after payment success
cancel_urlstringrequiredRedirect on cancellation
curl -X POST https://api.x-pilot.ai/api/payments/create-checkout-session \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"price_id":"price_pro_monthly","success_url":"https://yourapp.com/success","cancel_url":"https://yourapp.com/cancel"}'
POST /api/payments/billing-portal Open Stripe customer billing portal
curl -X POST https://api.x-pilot.ai/api/payments/billing-portal \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"return_url":"https://yourapp.com/settings"}'
Guide 01

End-to-End Workflows

Complete, runnable code that chains multiple API calls into production-ready workflows.

Document → Video Full Pipeline

Upload a PDF/PPTX, create a project, trigger generation, wait for completion, then export and download.

const BASE = 'https://api.x-pilot.ai';

async function documentToVideo({ email, password, filePath, projectTitle, prompt }) {
  // 1. Authenticate
  const { access_token } = await fetch(`${BASE}/auth/sign_in`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ email, password })
  }).then(r => r.json());

  const headers = {
    'Content-Type': 'application/json',
    'Authorization': `Bearer ${access_token}`
  };

  const api = (path, opts = {}) =>
    fetch(`${BASE}${path}`, { ...opts, headers: { ...headers, ...opts.headers } }).then(r => r.json());

  // 2. Upload source document
  const fileForm = new FormData();
  fileForm.append('file', await fetch(filePath).then(r => r.blob()), 'source.pdf');
  const { file_id } = await fetch(`${BASE}/file/upload`, {
    method: 'POST',
    headers: { 'Authorization': `Bearer ${access_token}` },
    body: fileForm
  }).then(r => r.json());

  // 3. Parse document
  const { documents } = await api('/api/document/parse/multiple', {
    method: 'POST', body: JSON.stringify({ file_ids: [file_id], output_format: 'markdown' })
  });

  // 4. Create project
  const { id: projectId } = await api('/api/video/projects', {
    method: 'POST', body: JSON.stringify({ title: projectTitle })
  });

  // 5. Trigger generation
  const { task_id } = await api(`/api/video/projects/${projectId}/chat-message`, {
    method: 'POST',
    body: JSON.stringify({ message: prompt, context_files: [file_id] })
  });

  // 6. Poll until complete
  let delay = 3000;
  while (true) {
    const task = await api(`/api/tasks/${task_id}`);
    console.log(`[${task.status}] ${task.progress ?? 0}%`);
    if (task.status === 'completed') break;
    if (task.status === 'failed') throw new Error(`Task failed: ${task.error}`);
    await new Promise(r => setTimeout(r, delay));
    delay = Math.min(delay * 1.4, 15000);
  }

  // 7. Export video
  await api(`/api/video/projects/${projectId}/export-video`, {
    method: 'POST', body: JSON.stringify({ resolution: '1080p' })
  });

  delay = 5000;
  while (true) {
    const job = await api(`/api/video/projects/${projectId}/export-video`);
    if (job.state === 'completed') return job.download_url;
    if (job.state === 'failed') throw new Error(`Export failed: ${job.error}`);
    await new Promise(r => setTimeout(r, delay));
    delay = Math.min(delay * 1.5, 20000);
  }
}

// Usage
documentToVideo({
  email: '[email protected]',
  password: 'yourpassword',
  filePath: './course-notes.pdf',
  projectTitle: 'Python Async Course',
  prompt: 'Create a comprehensive 8-slide video on Python async/await with animated code examples'
}).then(url => console.log('Download:', url));
Guide 02

MCP Integration

X-Pilot exposes its API surface as Model Context Protocol (MCP) tools. Each tool maps 1:1 to a REST endpoint, enabling AI agents (Claude, GPT, etc.) to call X-Pilot natively. Below are the complete JSON Schema definitions for six core MCP tools.

// MCP Tool Manifest — x-pilot-api/v2

const tools = [
  {
    name: 'xpilot_create_project',
    description: 'Create a new X-Pilot video project. Returns a project ID for downstream operations.',
    inputSchema: {
      type: 'object',
      required: ['title'],
      properties: {
        title: { type: 'string', description: 'Project title' },
        knowledge_base_id: { type: 'string', description: 'Optional KB ID to attach' },
        language: { type: 'string', default: 'en', description: 'ISO language code' }
      }
    }
  },
  {
    name: 'xpilot_generate_video',
    description: 'Send an AI generation instruction to a project and return the async task ID.',
    inputSchema: {
      type: 'object',
      required: ['project_id', 'message'],
      properties: {
        project_id: { type: 'string', description: 'Target project UUID' },
        message: { type: 'string', description: 'Natural language video generation instruction' },
        context_files: {
          type: 'array',
          items: { type: 'string' },
          description: 'Optional file IDs for generation context'
        },
        mode: {
          type: 'string',
          enum: ['generate', 'refine', 'regenerate'],
          default: 'generate'
        }
      }
    }
  },
  {
    name: 'xpilot_poll_task',
    description: 'Poll the status of an async task. Returns status, progress (0-100), and result when done.',
    inputSchema: {
      type: 'object',
      required: ['task_id'],
      properties: {
        task_id: { type: 'string', description: 'Task UUID returned by generate or create endpoints' }
      }
    }
  },
  {
    name: 'xpilot_export_video',
    description: 'Trigger video export for a project. Returns job status and download URL when complete.',
    inputSchema: {
      type: 'object',
      required: ['project_id'],
      properties: {
        project_id: { type: 'string' },
        resolution: {
          type: 'string',
          enum: ['720p', '1080p', '4k'],
          default: '1080p'
        },
        format: { type: 'string', enum: ['mp4', 'webm'], default: 'mp4' },
        include_captions: { type: 'boolean', default: false }
      }
    }
  },
  {
    name: 'xpilot_upload_to_kb',
    description: 'Upload a document file to a knowledge base for use as generation context.',
    inputSchema: {
      type: 'object',
      required: ['knowledge_base_id', 'file_content_base64', 'filename'],
      properties: {
        knowledge_base_id: { type: 'string' },
        file_content_base64: { type: 'string', description: 'Base64-encoded file content' },
        filename: { type: 'string', description: 'Original filename with extension' },
        mime_type: { type: 'string', default: 'application/pdf' }
      }
    }
  },
  {
    name: 'xpilot_list_voice_models',
    description: 'List all available voice models (built-in and custom). Returns IDs for use in project/generation settings.',
    inputSchema: {
      type: 'object',
      properties: {
        type_filter: {
          type: 'string',
          enum: ['all', 'builtin', 'custom'],
          default: 'all'
        },
        language_filter: { type: 'string', description: 'ISO language code filter' }
      }
    }
  }
];

REST-to-MCP Bridge Pattern: Each MCP tool handler should call the corresponding REST endpoint with the user's Bearer token, handle errors by returning them in the MCP error field, and for async tools (xpilot_generate_video, xpilot_export_video), implement polling internally and return the final result to the AI agent only when complete.

Guide 03

Skills Patterns

Skills are higher-level abstractions that encapsulate multi-step X-Pilot workflows for use in AI agent frameworks. Each Skill class wraps several API calls into a single callable interface.

VideoGenerationSkill

/**
 * VideoGenerationSkill — orchestrates the full project → generate → export pipeline
 */
class VideoGenerationSkill {
  constructor(apiClient) {
    this.api = apiClient; // authenticated API client instance
  }

  /** @param {object} params - {title, prompt, resolution, contextFileIds} */
  async execute({ title, prompt, resolution = '1080p', contextFileIds = [] }) {
    // Step 1: Create project
    const { id: projectId } = await this.api.post('/api/video/projects', { title });

    // Step 2: Generate
    const { task_id } = await this.api.post(`/api/video/projects/${projectId}/chat-message`, {
      message: prompt, context_files: contextFileIds
    });

    // Step 3: Await generation
    await this._waitForTask(task_id);

    // Step 4: Export
    return this._exportAndWait(projectId, resolution);
  }

  async _waitForTask(taskId, maxWait = 600000) {
    const start = Date.now(); let delay = 3000;
    while (Date.now() - start < maxWait) {
      const t = await this.api.get(`/api/tasks/${taskId}`);
      if (t.status === 'completed') return t.result;
      if (t.status === 'failed') throw new Error(`Task ${taskId} failed: ${t.error}`);
      await sleep(delay); delay = Math.min(delay * 1.4, 15000);
    }
    throw new Error('Task timed out');
  }

  async _exportAndWait(projectId, resolution) {
    const url = `/api/video/projects/${projectId}/export-video`;
    await this.api.post(url, { resolution });
    let delay = 5000;
    while (true) {
      const job = await this.api.get(url);
      if (job.state === 'completed') return { projectId, downloadUrl: job.download_url };
      if (job.state === 'failed') throw new Error(job.error);
      await sleep(delay); delay = Math.min(delay * 1.5, 20000);
    }
  }
}

// Usage
const skill = new VideoGenerationSkill(authenticatedApiClient);
const { downloadUrl } = await skill.execute({
  title: 'React Hooks Deep Dive',
  prompt: 'Create a 6-slide animated explainer covering useState, useEffect, useMemo, useCallback',
  resolution: '1080p'
});

DocumentToVideoSkill

class DocumentToVideoSkill {
  constructor(apiClient) { this.api = apiClient; }

  async execute({ file, projectTitle, generationPrompt, resolution = '1080p' }) {
    // 1. Upload document
    const form = new FormData(); form.append('file', file);
    const { file_id } = await this.api.postForm('/file/upload', form);

    // 2. Parse it
    const { documents } = await this.api.post('/api/document/parse/multiple', {
      file_ids: [file_id], output_format: 'markdown'
    });

    // 3. Delegate to VideoGenerationSkill
    const vg = new VideoGenerationSkill(this.api);
    return vg.execute({
      title: projectTitle,
      prompt: `${generationPrompt}

Source document (parsed):
${documents[0].content}`,
      contextFileIds: [file_id],
      resolution
    });
  }
}

VoicePersonalizationSkill

class VoicePersonalizationSkill {
  constructor(apiClient) { this.api = apiClient; }

  /** Clone voice from sample, then apply to project audio generation */
  async execute({ voiceName, sampleAudioFile, projectId, speed = 1.0 }) {
    // 1. Clone voice
    const form = new FormData();
    form.append('name', voiceName);
    form.append('reference_audio', sampleAudioFile);
    const { id: voiceModelId } = await this.api.postForm('/api/audio/model', form);

    // 2. Generate audio with custom voice
    await this.api.post(`/api/video/projects/${projectId}/generate-audio`, {
      voice_model_id: voiceModelId, speed
    });

    // 3. Poll audio generation
    let delay = 3000;
    while (true) {
      const s = await this.api.get(`/api/video/projects/${projectId}/generate-audio`);
      if (s.state === 'completed') return { voiceModelId, projectId };
      if (s.state === 'failed') throw new Error(s.error);
      await sleep(delay); delay = Math.min(delay * 1.4, 10000);
    }
  }
}
Reference 01

Error Codes

All errors follow a consistent structure: HTTP status code + JSON body with error (machine-readable code) and message (human-readable explanation). Business-logic errors always return HTTP 200 with an error body.

// Error response structure
{
  "error": "ERR_INVALID_TOKEN",
  "message": "The provided access token has expired.",
  "status": 401,
  "request_id": "req_8f2a19c3"  // Include in support tickets
}
HTTP StatusError CodeMeaningAction
200SUCCESSRequest succeeded
400ERR_VALIDATIONMissing or invalid request fieldsCheck request body against schema
400ERR_FILE_TYPEUnsupported file formatUse PDF, DOCX, PPTX, TXT, or MD
400ERR_FILE_TOO_LARGEFile exceeds 50MB limitCompress or split the file
401ERR_UNAUTHORIZEDNo Authorization headerInclude Bearer <token> header
401ERR_INVALID_TOKENToken invalid or malformedRe-authenticate via /auth/sign_in
401ERR_TOKEN_EXPIREDAccess token has expiredUse refresh_token to get a new access_token
403ERR_FORBIDDENResource belongs to another userVerify you own the requested resource
403ERR_PLAN_LIMITAction exceeds your plan quotaUpgrade plan or wait for quota reset
404ERR_NOT_FOUNDResource does not existVerify the ID is correct
409ERR_CONFLICTDuplicate resource or concurrent modificationRetry with exponential backoff
422ERR_CREDITS_EXHAUSTEDNo generation credits remainingPurchase credits or upgrade plan
429ERR_RATE_LIMITToo many requests (60 req/min default)Implement exponential backoff; check Retry-After header
500ERR_INTERNALUnexpected server errorRetry once; if persists, contact support with request_id
503ERR_SERVICE_UNAVAILABLEDownstream AI service overloadedRetry with exponential backoff (up to 3×)

Rate Limits

PlanRequests/minConcurrent ExportsMonthly Generations
Free20110
Pro603100
Team20010Unlimited
EnterpriseCustomCustomUnlimited
Reference 02

FAQ

How do I handle token refresh?

Access tokens expire after ~1 hour. When you receive a 401 ERR_TOKEN_EXPIRED response, POST to /auth/refresh with your refresh_token:

curl -X POST https://api.x-pilot.ai/auth/refresh \
  -H "Content-Type: application/json" \
  -d '{"refresh_token":"your_refresh_token"}'
How long does video generation take?

Generation time varies by complexity: a 5-slide script typically takes 30–90 seconds. Full rendering (audio + export) adds 2–5 minutes per minute of video at 1080p. Implement polling with 3–5 second intervals and exponential backoff up to 15 seconds.

What file formats are supported for document upload?

Supported: PDF, DOCX, PPTX, TXT, MD, HTML. Maximum file size is 50MB per file. For large documents, we recommend splitting by chapter or section for better generation quality.

Can I use the API without a credit card?

Yes. Free plan accounts include 10 video generations per month. Sign up at , then use your email/password to authenticate via the API.

How do I get my download URL after export?

After triggering export (POST), poll GET on the same endpoint (/api/video/projects/{'{id}'}/export-video) until state === "completed". The response will include download_url (pre-signed S3 URL) and expires_at. Download links expire after 24 hours.

Is there a webhook alternative to polling?

Webhook support is on the roadmap for Team and Enterprise plans. Currently, the recommended pattern is polling with exponential backoff (3s initial delay, max 15s, timeout at 10 minutes). Join our developer newsletter to be notified when webhooks launch.

Ready to build with X-Pilot?

Start with a free account — 10 video generations per month, no credit card required. Access the full API within minutes.

Need enterprise support or higher rate limits? [email protected].