VrexAPI Docs

Avatars

Create reusable AI presenters (portrait + cloned voice) and generate lipsync talking videos. Avatar creation costs $1.00. Video generation billed at $0.05/s (avatar) or $0.08/s (avatar_pro).

Overview

The Avatars API lets you create a persistent AI presenter from either a text description or a talking-head video clip. Each avatar bundles a generated portrait with a cloned TTS voice — both reusable across unlimited lipsync video generations.

Feature flag: The API is gated by AVATARS_API_ENABLED=true. All endpoints return 503 FEATURE_DISABLED when the flag is absent or falsy.

System avatars: A set of pre-seeded public avatars (2 English, 4 Vietnamese) are always included in listing and fetch responses alongside your own avatars.

ActionCostNotes
Create avatar$1.00Charged immediately; refunded on failure
Create pose$0.013Image generation (i2i) rate
Video — avatar tier$0.05 / sFast; good for production
Video — avatar_pro tier$0.08 / sPremium quality; detailed expressions

avatar tier

Powered by pruna-ai/p-video/avatar. Fast turnaround, suitable for production workflows. Billed at $0.05 per second of actual audio.

avatar_pro tier

Powered by skywork-ai/skyreels-v3-standard/single-avatar. Slower generation with richer facial expressions and lip motion. Billed at $0.08 per second of actual audio.

Quick Start

# Create avatar from text description (generated)
curl -X POST https://getvrex.com/api/v1/avatars \
  -H "Authorization: Bearer sk-your-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Aria",
    "description": "Professional female presenter, confident and warm expression, business attire",
    "language": "en",
    "nationality": "American",
    "gender": "female",
    "accent": "Neutral"
  }'

# Poll for completion
curl https://getvrex.com/api/v1/avatars/av_abc123def456 \
  -H "Authorization: Bearer sk-your-api-key"

Avatar creation involves portrait generation, voice harvesting, and TTS voice cloning — expect 60–300 seconds. Poll every 5–10 seconds or use webhooks for zero-latency notification.

API Reference — Avatars

POST/avatars

Submit an async avatar creation job. Two modes: 'generated' (AI portrait from description) or 'video' (face + voice extracted from a talking-head clip).

Request Body

