> ## Documentation Index
> Fetch the complete documentation index at: https://developers.x-pilot.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# create avatar video

> Synthesize a talking-presenter video with an owned avatar whose training_status is ready. Drive it with text + voice_id (platform TTS, Voice I or Voice II) or with your own speech audio (asset_id or a public http(s) audio_url) — exactly one source, up to 5 minutes of speech. Output is a transparent-background WebM (VP9 with alpha) for compositing. Billed per rendered second at the digital-human video rate; the balance must cover the estimate before dispatch. Poll get_avatar_video, or receive avatar-video.completed / avatar-video.failed through callback_url or a webhook subscription. Reuse Idempotency-Key on retry; never resubmit automatically.

export const XpilotArticleMetadata = () => <script type="application/ld+json" data-xpilot-article-metadata="" dangerouslySetInnerHTML={{
  __html: "{\"@context\":\"https://schema.org\",\"@id\":\"https://developers.x-pilot.ai/api-reference/create-avatar-video#apireference\",\"author\":{\"@type\":\"Organization\",\"@id\":\"https://www.x-pilot.ai/#organization\",\"name\":\"X-Pilot\",\"url\":\"https://www.x-pilot.ai/\"},\"image\":{\"@type\":\"ImageObject\",\"url\":\"https://developers.x-pilot.ai/images/integration-api.png\",\"width\":1200,\"height\":675,\"caption\":\"REST requests use a scoped API key. Keys, credits and usage are managed in the App console.\"}}"
}} />;

<XpilotArticleMetadata />

export const XpilotBreadcrumb = () => <nav aria-label="Breadcrumb" className="xpilot-breadcrumb"><ol><li><a href="/api-reference/list-avatars">Avatars</a></li><li aria-current="page"><span aria-hidden="true">/</span><span>create avatar video</span></li></ol></nav>;

<XpilotBreadcrumb />

<p className="xpilot-doc-author">Documentation by <a href="https://www.x-pilot.ai/">X-Pilot</a></p>

<Warning>This request starts work that may consume workspace credits. Check credits and capacity before sending it.</Warning>

Required scope: `avatars:write`. A stable `Idempotency-Key` is required for exact retries.