NameTypeRequiredDefaultDescription
namestringRequiredAvatar display name (1–60 chars).
descriptionstringOptionalPortrait/persona description (1–2000 chars). Required for source="generated"; optional for source="video" (auto-defaulted).
languagestringRequiredLanguage code: en, vi, zh, ja, ko, es, fr, de, pt, ar.
nationalitystringRequiredNationality label (1–60 chars), e.g. "American", "Vietnamese".
genderstringOptionalGender hint: male or female (guides voice selection).
accentstringOptionalOptional accent label (max 40 chars), e.g. "Northern", "Southern".
sourcestringOptionalgeneratedCreation mode: "generated" (text description → AI portrait) or "video" (talking-head clip → face frame + real-voice clone).
ref_image_data_urlstringOptionalSeed image for i2i portrait. Data URL (data:image/...;base64,...) or HTTPS URL (≤4 MB). Ignored when source="video".
source_video_urlstringOptionalRequired when source="video". Data URL (data:video/*;base64,...) or public HTTPS URL. Max 80 MB. MP4, MOV, WebM, M4V. The clip becomes the avatar's demo video.

Response (202 Accepted)

202Avatar creation job queued
{
  "id": "av_abc123def456",
  "status": "pending",
  "estimated_cost_usd": 1.00,
  "poll_url": "/api/v1/avatars/av_abc123def456"
}

Errors

CodeStatusDescription
INVALID_JSON400Request body is not valid JSON
VALIDATION_ERROR400Invalid request (name/description missing, language unsupported, etc.)
INSUFFICIENT_BALANCE402Insufficient balance. Please top up your account.
QUEUE_FULL429Avatar creation queue at capacity (sends Retry-After: 60)
RATE_LIMITED429Rate limit exceeded
FEATURE_DISABLED503Avatar creation temporarily disabled (AVATARS_API_ENABLED not set)
GET/avatars

List all avatars accessible to the caller: owned avatars + all public system avatars. Supports pagination.

Query Parameters

NameTypeRequiredDefaultDescription
pagenumberOptional1Page number for pagination.
limitnumberOptional20Items per page (max 100).

Response (200 OK)

200Paginated avatar list
{
  "data": [
    {
      "id": "av_abc123def456",
      "name": "Aria",
      "description": "Professional female presenter...",
      "language": "en",
      "nationality": "American",
      "gender": "female",
      "accent": "Neutral",
      "image_url": "https://r2.getvrex.com/avatars/...",
      "status": "ready",
      "stage": null,
      "is_system": false,
      "is_public": false,
      "cost_usd": 1.00,
      "error": null,
      "created_at": "2025-01-01T00:00:00.000Z",
      "updated_at": "2025-01-01T00:05:00.000Z"
    }
  ],
  "page": 1,
  "limit": 20
}

status: pending, processing, ready, failed

stage: Creation progress — one of portrait, demo, voice, poses

image_url: Presigned portrait URL (1-hour expiry) when status="ready", else null

is_system: true for pre-seeded system avatars (not deletable via API)

GET/avatars/:id

Fetch a single avatar by ID. Must be owned by the caller or a public system avatar.

Response (200 OK)

200Avatar detail
{
  "id": "av_abc123def456",
  "name": "Aria",
  "description": "Professional female presenter...",
  "language": "en",
  "nationality": "American",
  "gender": "female",
  "accent": "Neutral",
  "image_url": "https://r2.getvrex.com/avatars/...",
  "status": "ready",
  "stage": null,
  "is_system": false,
  "is_public": false,
  "tts_voice_id": "voice-abc123xyz",
  "cost_usd": 1.00,
  "error": null,
  "created_at": "2025-01-01T00:00:00.000Z",
  "updated_at": "2025-01-01T00:05:00.000Z"
}

tts_voice_id: Cloned TTS voice ID populated once status="ready". Use it directly with the /tts endpoint to synthesise speech in the avatar's voice without generating a full video.

Errors

CodeStatusDescription
NOT_FOUND404Avatar not found or not accessible
STORAGE_ERROR502Portrait key exists but R2 presigning failed
FEATURE_DISABLED503Avatar API disabled
DELETE/avatars/:id

Delete an owned avatar and all associated assets (portrait, videos, poses, TTS voice). System avatars cannot be deleted via API.

Response

204No Content — avatar and all assets deleted

Errors

CodeStatusDescription
NOT_FOUND404Avatar not found
FORBIDDEN403Avatar not owned by caller; system avatars are not deletable
FEATURE_DISABLED503Avatar API disabled

API Reference — Avatar Poses

Poses are i2i variations of an avatar's base portrait, usable as the starting frame for video generation. Each pose costs $0.013 (the standard image generation rate). The base portrait is always available as a free pose.

POST/avatars/:id/poses

Submit a pose creation job (i2i variation of the avatar's portrait). Avatar must be in 'ready' status.

Request Body

NameTypeRequiredDefaultDescription
promptstringRequiredPose description for i2i variation (1–600 chars).
namestringOptionalDisplay label (max 60 chars). Defaults to "Pose" if omitted.

Response (201 Created)

201Pose created
{
  "id": "ap_xyz789abc123",
  "avatar_id": "av_abc123def456",
  "prompt": "side profile, arms crossed, confident posture, business casual",
  "name": "Side Profile",
  "image_key": "avatars/user-id/pose-id.jpg",
  "image_url": "https://r2.getvrex.com/avatars/...",
  "status": "ready",
  "is_base": false,
  "cost_usd": 0.013
}

Errors

CodeStatusDescription
INVALID_JSON400Request body is not valid JSON
VALIDATION_ERROR400Prompt missing or too long (max 600 chars)
NOT_FOUND404Avatar not found or not accessible
WALLET_NOT_FOUND404No billing wallet exists yet (top up to initialise)
AVATAR_NOT_READY409Avatar not in ready status (still processing)
INSUFFICIENT_BALANCE_FOR_POSE402Insufficient balance to create a pose
DAILY_CAP_REACHED429Per-tier daily cap reached (resets midnight UTC)
RATE_LIMITED429Too many requests — see Retry-After header
FEATURE_DISABLED503Avatar API disabled
GET/avatars/:id/poses

List all poses for an avatar: the base portrait plus any custom poses created by the caller.

Response (200 OK)

200Pose list (base + custom)
{
  "data": [
    {
      "id": "ap_base-portrait-id",
      "avatar_id": "av_abc123def456",
      "name": "Base Portrait",
      "prompt": null,
      "image_key": null,
      "image_url": "https://r2.getvrex.com/avatars/...",
      "status": "ready",
      "is_base": true,
      "cost_usd": 0.0,
      "created_at": "2025-01-01T00:00:00.000Z"
    },
    {
      "id": "ap_xyz789abc123",
      "avatar_id": "av_abc123def456",
      "name": "Side Profile",
      "prompt": "side profile, arms crossed...",
      "image_key": "avatars/user-id/pose-id.jpg",
      "image_url": "https://r2.getvrex.com/avatars/...",
      "status": "ready",
      "is_base": false,
      "cost_usd": 0.013,
      "created_at": "2025-01-01T00:10:00.000Z"
    }
  ]
}

is_base: true for the avatar's default portrait (free; always present)

prompt / image_key: null for base portrait, populated for custom poses

Errors

CodeStatusDescription
NOT_FOUND404Avatar not found or not accessible
FEATURE_DISABLED503Avatar API disabled

API Reference — Avatar Videos

Generate a lipsync talking video from any ready avatar and a text script. Cost is estimated at request time from text length, then reconciled to actual audio duration after completion — you are only charged for what was produced.

Text limit: 600 characters (~30 seconds of audio).

# Generate an avatar lipsync video
curl -X POST https://getvrex.com/api/v1/avatar-videos \
  -H "Authorization: Bearer sk-your-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "avatar_id": "av_abc123def456",
    "text": "Welcome to our product demo. Let me show you what we can do.",
    "tier": "avatar",
    "video_prompt": "professional confidence, relaxed posture",
    "webhook_url": "https://your-server.com/webhook"
  }'

# Poll for completion
curl https://getvrex.com/api/v1/avatar-videos/vg_abc123def456 \
  -H "Authorization: Bearer sk-your-api-key"
POST/avatar-videos

Submit an async lipsync video generation job.

Request Body

NameTypeRequiredDefaultDescription
avatar_idstringRequiredAvatar ID to use (av_...).
textstringRequiredSpeech text (1–600 chars, ~30 s max).
tierstringOptionalavatarQuality tier: "avatar" ($0.05/s, fast) or "avatar_pro" ($0.08/s, premium).
pose_idstringOptionalCustom pose ID (ap_...); uses base portrait if omitted.
video_promptstringOptionalBehavior/movement hint for the lipsync model (max 300 chars).
webhook_urlstringOptionalHTTPS URL to receive video.completed or video.failed events.
output_formatstringOptionalurl"url" (presigned, 1-hour expiry) or "raw_key" (R2 object key). Affects the video_url field in GET /avatar-videos/:id — no effect on the 202 create response.

Response (202 Accepted)

202Avatar video job queued
{
  "id": "vg_abc123def456",
  "status": "queued",
  "tier": "avatar",
  "estimated_cost_usd": 0.15,
  "poll_url": "/api/v1/avatar-videos/vg_abc123def456"
}

Errors

CodeStatusDescription
INVALID_JSON400Request body is not valid JSON
VALIDATION_ERROR400Invalid request (text missing, too long, tier invalid, etc.)
POLICY_VIOLATION400Text fails safety filter
INSUFFICIENT_BALANCE402Insufficient balance
NOT_FOUND404Avatar or pose not found
AVATAR_NOT_READY409Avatar not in ready status, or avatar lacks portrait/voice
QUEUE_FULL429Avatar video queue at capacity (sends Retry-After: 60)
RATE_LIMITED429Rate limit exceeded
FEATURE_DISABLED503Avatar API disabled
GET/avatar-videos/:id

Poll the status and download link of an avatar video generation job.

Query Parameters

NameTypeRequiredDefaultDescription
output_formatstringOptionalurl"url" (presigned, 1-hour expiry) or "raw_key" (R2 object key).

Response (200 OK)

200Avatar video status
{
  "id": "vg_abc123def456",
  "status": "completed",
  "tier": "avatar",
  "seconds": 3,
  "actual_seconds": 3,
  "avatar_id": "av_abc123def456",
  "pose_id": "ap_xyz789abc123",
  "video_url": "https://r2.getvrex.com/avatar-videos/...",
  "cost_usd": 0.15,
  "actual_cost_usd": 0.15,
  "error": null,
  "created_at": "2025-01-01T12:00:00.000Z",
  "completed_at": "2025-01-01T12:00:30.000Z"
}

status: queued, processing, completed, failed

seconds: Estimated duration (from text length at request time)

actual_seconds: Actual measured audio duration (populated only after completion)

cost_usd: Estimated charge held at submission

actual_cost_usd: Final reconciled cost; reduced if actual duration < estimate; null on failure (refunded in full)

video_url: Presigned URL (1-hour expiry) or R2 key per output_format; null until completed

Errors

CodeStatusDescription
UNAUTHORIZED401Missing or invalid API key
VALIDATION_ERROR400output_format is not url or raw_key
NOT_FOUND404Video not found or does not belong to caller
STORAGE_ERROR502Failed to generate presigned URL
FEATURE_DISABLED503Avatar API disabled

Webhooks

Set webhook_url in the POST /avatar-videos request to receive events when the job reaches a terminal state. Your server must respond with 2xx within 10 seconds.

200video.completed — avatar video webhook payload
{
  "event": "video.completed",
  "video_gen_id": "vg_abc123def456",
  "video_url": "https://r2.getvrex.com/avatar-videos/...",
  "duration_sec": 3,
  "tier": "avatar",
  "actual_cost_usd": 0.15,
  "timestamp": "2025-01-01T12:00:30.000Z"
}

tier: Lipsync tier used — "avatar" or "avatar_pro"

actual_cost_usd: Present once cost reconciliation completes; may be omitted if reconciliation has not yet finished at webhook dispatch time

200video.failed — charge refunded in full
{
  "event": "video.failed",
  "video_gen_id": "vg_abc123def456",
  "error": "wavespeed API returned 502: service unavailable",
  "timestamp": "2025-01-01T12:00:30.000Z"
}

SDK

The official JavaScript SDK exposes all avatar operations under client.avatar.*:

create · list · get · delete · createPose · listPoses · generateVideo · videoStatus · waitForVideo

import { VrexClient } from "@vrex/sdk";

const client = new VrexClient({ apiKey: "sk-your-api-key" });

// Create an avatar (async — polls automatically)
const avatar = await client.avatar.create({
  name: "Aria",
  description: "Professional female presenter, confident and warm",
  language: "en",
  nationality: "American",
  gender: "female",
});

// List avatars
const { data } = await client.avatar.list({ page: 1, limit: 20 });

// Create a custom pose
const pose = await client.avatar.createPose(avatar.id, {
  prompt: "side profile, arms crossed, confident posture",
  name: "Side Profile",
});

// Generate a lipsync video (polls until complete)
const video = await client.avatar.waitForVideo({
  avatar_id: avatar.id,
  pose_id: pose.id,
  text: "Hello! Welcome to the demo.",
  tier: "avatar_pro",
});
console.log("Video URL:", video.video_url);
Tài liệu API — Vrex