[Manage API keys](https://app.x-pilot.ai/developers/console) · [Authentication and recovery](/api-reference)

export const XpilotDocFigure = () => <figure className="xpilot-doc-figure"><img src="/images/integration-api.png" alt="An application sends a scoped API key to the X-Pilot REST API and receives an HTTP status and JSON response." width="1200" height="675" loading="lazy" /><figcaption>REST requests use a scoped API key. Keys, credits and usage are managed in the App console.</figcaption></figure>;

<XpilotDocFigure />


## OpenAPI

````yaml openapi.json POST /v1/avatars/{avatar_id}/videos
openapi: 3.0.3
info:
  title: X-Pilot Developer API
  version: 1.1.0
  description: >-
    Generated from the same public REST contract used by the X-Pilot app. REST
    uses scoped API Keys. MCP OAuth tokens do not authenticate REST requests.
servers:
  - url: https://api.x-pilot.ai
    description: Production; confirm the deployed base URL in Developer Console.
security:
  - BearerAuth: []
tags:
  - name: Video Agent
  - name: Renders
  - name: Brand kits
  - name: Account & capacity
  - name: Assets
  - name: Voices & audio
  - name: Avatars
paths:
  /v1/avatars/{avatar_id}/videos:
    post:
      tags:
        - Avatars
      summary: create avatar video
      description: >-
        Synthesize a talking-presenter video with an owned avatar whose
        training_status is ready. Drive it with text + voice_id (platform TTS,
        Voice I or Voice II) or with your own speech audio (asset_id or a public
        http(s) audio_url) — exactly one source, up to 5 minutes of speech.
        Output is a transparent-background WebM (VP9 with alpha) for
        compositing. Billed per rendered second at the digital-human video rate;
        the balance must cover the estimate before dispatch. Poll
        get_avatar_video, or receive avatar-video.completed /
        avatar-video.failed through callback_url or a webhook subscription.
        Reuse Idempotency-Key on retry; never resubmit automatically.
      operationId: create-avatar-video
      parameters:
        - name: avatar_id
          in: path
          required: true
          description: Owned avatar ID with training_status ready.
          schema:
            type: string
            description: Owned avatar ID with training_status ready.
        - name: Idempotency-Key
          in: header
          required: true
          description: >-
            Stable key for exact retries only. Use a different key for a
            different operation or input.
          schema:
            type: string
            minLength: 8
            maxLength: 128
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                text:
                  type: string
                  description: >-
                    Spoken text for platform TTS. Use with voice_id; omit when
                    sending audio.
                  example: Welcome to our lesson.
                  maxLength: 5000
                voice_id:
                  type: string
                  description: >-
                    Catalog voice ID or owned ready clone ID from list_voices.
                    Required with text.
                voice_version:
                  type: integer
                  description: >-
                    Voice version of voice_id: Voice I (1, default) or Voice II
                    (2).
                  enum:
                    - 1
                    - 2
                  default: 1
                locale:
                  type: string
                  description: Optional native locale for the voice.
                speed:
                  type: number
                  description: TTS playback speed.
                  minimum: 0.5
                  maximum: 2
                audio_url:
                  type: string
                  description: >-
                    Public http(s) speech audio URL (≤20 MB). The backend
                    archives third-party audio to your owned storage first. Use
                    this or asset_id instead of text.
                asset_id:
                  type: string
                  description: >-
                    Owned audio asset ID returned by POST /v1/assets. Use this
                    or audio_url instead of text.
                callback_url:
                  type: string
                  description: >-
                    Optional public HTTPS URL notified once with
                    avatar-video.completed or avatar-video.failed. Signed with
                    the workspace callback secret (X-XPilot-Signature). Only set
                    it when you run a receiving service.
                  maxLength: 2048
                callback_id:
                  type: string
                  description: >-
                    Optional reference echoed back as data.callback_id. Requires
                    callback_url.
                  maxLength: 128
      responses:
        '202':
          description: Success
          content:
            application/json:
              example:
                data:
                  id: <video_id>
                  avatar_id: <avatar_id>
                  status: queued
                  source: text
                  video_url: null
                  format: webm
                  has_alpha: true
                  duration_seconds: null
                  width: null
                  height: null
                  cost_credits: null
                  error: null
                  created_at: 1791849600
                  updated_at: 1791849600
        '400':
          description: Check parameter types, required fields and idempotency key.
          content:
            application/json:
              example:
                error:
                  code: invalid_parameter
                  message: Check parameter types, required fields and idempotency key.
                request_id: <request_id>
        '401':
          description: Use an active scoped API Key. MCP OAuth tokens cannot call REST.
          content:
            application/json:
              example:
                error:
                  code: invalid_token
                  message: >-
                    Use an active scoped API Key. MCP OAuth tokens cannot call
                    REST.
                request_id: <request_id>
        '402':
          description: >-
            The balance cannot cover the platform reserve, or the credential
            monthly budget is used up.
          content:
            application/json:
              example:
                error:
                  code: insufficient_credits
                  message: >-
                    The balance cannot cover the platform reserve, or the
                    credential monthly budget is used up.
                request_id: <request_id>
        '403':
          description: Check the credential scope and resource ownership.
          content:
            application/json:
              example:
                error:
                  code: insufficient_scope
                  message: Check the credential scope and resource ownership.
                request_id: <request_id>
        '404':
          description: Use an existing owned conversation, message, brand kit or render ID.
          content:
            application/json:
              example:
                error:
                  code: not_found
                  message: >-
                    Use an existing owned conversation, message, brand kit or
                    render ID.
                request_id: <request_id>
        '409':
          description: >-
            The same idempotency key must use the exact same input. A
            conversation may already be busy.
          content:
            application/json:
              example:
                error:
                  code: idempotency_conflict
                  message: >-
                    The same idempotency key must use the exact same input. A
                    conversation may already be busy.
                request_id: <request_id>
        '429':
          description: >-
            Credential/workspace rate or concurrency limit reached. Respect
            Retry-After before retrying.
          content:
            application/json:
              example:
                error:
                  code: rate_limited
                  message: >-
                    Credential/workspace rate or concurrency limit reached.
                    Respect Retry-After before retrying.
                  retry_after: 60
                request_id: <request_id>
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl --fail-with-body --request POST \
              --url "$XPILOT_API_BASE_URL/v1/avatars/%3Cavatar_id%3E/videos" \
              --header "Authorization: Bearer $XPILOT_API_KEY" \
              --header 'Content-Type: application/json' \
              --header 'Idempotency-Key: lesson-request-001' \
              --data '{"text":"Welcome to our lesson.","voice_id":"<voice_id>","voice_version":1}'
        - lang: javascript
          label: JavaScript
          source: >-
            const response = await fetch(process.env.XPILOT_API_BASE_URL +
            "/v1/avatars/%3Cavatar_id%3E/videos", {
              method: "POST",
              headers: {
                Authorization: `Bearer ${process.env.XPILOT_API_KEY}`,
                "Content-Type": "application/json",
                "Idempotency-Key": "lesson-request-001",
              },
              body: JSON.stringify({
              "text": "Welcome to our lesson.",
              "voice_id": "<voice_id>",
              "voice_version": 1
            }),

            });

            const result = await response.json();

            if (!response.ok) throw new Error(JSON.stringify(result));

            console.log(result);
        - lang: python
          label: Python
          source: |-
            import os, json, requests

            response = requests.request(
                "POST",
                os.environ["XPILOT_API_BASE_URL"] + "/v1/avatars/%3Cavatar_id%3E/videos",
                headers={
                    "Authorization": "Bearer " + os.environ["XPILOT_API_KEY"],
                    "Content-Type": "application/json",
                    "Idempotency-Key": "lesson-request-001",
                },
                json=json.loads("{\"text\":\"Welcome to our lesson.\",\"voice_id\":\"<voice_id>\",\"voice_version\":1}"),
                timeout=70,
            )
            print(response.status_code, response.text)
            response.raise_for_status()
components:
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      description: Scoped X-Pilot API key

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.