{
  "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."
    }
  ],
  "tags": [
    {
      "name": "Video Agent"
    },
    {
      "name": "Renders"
    },
    {
      "name": "Brand kits"
    },
    {
      "name": "Account & capacity"
    },
    {
      "name": "Assets"
    },
    {
      "name": "Voices & audio"
    },
    {
      "name": "Avatars"
    }
  ],
  "security": [
    {
      "BearerAuth": []
    }
  ],
  "paths": {
    "/v1/video-agents/conversations": {
      "get": {
        "operationId": "list-conversations",
        "tags": [
          "Video Agent"
        ],
        "summary": "List conversations",
        "description": "Owned conversations, newest first, with cumulative cost_credits. Conversation status follows its latest message. status: queued, running, stopping, paused, completed, failed or stopped. next_action is set only when paused: confirm_outline (confirm or revise the outline) or reply (answer the assistant with a prompt). Times are Unix seconds.",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Results per page, from 1 to 100.",
            "schema": {
              "type": "integer",
              "description": "Results per page, from 1 to 100.",
              "default": 20,
              "minimum": 1,
              "maximum": 100
            }
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "description": "Number of items to skip.",
            "schema": {
              "type": "integer",
              "description": "Number of items to skip.",
              "default": 0,
              "minimum": 0
            }
          }
        ],
        "x-required-scope": "video_agents:read",
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "items": [
                      {
                        "conversation_id": "<conversation_id>",
                        "status": "paused",
                        "next_action": "confirm_outline",
                        "created_at": 1791849600,
                        "updated_at": 1791849600,
                        "cost_credits": 12.5,
                        "preview_video_url": null
                      }
                    ],
                    "total": 1,
                    "limit": 20,
                    "offset": 0
                  }
                }
              }
            }
          },
          "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>"
                }
              }
            }
          },
          "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>"
                }
              }
            }
          },
          "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 GET \\\n  --url \"$XPILOT_API_BASE_URL/v1/video-agents/conversations?limit=20&offset=0\" \\\n  --header \"Authorization: Bearer $XPILOT_API_KEY\""
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const response = await fetch(process.env.XPILOT_API_BASE_URL + \"/v1/video-agents/conversations?limit=20&offset=0\", {\n  method: \"GET\",\n  headers: {\n    Authorization: `Bearer ${process.env.XPILOT_API_KEY}`,\n  },\n});\nconst result = await response.json();\nif (!response.ok) throw new Error(JSON.stringify(result));\nconsole.log(result);"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os, json, requests\n\nresponse = requests.request(\n    \"GET\",\n    os.environ[\"XPILOT_API_BASE_URL\"] + \"/v1/video-agents/conversations?limit=20&offset=0\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"XPILOT_API_KEY\"],\n    },\n    timeout=70,\n)\nprint(response.status_code, response.text)\nresponse.raise_for_status()"
          }
        ]
      },
      "post": {
        "operationId": "create-conversation",
        "tags": [
          "Video Agent"
        ],
        "summary": "Create conversation",
        "description": "Creates a conversation and starts the first paid message immediately. Check credits and capacity first. By default the video is generated straight through; set require_outline_confirmation=true to review the outline first. Each files item may use an owned asset_id or a third-party public URL, with its own files_role. Billing matches the app: the platform reserve is held, released at the end, then actual usage is charged (a short balance is charged to 0, never negative). cost_credits is the held reserve until the message settles. Poll list messages at least 5 seconds apart; there is no streaming.",
        "parameters": [
          {
            "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
            }
          }
        ],
        "x-required-scope": "video_agents:write",
        "responses": {
          "202": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "conversation_id": "<conversation_id>",
                    "message_id": "<message_id>",
                    "status": "running",
                    "cost_credits": 12
                  }
                }
              }
            }
          },
          "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>"
                }
              }
            }
          },
          "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 \\\n  --url \"$XPILOT_API_BASE_URL/v1/video-agents/conversations\" \\\n  --header \"Authorization: Bearer $XPILOT_API_KEY\" \\\n  --header 'Content-Type: application/json' \\\n  --header 'Idempotency-Key: lesson-request-001' \\\n  --data '{\"prompt\":\"Create a short English lesson about solar energy.\",\"require_outline_confirmation\":false,\"video_config\":{\"target_language\":\"en\",\"video_duration\":\"short\",\"video_style\":\"clean_lecture\"},\"files\":[{\"url\":\"https://cdn.example.com/course.pdf\",\"files_role\":\"primary\"}],\"callback_url\":\"https://your-domain.com/xpilot/callback\",\"callback_id\":\"order-1024\"}'"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const response = await fetch(process.env.XPILOT_API_BASE_URL + \"/v1/video-agents/conversations\", {\n  method: \"POST\",\n  headers: {\n    Authorization: `Bearer ${process.env.XPILOT_API_KEY}`,\n    \"Content-Type\": \"application/json\",\n    \"Idempotency-Key\": \"lesson-request-001\",\n  },\n  body: JSON.stringify({\n  \"prompt\": \"Create a short English lesson about solar energy.\",\n  \"require_outline_confirmation\": false,\n  \"video_config\": {\n    \"target_language\": \"en\",\n    \"video_duration\": \"short\",\n    \"video_style\": \"clean_lecture\"\n  },\n  \"files\": [\n    {\n      \"url\": \"https://cdn.example.com/course.pdf\",\n      \"files_role\": \"primary\"\n    }\n  ],\n  \"callback_url\": \"https://your-domain.com/xpilot/callback\",\n  \"callback_id\": \"order-1024\"\n}),\n});\nconst result = await response.json();\nif (!response.ok) throw new Error(JSON.stringify(result));\nconsole.log(result);"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os, json, requests\n\nresponse = requests.request(\n    \"POST\",\n    os.environ[\"XPILOT_API_BASE_URL\"] + \"/v1/video-agents/conversations\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"XPILOT_API_KEY\"],\n        \"Content-Type\": \"application/json\",\n        \"Idempotency-Key\": \"lesson-request-001\",\n    },\n    json=json.loads(\"{\\\"prompt\\\":\\\"Create a short English lesson about solar energy.\\\",\\\"require_outline_confirmation\\\":false,\\\"video_config\\\":{\\\"target_language\\\":\\\"en\\\",\\\"video_duration\\\":\\\"short\\\",\\\"video_style\\\":\\\"clean_lecture\\\"},\\\"files\\\":[{\\\"url\\\":\\\"https://cdn.example.com/course.pdf\\\",\\\"files_role\\\":\\\"primary\\\"}],\\\"callback_url\\\":\\\"https://your-domain.com/xpilot/callback\\\",\\\"callback_id\\\":\\\"order-1024\\\"}\"),\n    timeout=70,\n)\nprint(response.status_code, response.text)\nresponse.raise_for_status()"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "prompt": {
                    "type": "string",
                    "description": "The brief: audience and goal first, then a # title and ## sections with concrete facts, numbers, formulas, dates or ordered steps. Each ## section becomes roughly one scene; keep one video to about 12 scenes. Do not name visual components. Up to 20,000 characters.",
                    "example": "Create a short English lesson about solar energy.",
                    "maxLength": 20000
                  },
                  "require_outline_confirmation": {
                    "type": "boolean",
                    "description": "Default false: generate straight through with no pause. true: the first message pauses with status=paused, next_action=confirm_outline and an outline summary; then send outline_action=confirm (no prompt needed) or outline_action=revise with a prompt.",
                    "default": false,
                    "example": false
                  },
                  "video_config": {
                    "type": "object",
                    "description": "Video settings applied at creation; they cannot be changed by a follow-up message. Unknown fields or unsupported values return 400 invalid_parameter with param and allowed.",
                    "example": {
                      "target_language": "en",
                      "video_duration": "short",
                      "video_style": "clean_lecture"
                    },
                    "properties": {
                      "target_language": {
                        "type": "string",
                        "description": "Narration and subtitle language: ISO 639-1 code or BCP-47 tag (en, zh, zh-CN, ja, de, fr, es…). Default en. Changing it later means a new video.",
                        "default": "en"
                      },
                      "video_duration": {
                        "type": "string",
                        "description": "short: 1–3 min. deep: 3–10 min. long: 10–20 min.",
                        "enum": [
                          "short",
                          "deep",
                          "long"
                        ],
                        "default": "short"
                      },
                      "video_style": {
                        "type": "string",
                        "description": "auto lets the agent choose. clean_lecture: courses. science_explainer: science processes. professional_training: workplace training. product_showcase: product demos. cinematic_story: history and narrative.",
                        "enum": [
                          "auto",
                          "clean_lecture",
                          "science_explainer",
                          "professional_training",
                          "product_showcase",
                          "cinematic_story"
                        ],
                        "default": "auto"
                      },
                      "voice_id": {
                        "type": "string",
                        "description": "Narration voice from list voices. Default picks a voice for target_language."
                      },
                      "voice_version": {
                        "type": "integer",
                        "description": "Version of voice_id. Requires voice_id.",
                        "enum": [
                          1,
                          2
                        ],
                        "default": 1
                      },
                      "locale": {
                        "type": "string",
                        "description": "Optional native locale of voice_id, for example en-US. Requires voice_id."
                      },
                      "avatar_id": {
                        "oneOf": [
                          {
                            "type": "string"
                          },
                          {
                            "type": "integer"
                          }
                        ],
                        "description": "Presenter from list avatars. Must have selectable=true, otherwise 409 avatar_not_ready."
                      },
                      "brand_kit_id": {
                        "oneOf": [
                          {
                            "type": "string"
                          },
                          {
                            "type": "integer"
                          }
                        ],
                        "description": "Brand kit for logo, colors and tone."
                      },
                      "enable_initial_ai_video": {
                        "type": "boolean",
                        "description": "Generate an AI opening clip when the plan allows it.",
                        "default": false
                      }
                    }
                  },
                  "files": {
                    "type": "array",
                    "description": "Up to 5 attachments. Each item uses either an owned asset_id or a caller-supplied public http(s) URL. Third-party URLs are downloaded and archived to the caller's storage before use. Item fields: asset_id or url (required), name (optional, ≤255), type (optional: document, image, video; inferred when omitted), and files_role (optional: primary or reference).",
                    "example": [
                      {
                        "url": "https://cdn.example.com/course.pdf",
                        "files_role": "primary"
                      }
                    ],
                    "items": {
                      "type": "object",
                      "properties": {
                        "asset_id": {
                          "oneOf": [
                            {
                              "type": "string"
                            },
                            {
                              "type": "integer"
                            }
                          ],
                          "description": "id returned by POST /v1/assets or list assets."
                        },
                        "url": {
                          "type": "string",
                          "description": "Caller-supplied public http(s) URL. Third-party content is archived before use."
                        },
                        "name": {
                          "type": "string",
                          "description": "Optional display name, up to 255 characters; inferred when omitted."
                        },
                        "type": {
                          "type": "string",
                          "description": "Optional; inferred from the file.",
                          "enum": [
                            "document",
                            "image",
                            "video"
                          ]
                        },
                        "files_role": {
                          "type": "string",
                          "description": "How this file shapes the video. primary: use it as main content and visual source. reference: use it only as background facts. Omit to let the agent decide.",
                          "enum": [
                            "primary",
                            "reference"
                          ]
                        }
                      }
                    }
                  },
                  "callback_url": {
                    "type": "string",
                    "description": "Optional webhook for this message only. Public HTTPS (port 443) up to 2,048 characters; private, loopback and http addresses return 400 invalid_webhook_url / unsafe_webhook_url. When the message reaches completed, paused, failed or stopped, X Pilot POSTs a video-agent.<status> event signed with the workspace callback secret (Developer console → Webhooks). Deliveries retry up to 6 times and are listed in the console.",
                    "example": "https://your-domain.com/xpilot/callback",
                    "maxLength": 2048
                  },
                  "callback_id": {
                    "type": "string",
                    "description": "Optional reference echoed back as data.callback_id in the callback, such as your order ID. Letters, digits, _ . : - up to 128 characters. Requires callback_url.",
                    "example": "order-1024",
                    "pattern": "^[\\w.:-]{1,128}$",
                    "maxLength": 128
                  }
                },
                "required": [
                  "prompt"
                ]
              }
            }
          }
        }
      }
    },
    "/v1/video-agents/conversations/{conversation_id}": {
      "get": {
        "operationId": "get-conversation",
        "tags": [
          "Video Agent"
        ],
        "summary": "Get conversation",
        "description": "Conversation summary. status: queued, running, stopping, paused, completed, failed or stopped. next_action is set only when paused: confirm_outline (confirm or revise the outline) or reply (answer the assistant with a prompt). Use list messages for the outline and per-message detail.",
        "parameters": [
          {
            "name": "conversation_id",
            "in": "path",
            "required": true,
            "description": "An owned video agent conversation ID.",
            "schema": {
              "type": "string",
              "description": "An owned video agent conversation ID."
            }
          }
        ],
        "x-required-scope": "video_agents:read",
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "conversation_id": "<conversation_id>",
                    "status": "paused",
                    "next_action": "confirm_outline",
                    "created_at": 1791849600,
                    "updated_at": 1791849600,
                    "cost_credits": 12.5,
                    "preview_video_url": null
                  }
                }
              }
            }
          },
          "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>"
                }
              }
            }
          },
          "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>"
                }
              }
            }
          },
          "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 GET \\\n  --url \"$XPILOT_API_BASE_URL/v1/video-agents/conversations/%3Cconversation_id%3E\" \\\n  --header \"Authorization: Bearer $XPILOT_API_KEY\""
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const response = await fetch(process.env.XPILOT_API_BASE_URL + \"/v1/video-agents/conversations/%3Cconversation_id%3E\", {\n  method: \"GET\",\n  headers: {\n    Authorization: `Bearer ${process.env.XPILOT_API_KEY}`,\n  },\n});\nconst result = await response.json();\nif (!response.ok) throw new Error(JSON.stringify(result));\nconsole.log(result);"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os, json, requests\n\nresponse = requests.request(\n    \"GET\",\n    os.environ[\"XPILOT_API_BASE_URL\"] + \"/v1/video-agents/conversations/%3Cconversation_id%3E\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"XPILOT_API_KEY\"],\n    },\n    timeout=70,\n)\nprint(response.status_code, response.text)\nresponse.raise_for_status()"
          }
        ]
      },
      "post": {
        "operationId": "send-message",
        "tags": [
          "Video Agent"
        ],
        "summary": "Send message",
        "description": "Send a follow-up turn to a conversation that is not running (409 conversation_busy otherwise). Paid. When next_action=confirm_outline, send outline_action=confirm (no prompt) or outline_action=revise with a prompt. When next_action=reply, answer with a prompt. Otherwise send an edit instruction. video_config and require_outline_confirmation are create-only (400 unsupported_parameter).",
        "parameters": [
          {
            "name": "conversation_id",
            "in": "path",
            "required": true,
            "description": "An owned video agent conversation ID.",
            "schema": {
              "type": "string",
              "description": "An owned video agent conversation ID."
            }
          },
          {
            "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
            }
          }
        ],
        "x-required-scope": "video_agents:write",
        "responses": {
          "202": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "conversation_id": "<conversation_id>",
                    "message_id": "<message_id>",
                    "status": "running",
                    "cost_credits": 12
                  }
                }
              }
            }
          },
          "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 \\\n  --url \"$XPILOT_API_BASE_URL/v1/video-agents/conversations/%3Cconversation_id%3E\" \\\n  --header \"Authorization: Bearer $XPILOT_API_KEY\" \\\n  --header 'Content-Type: application/json' \\\n  --header 'Idempotency-Key: lesson-request-001' \\\n  --data '{\"prompt\":\"Make scene 2 shorter and add a worked example.\",\"files\":[{\"url\":\"https://cdn.example.com/course.pdf\",\"files_role\":\"primary\"}],\"callback_url\":\"https://your-domain.com/xpilot/callback\",\"callback_id\":\"order-1024\"}'"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const response = await fetch(process.env.XPILOT_API_BASE_URL + \"/v1/video-agents/conversations/%3Cconversation_id%3E\", {\n  method: \"POST\",\n  headers: {\n    Authorization: `Bearer ${process.env.XPILOT_API_KEY}`,\n    \"Content-Type\": \"application/json\",\n    \"Idempotency-Key\": \"lesson-request-001\",\n  },\n  body: JSON.stringify({\n  \"prompt\": \"Make scene 2 shorter and add a worked example.\",\n  \"files\": [\n    {\n      \"url\": \"https://cdn.example.com/course.pdf\",\n      \"files_role\": \"primary\"\n    }\n  ],\n  \"callback_url\": \"https://your-domain.com/xpilot/callback\",\n  \"callback_id\": \"order-1024\"\n}),\n});\nconst result = await response.json();\nif (!response.ok) throw new Error(JSON.stringify(result));\nconsole.log(result);"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os, json, requests\n\nresponse = requests.request(\n    \"POST\",\n    os.environ[\"XPILOT_API_BASE_URL\"] + \"/v1/video-agents/conversations/%3Cconversation_id%3E\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"XPILOT_API_KEY\"],\n        \"Content-Type\": \"application/json\",\n        \"Idempotency-Key\": \"lesson-request-001\",\n    },\n    json=json.loads(\"{\\\"prompt\\\":\\\"Make scene 2 shorter and add a worked example.\\\",\\\"files\\\":[{\\\"url\\\":\\\"https://cdn.example.com/course.pdf\\\",\\\"files_role\\\":\\\"primary\\\"}],\\\"callback_url\\\":\\\"https://your-domain.com/xpilot/callback\\\",\\\"callback_id\\\":\\\"order-1024\\\"}\"),\n    timeout=70,\n)\nprint(response.status_code, response.text)\nresponse.raise_for_status()"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "prompt": {
                    "type": "string",
                    "description": "The edit instruction or the answer to the assistant. Required unless outline_action=confirm; required with outline_action=revise to describe the change. Up to 20,000 characters.",
                    "example": "Make scene 2 shorter and add a worked example.",
                    "maxLength": 20000
                  },
                  "outline_action": {
                    "type": "string",
                    "description": "Only when next_action=confirm_outline. confirm continues with the outline; revise rewrites it using prompt.",
                    "enum": [
                      "confirm",
                      "revise"
                    ]
                  },
                  "files": {
                    "type": "array",
                    "description": "Up to 5 attachments. Each item uses either an owned asset_id or a caller-supplied public http(s) URL. Third-party URLs are downloaded and archived to the caller's storage before use. Item fields: asset_id or url (required), name (optional, ≤255), type (optional: document, image, video; inferred when omitted), and files_role (optional: primary or reference).",
                    "example": [
                      {
                        "url": "https://cdn.example.com/course.pdf",
                        "files_role": "primary"
                      }
                    ],
                    "items": {
                      "type": "object",
                      "properties": {
                        "asset_id": {
                          "oneOf": [
                            {
                              "type": "string"
                            },
                            {
                              "type": "integer"
                            }
                          ],
                          "description": "id returned by POST /v1/assets or list assets."
                        },
                        "url": {
                          "type": "string",
                          "description": "Caller-supplied public http(s) URL. Third-party content is archived before use."
                        },
                        "name": {
                          "type": "string",
                          "description": "Optional display name, up to 255 characters; inferred when omitted."
                        },
                        "type": {
                          "type": "string",
                          "description": "Optional; inferred from the file.",
                          "enum": [
                            "document",
                            "image",
                            "video"
                          ]
                        },
                        "files_role": {
                          "type": "string",
                          "description": "How this file shapes the video. primary: use it as main content and visual source. reference: use it only as background facts. Omit to let the agent decide.",
                          "enum": [
                            "primary",
                            "reference"
                          ]
                        }
                      }
                    }
                  },
                  "callback_url": {
                    "type": "string",
                    "description": "Optional webhook for this message only. Public HTTPS (port 443) up to 2,048 characters; private, loopback and http addresses return 400 invalid_webhook_url / unsafe_webhook_url. When the message reaches completed, paused, failed or stopped, X Pilot POSTs a video-agent.<status> event signed with the workspace callback secret (Developer console → Webhooks). Deliveries retry up to 6 times and are listed in the console.",
                    "example": "https://your-domain.com/xpilot/callback",
                    "maxLength": 2048
                  },
                  "callback_id": {
                    "type": "string",
                    "description": "Optional reference echoed back as data.callback_id in the callback, such as your order ID. Letters, digits, _ . : - up to 128 characters. Requires callback_url.",
                    "example": "order-1024",
                    "pattern": "^[\\w.:-]{1,128}$",
                    "maxLength": 128
                  }
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "delete-conversation",
        "tags": [
          "Video Agent"
        ],
        "summary": "Delete conversation",
        "description": "Deletes an owned conversation and stops its running message.",
        "parameters": [
          {
            "name": "conversation_id",
            "in": "path",
            "required": true,
            "description": "An owned video agent conversation ID.",
            "schema": {
              "type": "string",
              "description": "An owned video agent conversation ID."
            }
          }
        ],
        "x-required-scope": "video_agents:write",
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "conversation_id": "<conversation_id>",
                    "deleted": true
                  }
                }
              }
            }
          },
          "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>"
                }
              }
            }
          },
          "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>"
                }
              }
            }
          },
          "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 DELETE \\\n  --url \"$XPILOT_API_BASE_URL/v1/video-agents/conversations/%3Cconversation_id%3E\" \\\n  --header \"Authorization: Bearer $XPILOT_API_KEY\""
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const response = await fetch(process.env.XPILOT_API_BASE_URL + \"/v1/video-agents/conversations/%3Cconversation_id%3E\", {\n  method: \"DELETE\",\n  headers: {\n    Authorization: `Bearer ${process.env.XPILOT_API_KEY}`,\n  },\n});\nconst result = await response.json();\nif (!response.ok) throw new Error(JSON.stringify(result));\nconsole.log(result);"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os, json, requests\n\nresponse = requests.request(\n    \"DELETE\",\n    os.environ[\"XPILOT_API_BASE_URL\"] + \"/v1/video-agents/conversations/%3Cconversation_id%3E\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"XPILOT_API_KEY\"],\n    },\n    timeout=70,\n)\nprint(response.status_code, response.text)\nresponse.raise_for_status()"
          }
        ]
      }
    },
    "/v1/video-agents/conversations/{conversation_id}/messages": {
      "get": {
        "operationId": "list-messages",
        "tags": [
          "Video Agent"
        ],
        "summary": "List messages",
        "description": "Messages in order. Poll for status, next_action, outline, cost_credits and preview_video_url. status: queued, running, stopping, paused, completed, failed or stopped. next_action is set only when paused: confirm_outline (confirm or revise the outline) or reply (answer the assistant with a prompt). completed, paused, failed and stopped are terminal for that message. outline is present once an outline exists: title, total_scenes, estimated_duration_seconds, visual_style, confirmed and scenes [{index,title,intent,type,estimated_duration_seconds}].",
        "parameters": [
          {
            "name": "conversation_id",
            "in": "path",
            "required": true,
            "description": "An owned video agent conversation ID.",
            "schema": {
              "type": "string",
              "description": "An owned video agent conversation ID."
            }
          }
        ],
        "x-required-scope": "video_agents:read",
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "items": [
                      {
                        "conversation_id": "<conversation_id>",
                        "message_id": "<message_id>",
                        "status": "paused",
                        "next_action": "confirm_outline",
                        "outline": {
                          "title": "Solar energy in 3 minutes",
                          "total_scenes": 2,
                          "estimated_duration_seconds": 45,
                          "visual_style": "clean_lecture",
                          "confirmed": false,
                          "scenes": [
                            {
                              "index": 1,
                              "title": "Why the sun matters",
                              "intent": "Hook",
                              "type": "normal",
                              "estimated_duration_seconds": 20
                            },
                            {
                              "index": 2,
                              "title": "How panels convert light",
                              "intent": "Explain the photovoltaic effect",
                              "type": "normal",
                              "estimated_duration_seconds": 25
                            }
                          ]
                        },
                        "created_at": 1791849600,
                        "error": null,
                        "query": "Create a short lesson about solar energy.",
                        "answer": "...",
                        "message_files": [],
                        "preview_video_url": null,
                        "cost_credits": 12.5
                      }
                    ],
                    "total": 1
                  }
                }
              }
            }
          },
          "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>"
                }
              }
            }
          },
          "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>"
                }
              }
            }
          },
          "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 GET \\\n  --url \"$XPILOT_API_BASE_URL/v1/video-agents/conversations/%3Cconversation_id%3E/messages\" \\\n  --header \"Authorization: Bearer $XPILOT_API_KEY\""
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const response = await fetch(process.env.XPILOT_API_BASE_URL + \"/v1/video-agents/conversations/%3Cconversation_id%3E/messages\", {\n  method: \"GET\",\n  headers: {\n    Authorization: `Bearer ${process.env.XPILOT_API_KEY}`,\n  },\n});\nconst result = await response.json();\nif (!response.ok) throw new Error(JSON.stringify(result));\nconsole.log(result);"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os, json, requests\n\nresponse = requests.request(\n    \"GET\",\n    os.environ[\"XPILOT_API_BASE_URL\"] + \"/v1/video-agents/conversations/%3Cconversation_id%3E/messages\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"XPILOT_API_KEY\"],\n    },\n    timeout=70,\n)\nprint(response.status_code, response.text)\nresponse.raise_for_status()"
          }
        ]
      }
    },
    "/v1/video-agents/conversations/{conversation_id}/stop": {
      "post": {
        "operationId": "stop-conversation",
        "tags": [
          "Video Agent"
        ],
        "summary": "Stop conversation",
        "description": "Stops the running message (409 not_running when nothing runs). Poll list messages until stopped; cost already incurred may still be charged.",
        "parameters": [
          {
            "name": "conversation_id",
            "in": "path",
            "required": true,
            "description": "An owned video agent conversation ID.",
            "schema": {
              "type": "string",
              "description": "An owned video agent conversation ID."
            }
          }
        ],
        "x-required-scope": "video_agents:write",
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "conversation_id": "<conversation_id>",
                    "message_id": "<message_id>",
                    "status": "stopping",
                    "cost_credits": 12
                  }
                }
              }
            }
          },
          "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>"
                }
              }
            }
          },
          "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 \\\n  --url \"$XPILOT_API_BASE_URL/v1/video-agents/conversations/%3Cconversation_id%3E/stop\" \\\n  --header \"Authorization: Bearer $XPILOT_API_KEY\""
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const response = await fetch(process.env.XPILOT_API_BASE_URL + \"/v1/video-agents/conversations/%3Cconversation_id%3E/stop\", {\n  method: \"POST\",\n  headers: {\n    Authorization: `Bearer ${process.env.XPILOT_API_KEY}`,\n  },\n});\nconst result = await response.json();\nif (!response.ok) throw new Error(JSON.stringify(result));\nconsole.log(result);"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os, json, requests\n\nresponse = requests.request(\n    \"POST\",\n    os.environ[\"XPILOT_API_BASE_URL\"] + \"/v1/video-agents/conversations/%3Cconversation_id%3E/stop\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"XPILOT_API_KEY\"],\n    },\n    timeout=70,\n)\nprint(response.status_code, response.text)\nresponse.raise_for_status()"
          }
        ]
      }
    },
    "/v1/video-agents/conversations/{conversation_id}/renders": {
      "get": {
        "operationId": "list-renders",
        "tags": [
          "Renders"
        ],
        "summary": "List renders",
        "description": "MP4 exports of a conversation. status: queued, running, completed, failed or superseded. progress is 0–100 when available, otherwise null.",
        "parameters": [
          {
            "name": "conversation_id",
            "in": "path",
            "required": true,
            "description": "An owned video agent conversation ID.",
            "schema": {
              "type": "string",
              "description": "An owned video agent conversation ID."
            }
          }
        ],
        "x-required-scope": "video_agents:read",
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "items": [
                      {
                        "conversation_id": "<conversation_id>",
                        "render_id": "<render_id>",
                        "message_id": "<message_id>",
                        "status": "running",
                        "progress": 42,
                        "video_url": null,
                        "created_at": 1791849600
                      }
                    ],
                    "total": 1
                  }
                }
              }
            }
          },
          "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>"
                }
              }
            }
          },
          "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>"
                }
              }
            }
          },
          "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 GET \\\n  --url \"$XPILOT_API_BASE_URL/v1/video-agents/conversations/%3Cconversation_id%3E/renders\" \\\n  --header \"Authorization: Bearer $XPILOT_API_KEY\""
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const response = await fetch(process.env.XPILOT_API_BASE_URL + \"/v1/video-agents/conversations/%3Cconversation_id%3E/renders\", {\n  method: \"GET\",\n  headers: {\n    Authorization: `Bearer ${process.env.XPILOT_API_KEY}`,\n  },\n});\nconst result = await response.json();\nif (!response.ok) throw new Error(JSON.stringify(result));\nconsole.log(result);"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os, json, requests\n\nresponse = requests.request(\n    \"GET\",\n    os.environ[\"XPILOT_API_BASE_URL\"] + \"/v1/video-agents/conversations/%3Cconversation_id%3E/renders\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"XPILOT_API_KEY\"],\n    },\n    timeout=70,\n)\nprint(response.status_code, response.text)\nresponse.raise_for_status()"
          }
        ]
      },
      "post": {
        "operationId": "create-render",
        "tags": [
          "Renders"
        ],
        "summary": "Create render",
        "description": "Export an MP4 once preview_video_url is available (409 preview_not_ready otherwise). A preview is not an export. Retrying with the same Idempotency-Key returns the same render. Poll get render until completed.",
        "parameters": [
          {
            "name": "conversation_id",
            "in": "path",
            "required": true,
            "description": "An owned video agent conversation ID.",
            "schema": {
              "type": "string",
              "description": "An owned video agent conversation ID."
            }
          },
          {
            "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
            }
          }
        ],
        "x-required-scope": "video_agents:write",
        "responses": {
          "202": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "conversation_id": "<conversation_id>",
                    "render_id": "<render_id>",
                    "message_id": "<message_id>",
                    "status": "running",
                    "progress": 0,
                    "video_url": null,
                    "created_at": null
                  }
                }
              }
            }
          },
          "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 \\\n  --url \"$XPILOT_API_BASE_URL/v1/video-agents/conversations/%3Cconversation_id%3E/renders\" \\\n  --header \"Authorization: Bearer $XPILOT_API_KEY\" \\\n  --header 'Content-Type: application/json' \\\n  --header 'Idempotency-Key: lesson-request-001' \\\n  --data '{\"force\":false}'"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const response = await fetch(process.env.XPILOT_API_BASE_URL + \"/v1/video-agents/conversations/%3Cconversation_id%3E/renders\", {\n  method: \"POST\",\n  headers: {\n    Authorization: `Bearer ${process.env.XPILOT_API_KEY}`,\n    \"Content-Type\": \"application/json\",\n    \"Idempotency-Key\": \"lesson-request-001\",\n  },\n  body: JSON.stringify({\n  \"force\": false\n}),\n});\nconst result = await response.json();\nif (!response.ok) throw new Error(JSON.stringify(result));\nconsole.log(result);"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os, json, requests\n\nresponse = requests.request(\n    \"POST\",\n    os.environ[\"XPILOT_API_BASE_URL\"] + \"/v1/video-agents/conversations/%3Cconversation_id%3E/renders\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"XPILOT_API_KEY\"],\n        \"Content-Type\": \"application/json\",\n        \"Idempotency-Key\": \"lesson-request-001\",\n    },\n    json=json.loads(\"{\\\"force\\\":false}\"),\n    timeout=70,\n)\nprint(response.status_code, response.text)\nresponse.raise_for_status()"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "message_id": {
                    "type": "string",
                    "description": "Message to export. Default: the latest message with a preview."
                  },
                  "force": {
                    "type": "boolean",
                    "description": "Re-export even when a completed export exists.",
                    "default": false
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/video-agents/conversations/{conversation_id}/renders/{render_id}": {
      "get": {
        "operationId": "get-render",
        "tags": [
          "Renders"
        ],
        "summary": "Get render",
        "description": "Export status, progress (0–100 or null when unavailable), and video_url once completed.",
        "parameters": [
          {
            "name": "conversation_id",
            "in": "path",
            "required": true,
            "description": "An owned video agent conversation ID.",
            "schema": {
              "type": "string",
              "description": "An owned video agent conversation ID."
            }
          },
          {
            "name": "render_id",
            "in": "path",
            "required": true,
            "description": "Export render ID.",
            "schema": {
              "type": "string",
              "description": "Export render ID."
            }
          }
        ],
        "x-required-scope": "video_agents:read",
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "conversation_id": "<conversation_id>",
                    "render_id": "<render_id>",
                    "message_id": "<message_id>",
                    "status": "completed",
                    "progress": 100,
                    "video_url": "<mp4_url>",
                    "created_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>"
                }
              }
            }
          },
          "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>"
                }
              }
            }
          },
          "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 GET \\\n  --url \"$XPILOT_API_BASE_URL/v1/video-agents/conversations/%3Cconversation_id%3E/renders/%3Crender_id%3E\" \\\n  --header \"Authorization: Bearer $XPILOT_API_KEY\""
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const response = await fetch(process.env.XPILOT_API_BASE_URL + \"/v1/video-agents/conversations/%3Cconversation_id%3E/renders/%3Crender_id%3E\", {\n  method: \"GET\",\n  headers: {\n    Authorization: `Bearer ${process.env.XPILOT_API_KEY}`,\n  },\n});\nconst result = await response.json();\nif (!response.ok) throw new Error(JSON.stringify(result));\nconsole.log(result);"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os, json, requests\n\nresponse = requests.request(\n    \"GET\",\n    os.environ[\"XPILOT_API_BASE_URL\"] + \"/v1/video-agents/conversations/%3Cconversation_id%3E/renders/%3Crender_id%3E\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"XPILOT_API_KEY\"],\n    },\n    timeout=70,\n)\nprint(response.status_code, response.text)\nresponse.raise_for_status()"
          }
        ]
      },
      "delete": {
        "operationId": "delete-render",
        "tags": [
          "Renders"
        ],
        "summary": "Delete render",
        "description": "Delete an export render record.",
        "parameters": [
          {
            "name": "conversation_id",
            "in": "path",
            "required": true,
            "description": "An owned video agent conversation ID.",
            "schema": {
              "type": "string",
              "description": "An owned video agent conversation ID."
            }
          },
          {
            "name": "render_id",
            "in": "path",
            "required": true,
            "description": "Export render ID.",
            "schema": {
              "type": "string",
              "description": "Export render ID."
            }
          }
        ],
        "x-required-scope": "video_agents:write",
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "conversation_id": "<conversation_id>",
                    "render_id": "<render_id>",
                    "deleted": true
                  }
                }
              }
            }
          },
          "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>"
                }
              }
            }
          },
          "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>"
                }
              }
            }
          },
          "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 DELETE \\\n  --url \"$XPILOT_API_BASE_URL/v1/video-agents/conversations/%3Cconversation_id%3E/renders/%3Crender_id%3E\" \\\n  --header \"Authorization: Bearer $XPILOT_API_KEY\""
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const response = await fetch(process.env.XPILOT_API_BASE_URL + \"/v1/video-agents/conversations/%3Cconversation_id%3E/renders/%3Crender_id%3E\", {\n  method: \"DELETE\",\n  headers: {\n    Authorization: `Bearer ${process.env.XPILOT_API_KEY}`,\n  },\n});\nconst result = await response.json();\nif (!response.ok) throw new Error(JSON.stringify(result));\nconsole.log(result);"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os, json, requests\n\nresponse = requests.request(\n    \"DELETE\",\n    os.environ[\"XPILOT_API_BASE_URL\"] + \"/v1/video-agents/conversations/%3Cconversation_id%3E/renders/%3Crender_id%3E\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"XPILOT_API_KEY\"],\n    },\n    timeout=70,\n)\nprint(response.status_code, response.text)\nresponse.raise_for_status()"
          }
        ]
      }
    },
    "/v1/brand-kits": {
      "get": {
        "operationId": "list-brand-kits",
        "tags": [
          "Brand kits"
        ],
        "summary": "List brand kits",
        "description": "Owned brand kits. Pass an id as video_config.brand_kit_id.",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Results per page, from 1 to 100.",
            "schema": {
              "type": "integer",
              "description": "Results per page, from 1 to 100.",
              "default": 20,
              "minimum": 1,
              "maximum": 100
            }
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "description": "Number of items to skip.",
            "schema": {
              "type": "integer",
              "description": "Number of items to skip.",
              "default": 0,
              "minimum": 0,
              "maximum": 1000
            }
          }
        ],
        "x-required-scope": "brand_kits:read",
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "items": [
                      {
                        "id": 1,
                        "brand_name": "Acme",
                        "brand_logo": "<asset_url>",
                        "content_style_description": "Friendly and concise.",
                        "theme_color": {
                          "primary": "#2563eb",
                          "accent": "#f97316",
                          "background": "#ffffff",
                          "text": "#0f172a"
                        },
                        "created_at": 1791849600,
                        "updated_at": 1791849600
                      }
                    ],
                    "total": 1,
                    "limit": 20,
                    "offset": 0
                  }
                }
              }
            }
          },
          "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>"
                }
              }
            }
          },
          "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>"
                }
              }
            }
          },
          "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 GET \\\n  --url \"$XPILOT_API_BASE_URL/v1/brand-kits?limit=20&offset=0\" \\\n  --header \"Authorization: Bearer $XPILOT_API_KEY\""
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const response = await fetch(process.env.XPILOT_API_BASE_URL + \"/v1/brand-kits?limit=20&offset=0\", {\n  method: \"GET\",\n  headers: {\n    Authorization: `Bearer ${process.env.XPILOT_API_KEY}`,\n  },\n});\nconst result = await response.json();\nif (!response.ok) throw new Error(JSON.stringify(result));\nconsole.log(result);"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os, json, requests\n\nresponse = requests.request(\n    \"GET\",\n    os.environ[\"XPILOT_API_BASE_URL\"] + \"/v1/brand-kits?limit=20&offset=0\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"XPILOT_API_KEY\"],\n    },\n    timeout=70,\n)\nprint(response.status_code, response.text)\nresponse.raise_for_status()"
          }
        ]
      },
      "post": {
        "operationId": "create-brand-kit",
        "tags": [
          "Brand kits"
        ],
        "summary": "Create brand kit",
        "description": "Create a brand kit referenced by video_config.brand_kit_id. Unknown fields return 400.",
        "parameters": [],
        "x-required-scope": "brand_kits:write",
        "responses": {
          "201": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "id": 1,
                    "brand_name": "Acme",
                    "brand_logo": "<asset_url>",
                    "content_style_description": "Friendly and concise.",
                    "theme_color": {
                      "primary": "#2563eb",
                      "accent": "#f97316",
                      "background": "#ffffff",
                      "text": "#0f172a"
                    },
                    "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>"
                }
              }
            }
          },
          "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>"
                }
              }
            }
          },
          "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 \\\n  --url \"$XPILOT_API_BASE_URL/v1/brand-kits\" \\\n  --header \"Authorization: Bearer $XPILOT_API_KEY\" \\\n  --header 'Content-Type: application/json' \\\n  --data '{\"brand_name\":\"Acme\",\"theme_color\":{\"primary\":\"#2563eb\",\"accent\":\"#f97316\"}}'"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const response = await fetch(process.env.XPILOT_API_BASE_URL + \"/v1/brand-kits\", {\n  method: \"POST\",\n  headers: {\n    Authorization: `Bearer ${process.env.XPILOT_API_KEY}`,\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({\n  \"brand_name\": \"Acme\",\n  \"theme_color\": {\n    \"primary\": \"#2563eb\",\n    \"accent\": \"#f97316\"\n  }\n}),\n});\nconst result = await response.json();\nif (!response.ok) throw new Error(JSON.stringify(result));\nconsole.log(result);"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os, json, requests\n\nresponse = requests.request(\n    \"POST\",\n    os.environ[\"XPILOT_API_BASE_URL\"] + \"/v1/brand-kits\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"XPILOT_API_KEY\"],\n        \"Content-Type\": \"application/json\",\n    },\n    json=json.loads(\"{\\\"brand_name\\\":\\\"Acme\\\",\\\"theme_color\\\":{\\\"primary\\\":\\\"#2563eb\\\",\\\"accent\\\":\\\"#f97316\\\"}}\"),\n    timeout=70,\n)\nprint(response.status_code, response.text)\nresponse.raise_for_status()"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "brand_name": {
                    "type": "string",
                    "description": "Brand name, 1–120 characters.",
                    "example": "Acme",
                    "maxLength": 120
                  },
                  "brand_logo": {
                    "type": "string",
                    "description": "http(s) logo URL, preferably returned by POST /v1/assets.",
                    "maxLength": 2048
                  },
                  "content_style_description": {
                    "type": "string",
                    "description": "Tone and style guidance for scripts, up to 20,000 characters.",
                    "maxLength": 20000
                  },
                  "theme_color": {
                    "type": "object",
                    "description": "Theme colors. Keys: primary, secondary, accent, background, text, textSecondary, success, warning, error, surface, surfaceLight, shadow. Values: #rgb, #rrggbb, #rrggbbaa or rgb()/rgba(); null clears a color.",
                    "example": {
                      "primary": "#2563eb",
                      "accent": "#f97316"
                    },
                    "properties": {
                      "primary": {
                        "type": "string",
                        "nullable": true,
                        "description": "primary color."
                      },
                      "secondary": {
                        "type": "string",
                        "nullable": true,
                        "description": "secondary color."
                      },
                      "accent": {
                        "type": "string",
                        "nullable": true,
                        "description": "accent color."
                      },
                      "background": {
                        "type": "string",
                        "nullable": true,
                        "description": "background color."
                      },
                      "text": {
                        "type": "string",
                        "nullable": true,
                        "description": "text color."
                      },
                      "textSecondary": {
                        "type": "string",
                        "nullable": true,
                        "description": "textSecondary color."
                      },
                      "success": {
                        "type": "string",
                        "nullable": true,
                        "description": "success color."
                      },
                      "warning": {
                        "type": "string",
                        "nullable": true,
                        "description": "warning color."
                      },
                      "error": {
                        "type": "string",
                        "nullable": true,
                        "description": "error color."
                      },
                      "surface": {
                        "type": "string",
                        "nullable": true,
                        "description": "surface color."
                      },
                      "surfaceLight": {
                        "type": "string",
                        "nullable": true,
                        "description": "surfaceLight color."
                      },
                      "shadow": {
                        "type": "string",
                        "nullable": true,
                        "description": "shadow color."
                      }
                    }
                  }
                },
                "required": [
                  "brand_name"
                ]
              }
            }
          }
        }
      }
    },
    "/v1/brand-kits/{brand_kit_id}": {
      "get": {
        "operationId": "get-brand-kit",
        "tags": [
          "Brand kits"
        ],
        "summary": "Get brand kit",
        "description": "Read an owned brand kit.",
        "parameters": [
          {
            "name": "brand_kit_id",
            "in": "path",
            "required": true,
            "description": "An owned brand kit ID.",
            "schema": {
              "type": "string",
              "description": "An owned brand kit ID."
            }
          }
        ],
        "x-required-scope": "brand_kits:read",
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "id": 1,
                    "brand_name": "Acme",
                    "brand_logo": "<asset_url>",
                    "content_style_description": "Friendly and concise.",
                    "theme_color": {
                      "primary": "#2563eb",
                      "accent": "#f97316",
                      "background": "#ffffff",
                      "text": "#0f172a"
                    },
                    "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>"
                }
              }
            }
          },
          "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>"
                }
              }
            }
          },
          "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 GET \\\n  --url \"$XPILOT_API_BASE_URL/v1/brand-kits/%3Cbrand_kit_id%3E\" \\\n  --header \"Authorization: Bearer $XPILOT_API_KEY\""
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const response = await fetch(process.env.XPILOT_API_BASE_URL + \"/v1/brand-kits/%3Cbrand_kit_id%3E\", {\n  method: \"GET\",\n  headers: {\n    Authorization: `Bearer ${process.env.XPILOT_API_KEY}`,\n  },\n});\nconst result = await response.json();\nif (!response.ok) throw new Error(JSON.stringify(result));\nconsole.log(result);"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os, json, requests\n\nresponse = requests.request(\n    \"GET\",\n    os.environ[\"XPILOT_API_BASE_URL\"] + \"/v1/brand-kits/%3Cbrand_kit_id%3E\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"XPILOT_API_KEY\"],\n    },\n    timeout=70,\n)\nprint(response.status_code, response.text)\nresponse.raise_for_status()"
          }
        ]
      },
      "put": {
        "operationId": "update-brand-kit",
        "tags": [
          "Brand kits"
        ],
        "summary": "Update brand kit",
        "description": "Update fields of an owned brand kit; omitted fields stay unchanged.",
        "parameters": [
          {
            "name": "brand_kit_id",
            "in": "path",
            "required": true,
            "description": "An owned brand kit ID.",
            "schema": {
              "type": "string",
              "description": "An owned brand kit ID."
            }
          }
        ],
        "x-required-scope": "brand_kits:write",
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "id": 1,
                    "brand_name": "Acme",
                    "brand_logo": "<asset_url>",
                    "content_style_description": "Friendly and concise.",
                    "theme_color": {
                      "primary": "#2563eb",
                      "accent": "#f97316",
                      "background": "#ffffff",
                      "text": "#0f172a"
                    },
                    "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>"
                }
              }
            }
          },
          "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>"
                }
              }
            }
          },
          "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 PUT \\\n  --url \"$XPILOT_API_BASE_URL/v1/brand-kits/%3Cbrand_kit_id%3E\" \\\n  --header \"Authorization: Bearer $XPILOT_API_KEY\" \\\n  --header 'Content-Type: application/json' \\\n  --data '{\"brand_name\":\"Acme\",\"theme_color\":{\"primary\":\"#2563eb\",\"accent\":\"#f97316\"}}'"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const response = await fetch(process.env.XPILOT_API_BASE_URL + \"/v1/brand-kits/%3Cbrand_kit_id%3E\", {\n  method: \"PUT\",\n  headers: {\n    Authorization: `Bearer ${process.env.XPILOT_API_KEY}`,\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({\n  \"brand_name\": \"Acme\",\n  \"theme_color\": {\n    \"primary\": \"#2563eb\",\n    \"accent\": \"#f97316\"\n  }\n}),\n});\nconst result = await response.json();\nif (!response.ok) throw new Error(JSON.stringify(result));\nconsole.log(result);"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os, json, requests\n\nresponse = requests.request(\n    \"PUT\",\n    os.environ[\"XPILOT_API_BASE_URL\"] + \"/v1/brand-kits/%3Cbrand_kit_id%3E\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"XPILOT_API_KEY\"],\n        \"Content-Type\": \"application/json\",\n    },\n    json=json.loads(\"{\\\"brand_name\\\":\\\"Acme\\\",\\\"theme_color\\\":{\\\"primary\\\":\\\"#2563eb\\\",\\\"accent\\\":\\\"#f97316\\\"}}\"),\n    timeout=70,\n)\nprint(response.status_code, response.text)\nresponse.raise_for_status()"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "brand_name": {
                    "type": "string",
                    "description": "Brand name, 1–120 characters.",
                    "example": "Acme",
                    "maxLength": 120
                  },
                  "brand_logo": {
                    "type": "string",
                    "description": "http(s) logo URL, preferably returned by POST /v1/assets.",
                    "maxLength": 2048
                  },
                  "content_style_description": {
                    "type": "string",
                    "description": "Tone and style guidance for scripts, up to 20,000 characters.",
                    "maxLength": 20000
                  },
                  "theme_color": {
                    "type": "object",
                    "description": "Theme colors. Keys: primary, secondary, accent, background, text, textSecondary, success, warning, error, surface, surfaceLight, shadow. Values: #rgb, #rrggbb, #rrggbbaa or rgb()/rgba(); null clears a color.",
                    "example": {
                      "primary": "#2563eb",
                      "accent": "#f97316"
                    },
                    "properties": {
                      "primary": {
                        "type": "string",
                        "nullable": true,
                        "description": "primary color."
                      },
                      "secondary": {
                        "type": "string",
                        "nullable": true,
                        "description": "secondary color."
                      },
                      "accent": {
                        "type": "string",
                        "nullable": true,
                        "description": "accent color."
                      },
                      "background": {
                        "type": "string",
                        "nullable": true,
                        "description": "background color."
                      },
                      "text": {
                        "type": "string",
                        "nullable": true,
                        "description": "text color."
                      },
                      "textSecondary": {
                        "type": "string",
                        "nullable": true,
                        "description": "textSecondary color."
                      },
                      "success": {
                        "type": "string",
                        "nullable": true,
                        "description": "success color."
                      },
                      "warning": {
                        "type": "string",
                        "nullable": true,
                        "description": "warning color."
                      },
                      "error": {
                        "type": "string",
                        "nullable": true,
                        "description": "error color."
                      },
                      "surface": {
                        "type": "string",
                        "nullable": true,
                        "description": "surface color."
                      },
                      "surfaceLight": {
                        "type": "string",
                        "nullable": true,
                        "description": "surfaceLight color."
                      },
                      "shadow": {
                        "type": "string",
                        "nullable": true,
                        "description": "shadow color."
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "delete-brand-kit",
        "tags": [
          "Brand kits"
        ],
        "summary": "Delete brand kit",
        "description": "Delete an owned brand kit.",
        "parameters": [
          {
            "name": "brand_kit_id",
            "in": "path",
            "required": true,
            "description": "An owned brand kit ID.",
            "schema": {
              "type": "string",
              "description": "An owned brand kit ID."
            }
          }
        ],
        "x-required-scope": "brand_kits:write",
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "brand_kit_id": "<brand_kit_id>",
                    "deleted": true
                  }
                }
              }
            }
          },
          "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>"
                }
              }
            }
          },
          "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>"
                }
              }
            }
          },
          "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 DELETE \\\n  --url \"$XPILOT_API_BASE_URL/v1/brand-kits/%3Cbrand_kit_id%3E\" \\\n  --header \"Authorization: Bearer $XPILOT_API_KEY\""
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const response = await fetch(process.env.XPILOT_API_BASE_URL + \"/v1/brand-kits/%3Cbrand_kit_id%3E\", {\n  method: \"DELETE\",\n  headers: {\n    Authorization: `Bearer ${process.env.XPILOT_API_KEY}`,\n  },\n});\nconst result = await response.json();\nif (!response.ok) throw new Error(JSON.stringify(result));\nconsole.log(result);"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os, json, requests\n\nresponse = requests.request(\n    \"DELETE\",\n    os.environ[\"XPILOT_API_BASE_URL\"] + \"/v1/brand-kits/%3Cbrand_kit_id%3E\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"XPILOT_API_KEY\"],\n    },\n    timeout=70,\n)\nprint(response.status_code, response.text)\nresponse.raise_for_status()"
          }
        ]
      }
    },
    "/v1/account/credits": {
      "get": {
        "operationId": "check-credits",
        "tags": [
          "Account & capacity"
        ],
        "summary": "Check credits",
        "description": "The API and platform share the same wallet and the same credit conversion as the app. Recharge in the owner console.",
        "parameters": [],
        "x-required-scope": "account:read",
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "balance_credits": 1000,
                    "base_credits": 0,
                    "monthly_free_credits": 0,
                    "plan": "pro",
                    "shared_with_platform": true,
                    "payment_mode": "stripe_live"
                  }
                }
              }
            }
          },
          "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>"
                }
              }
            }
          },
          "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>"
                }
              }
            }
          },
          "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 GET \\\n  --url \"$XPILOT_API_BASE_URL/v1/account/credits\" \\\n  --header \"Authorization: Bearer $XPILOT_API_KEY\""
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const response = await fetch(process.env.XPILOT_API_BASE_URL + \"/v1/account/credits\", {\n  method: \"GET\",\n  headers: {\n    Authorization: `Bearer ${process.env.XPILOT_API_KEY}`,\n  },\n});\nconst result = await response.json();\nif (!response.ok) throw new Error(JSON.stringify(result));\nconsole.log(result);"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os, json, requests\n\nresponse = requests.request(\n    \"GET\",\n    os.environ[\"XPILOT_API_BASE_URL\"] + \"/v1/account/credits\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"XPILOT_API_KEY\"],\n    },\n    timeout=70,\n)\nprint(response.status_code, response.text)\nresponse.raise_for_status()"
          }
        ]
      }
    },
    "/v1/account/capacity": {
      "get": {
        "operationId": "check-capacity",
        "tags": [
          "Account & capacity"
        ],
        "summary": "Check capacity & budget",
        "description": "Check available concurrency and the credential monthly budget before starting a paid run.",
        "parameters": [],
        "x-required-scope": "account:read",
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "rpm": 60,
                    "concurrency": 2,
                    "active_tasks": 0,
                    "available_slots": 2,
                    "monthly_budget_credits": 1000,
                    "spent_credits": 0,
                    "reserved_credits": 0,
                    "remaining_budget_credits": 1000
                  }
                }
              }
            }
          },
          "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>"
                }
              }
            }
          },
          "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>"
                }
              }
            }
          },
          "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 GET \\\n  --url \"$XPILOT_API_BASE_URL/v1/account/capacity\" \\\n  --header \"Authorization: Bearer $XPILOT_API_KEY\""
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const response = await fetch(process.env.XPILOT_API_BASE_URL + \"/v1/account/capacity\", {\n  method: \"GET\",\n  headers: {\n    Authorization: `Bearer ${process.env.XPILOT_API_KEY}`,\n  },\n});\nconst result = await response.json();\nif (!response.ok) throw new Error(JSON.stringify(result));\nconsole.log(result);"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os, json, requests\n\nresponse = requests.request(\n    \"GET\",\n    os.environ[\"XPILOT_API_BASE_URL\"] + \"/v1/account/capacity\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"XPILOT_API_KEY\"],\n    },\n    timeout=70,\n)\nprint(response.status_code, response.text)\nresponse.raise_for_status()"
          }
        ]
      }
    },
    "/v1/assets": {
      "get": {
        "operationId": "list-assets",
        "tags": [
          "Assets"
        ],
        "summary": "List owned assets",
        "description": "Files uploaded to this account, newest first. Upload with POST /v1/assets.",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Results per page, from 1 to 100.",
            "schema": {
              "type": "integer",
              "description": "Results per page, from 1 to 100.",
              "default": 20,
              "minimum": 1,
              "maximum": 100
            }
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "description": "Number of items to skip.",
            "schema": {
              "type": "integer",
              "description": "Number of items to skip.",
              "default": 0,
              "minimum": 0
            }
          }
        ],
        "x-required-scope": "assets:read",
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "items": [
                      {
                        "id": 1,
                        "name": "lesson.pdf",
                        "url": "<asset_url>",
                        "mimetype": "application/pdf",
                        "created_at": 1791849600,
                        "updated_at": 1791849600
                      }
                    ],
                    "total": 1,
                    "limit": 20,
                    "offset": 0
                  }
                }
              }
            }
          },
          "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>"
                }
              }
            }
          },
          "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>"
                }
              }
            }
          },
          "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 GET \\\n  --url \"$XPILOT_API_BASE_URL/v1/assets?limit=20&offset=0\" \\\n  --header \"Authorization: Bearer $XPILOT_API_KEY\""
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const response = await fetch(process.env.XPILOT_API_BASE_URL + \"/v1/assets?limit=20&offset=0\", {\n  method: \"GET\",\n  headers: {\n    Authorization: `Bearer ${process.env.XPILOT_API_KEY}`,\n  },\n});\nconst result = await response.json();\nif (!response.ok) throw new Error(JSON.stringify(result));\nconsole.log(result);"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os, json, requests\n\nresponse = requests.request(\n    \"GET\",\n    os.environ[\"XPILOT_API_BASE_URL\"] + \"/v1/assets?limit=20&offset=0\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"XPILOT_API_KEY\"],\n    },\n    timeout=70,\n)\nprint(response.status_code, response.text)\nresponse.raise_for_status()"
          }
        ]
      },
      "post": {
        "operationId": "upload-assets",
        "tags": [
          "Assets"
        ],
        "summary": "Upload assets",
        "description": "Multipart upload, field name files, up to 5 files per request. Limits per file: documents (pdf, docx, pptx, md, markdown, mdx) 10 MB; images (jpg, jpeg, png, gif, webp, svg) 10 MB; audio (wav, mp3, m4a, aac, ogg, flac) 20 MB; video (mp4, webm, mov) 60 MB. Empty files are rejected. Errors return 400 invalid_parameter with reason (too_many, unsupported_type, empty, too_large), file and max_mb. Returned ids and urls are reused by conversations, voice cloning and avatar creation.",
        "parameters": [],
        "x-required-scope": "assets:write",
        "responses": {
          "201": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "data": [
                    {
                      "id": 1,
                      "name": "solar.pdf",
                      "url": "<asset_url>",
                      "mimetype": "application/pdf",
                      "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>"
                }
              }
            }
          },
          "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>"
                }
              }
            }
          },
          "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 \\\n  --url \"$XPILOT_API_BASE_URL/v1/assets\" \\\n  --header \"Authorization: Bearer $XPILOT_API_KEY\" \\\n  --form 'files=@\"solar.pdf\"'"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const form = new FormData();\nform.append(\"files\", /* File|Blob */ solarPdf, \"solar.pdf\");\nconst response = await fetch(process.env.XPILOT_API_BASE_URL + \"/v1/assets\", {\n  method: \"POST\",\n  headers: { Authorization: `Bearer ${process.env.XPILOT_API_KEY}` },\n  body: form,\n});\nconst result = await response.json();\nif (!response.ok) throw new Error(JSON.stringify(result));\nconsole.log(result);"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os, requests\n\nresponse = requests.post(\n    os.environ[\"XPILOT_API_BASE_URL\"] + \"/v1/assets\",\n    headers={\"Authorization\": \"Bearer \" + os.environ[\"XPILOT_API_KEY\"]},\n    files=[(\"files\", (\"solar.pdf\", open(\"solar.pdf\", \"rb\"), \"application/pdf\"))],\n    timeout=70,\n)\nprint(response.status_code, response.text)\nresponse.raise_for_status()"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "properties": {
                  "files": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "format": "binary"
                    },
                    "description": "Multipart form field. Repeat files for multiple uploads (max 5).",
                    "example": "@solar.pdf"
                  }
                },
                "required": [
                  "files"
                ]
              }
            }
          }
        }
      }
    },
    "/v1/avatars": {
      "get": {
        "operationId": "list-avatars",
        "tags": [
          "Avatars"
        ],
        "summary": "List owned avatars",
        "description": "Owned avatars and quota. Only avatars with selectable=true can be used as video_config.avatar_id.",
        "parameters": [],
        "x-required-scope": "avatars:read",
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "items": [
                      {
                        "id": 11,
                        "name": "Instructor",
                        "avatar_type": "human_video",
                        "status": "ready",
                        "training_status": "ready",
                        "preview_status": "ready",
                        "selectable": true,
                        "stage": null,
                        "preview_image_url": "<image_url>",
                        "preview_video_url": "<video_url>",
                        "error": null,
                        "created_at": 1791849600,
                        "updated_at": 1791849680
                      }
                    ],
                    "total": 1,
                    "quota": {
                      "used": 1,
                      "limit": 6
                    }
                  }
                }
              }
            }
          },
          "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>"
                }
              }
            }
          },
          "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>"
                }
              }
            }
          },
          "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 GET \\\n  --url \"$XPILOT_API_BASE_URL/v1/avatars\" \\\n  --header \"Authorization: Bearer $XPILOT_API_KEY\""
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const response = await fetch(process.env.XPILOT_API_BASE_URL + \"/v1/avatars\", {\n  method: \"GET\",\n  headers: {\n    Authorization: `Bearer ${process.env.XPILOT_API_KEY}`,\n  },\n});\nconst result = await response.json();\nif (!response.ok) throw new Error(JSON.stringify(result));\nconsole.log(result);"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os, json, requests\n\nresponse = requests.request(\n    \"GET\",\n    os.environ[\"XPILOT_API_BASE_URL\"] + \"/v1/avatars\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"XPILOT_API_KEY\"],\n    },\n    timeout=70,\n)\nprint(response.status_code, response.text)\nresponse.raise_for_status()"
          }
        ]
      },
      "post": {
        "operationId": "create-avatar",
        "tags": [
          "Avatars"
        ],
        "summary": "create avatar",
        "description": "Create an avatar from an owned asset_id or a public http(s) image/video URL. Third-party URLs are downloaded and archived to the caller’s owned storage before training. Requires platform entitlement. Poll get_avatar for preview_image_url and preview_video_url, or receive avatar.completed / avatar.failed through callback_url or a webhook subscription. Reuse Idempotency-Key on retry; never retrain automatically.",
        "parameters": [
          {
            "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
            }
          }
        ],
        "x-required-scope": "avatars:write",
        "responses": {
          "202": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "id": "<avatar_id>",
                    "name": "Presenter",
                    "avatar_type": "human_video",
                    "status": "generating",
                    "training_status": "pending",
                    "preview_status": "not_requested",
                    "selectable": false,
                    "stage": "provider_processing",
                    "preview_image_url": null,
                    "preview_video_url": 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>"
                }
              }
            }
          },
          "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>"
                }
              }
            }
          },
          "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 \\\n  --url \"$XPILOT_API_BASE_URL/v1/avatars\" \\\n  --header \"Authorization: Bearer $XPILOT_API_KEY\" \\\n  --header 'Content-Type: application/json' \\\n  --header 'Idempotency-Key: lesson-request-001' \\\n  --data '{\"name\":\"<name>\",\"avatar_type\":\"human_video\",\"video_url\":\"https://cdn.example.com/training.mp4\"}'"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const response = await fetch(process.env.XPILOT_API_BASE_URL + \"/v1/avatars\", {\n  method: \"POST\",\n  headers: {\n    Authorization: `Bearer ${process.env.XPILOT_API_KEY}`,\n    \"Content-Type\": \"application/json\",\n    \"Idempotency-Key\": \"lesson-request-001\",\n  },\n  body: JSON.stringify({\n  \"name\": \"<name>\",\n  \"avatar_type\": \"human_video\",\n  \"video_url\": \"https://cdn.example.com/training.mp4\"\n}),\n});\nconst result = await response.json();\nif (!response.ok) throw new Error(JSON.stringify(result));\nconsole.log(result);"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os, json, requests\n\nresponse = requests.request(\n    \"POST\",\n    os.environ[\"XPILOT_API_BASE_URL\"] + \"/v1/avatars\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"XPILOT_API_KEY\"],\n        \"Content-Type\": \"application/json\",\n        \"Idempotency-Key\": \"lesson-request-001\",\n    },\n    json=json.loads(\"{\\\"name\\\":\\\"<name>\\\",\\\"avatar_type\\\":\\\"human_video\\\",\\\"video_url\\\":\\\"https://cdn.example.com/training.mp4\\\"}\"),\n    timeout=70,\n)\nprint(response.status_code, response.text)\nresponse.raise_for_status()"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "Avatar name.",
                    "maxLength": 80
                  },
                  "avatar_type": {
                    "type": "string",
                    "description": "Training source.",
                    "enum": [
                      "human_video",
                      "virtual_character"
                    ]
                  },
                  "asset_id": {
                    "type": "string",
                    "description": "Owned asset ID returned by POST /v1/assets. human_video uses a video asset; virtual_character uses an image asset."
                  },
                  "image_url": {
                    "type": "string",
                    "description": "Public http(s) image URL. The backend archives third-party content to your owned storage before training. Use this or asset_id for virtual_character."
                  },
                  "video_url": {
                    "type": "string",
                    "description": "Public http(s) training video URL. The backend archives third-party content to your owned storage before training. Use this or asset_id for human_video."
                  },
                  "gender": {
                    "type": "string",
                    "description": "Required for image avatars.",
                    "enum": [
                      "Male",
                      "Female"
                    ]
                  },
                  "callback_url": {
                    "type": "string",
                    "description": "Optional public HTTPS URL notified once with avatar.completed or avatar.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
                  }
                },
                "required": [
                  "name",
                  "avatar_type"
                ]
              }
            }
          }
        }
      }
    },
    "/v1/voices": {
      "get": {
        "operationId": "list-voices",
        "tags": [
          "Voices & audio"
        ],
        "summary": "list voices",
        "description": "Find public catalog voices or your own clones. Choose voice_id from the returned items; never guess provider identifiers. Use samples on list/detail items for fixed audition clips.",
        "parameters": [
          {
            "name": "voice_version",
            "in": "query",
            "required": false,
            "description": "Voice I (1, default) or Voice II (2) for the public catalog. Private clone listings include both versions.",
            "schema": {
              "type": "integer",
              "description": "Voice I (1, default) or Voice II (2) for the public catalog. Private clone listings include both versions.",
              "enum": [
                1,
                2
              ],
              "default": 1
            }
          },
          {
            "name": "type",
            "in": "query",
            "required": false,
            "description": "public shared catalog or private owned clones.",
            "schema": {
              "type": "string",
              "description": "public shared catalog or private owned clones.",
              "enum": [
                "public",
                "private"
              ],
              "default": "public"
            }
          },
          {
            "name": "language",
            "in": "query",
            "required": false,
            "description": "Optional language filter aligned with the platform catalog.",
            "schema": {
              "type": "string",
              "description": "Optional language filter aligned with the platform catalog."
            }
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Page, starting at 1.",
            "schema": {
              "type": "integer",
              "description": "Page, starting at 1.",
              "minimum": 1
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Items per page, up to 100.",
            "schema": {
              "type": "integer",
              "description": "Items per page, up to 100.",
              "minimum": 1,
              "maximum": 100
            }
          }
        ],
        "x-required-scope": "voices:read",
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "items": [],
                    "page": 1,
                    "total": 0
                  }
                }
              }
            }
          },
          "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>"
                }
              }
            }
          },
          "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>"
                }
              }
            }
          },
          "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 GET \\\n  --url \"$XPILOT_API_BASE_URL/v1/voices?voice_version=1&type=public\" \\\n  --header \"Authorization: Bearer $XPILOT_API_KEY\""
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const response = await fetch(process.env.XPILOT_API_BASE_URL + \"/v1/voices?voice_version=1&type=public\", {\n  method: \"GET\",\n  headers: {\n    Authorization: `Bearer ${process.env.XPILOT_API_KEY}`,\n  },\n});\nconst result = await response.json();\nif (!response.ok) throw new Error(JSON.stringify(result));\nconsole.log(result);"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os, json, requests\n\nresponse = requests.request(\n    \"GET\",\n    os.environ[\"XPILOT_API_BASE_URL\"] + \"/v1/voices?voice_version=1&type=public\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"XPILOT_API_KEY\"],\n    },\n    timeout=70,\n)\nprint(response.status_code, response.text)\nresponse.raise_for_status()"
          }
        ]
      }
    },
    "/v1/voices/{voice_id}": {
      "get": {
        "operationId": "get-voice",
        "tags": [
          "Voices & audio"
        ],
        "summary": "get voice",
        "description": "Read a public or owned voice, including readiness and samples. Private voices from another account are unavailable. Poll this after clone_voice: a Voice II clone moves from training to trained (selectable=true) or failed.",
        "parameters": [
          {
            "name": "voice_id",
            "in": "path",
            "required": true,
            "description": "Catalog or owned clone voice ID.",
            "schema": {
              "type": "string",
              "description": "Catalog or owned clone voice ID."
            }
          },
          {
            "name": "voice_version",
            "in": "query",
            "required": false,
            "description": "Voice version of the voice: Voice I (1, default) or Voice II (2).",
            "schema": {
              "type": "integer",
              "description": "Voice version of the voice: Voice I (1, default) or Voice II (2).",
              "enum": [
                1,
                2
              ],
              "default": 1
            }
          }
        ],
        "x-required-scope": "voices:read",
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "_id": "<voice_id>",
                    "title": "Instructor",
                    "voice_version": 1,
                    "state": "trained",
                    "samples": [
                      {
                        "audio": "<sample_url>"
                      }
                    ]
                  }
                }
              }
            }
          },
          "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>"
                }
              }
            }
          },
          "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>"
                }
              }
            }
          },
          "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 GET \\\n  --url \"$XPILOT_API_BASE_URL/v1/voices/%3Cvoice_id%3E?voice_version=1\" \\\n  --header \"Authorization: Bearer $XPILOT_API_KEY\""
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const response = await fetch(process.env.XPILOT_API_BASE_URL + \"/v1/voices/%3Cvoice_id%3E?voice_version=1\", {\n  method: \"GET\",\n  headers: {\n    Authorization: `Bearer ${process.env.XPILOT_API_KEY}`,\n  },\n});\nconst result = await response.json();\nif (!response.ok) throw new Error(JSON.stringify(result));\nconsole.log(result);"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os, json, requests\n\nresponse = requests.request(\n    \"GET\",\n    os.environ[\"XPILOT_API_BASE_URL\"] + \"/v1/voices/%3Cvoice_id%3E?voice_version=1\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"XPILOT_API_KEY\"],\n    },\n    timeout=70,\n)\nprint(response.status_code, response.text)\nresponse.raise_for_status()"
          }
        ]
      },
      "delete": {
        "operationId": "delete-voice",
        "tags": [
          "Voices & audio"
        ],
        "summary": "delete voice",
        "description": "Delete an owned cloned voice. Public catalog voices cannot be deleted. Reuse Idempotency-Key on retry.",
        "parameters": [
          {
            "name": "voice_id",
            "in": "path",
            "required": true,
            "description": "Owned clone voice ID.",
            "schema": {
              "type": "string",
              "description": "Owned clone voice ID."
            }
          },
          {
            "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
            }
          }
        ],
        "x-required-scope": "audio:write",
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "id": "<voice_id>",
                    "deleted": true
                  }
                }
              }
            }
          },
          "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>"
                }
              }
            }
          },
          "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>"
                }
              }
            }
          },
          "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 DELETE \\\n  --url \"$XPILOT_API_BASE_URL/v1/voices/%3Cvoice_id%3E\" \\\n  --header \"Authorization: Bearer $XPILOT_API_KEY\" \\\n  --header 'Idempotency-Key: lesson-request-001'"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const response = await fetch(process.env.XPILOT_API_BASE_URL + \"/v1/voices/%3Cvoice_id%3E\", {\n  method: \"DELETE\",\n  headers: {\n    Authorization: `Bearer ${process.env.XPILOT_API_KEY}`,\n    \"Idempotency-Key\": \"lesson-request-001\",\n  },\n});\nconst result = await response.json();\nif (!response.ok) throw new Error(JSON.stringify(result));\nconsole.log(result);"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os, json, requests\n\nresponse = requests.request(\n    \"DELETE\",\n    os.environ[\"XPILOT_API_BASE_URL\"] + \"/v1/voices/%3Cvoice_id%3E\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"XPILOT_API_KEY\"],\n        \"Idempotency-Key\": \"lesson-request-001\",\n    },\n    timeout=70,\n)\nprint(response.status_code, response.text)\nresponse.raise_for_status()"
          }
        ]
      }
    },
    "/v1/voices/speech": {
      "post": {
        "operationId": "generate-audio",
        "tags": [
          "Voices & audio"
        ],
        "summary": "generate audio",
        "description": "Synthesize up to 1,000 characters with a catalog voice or one of your ready clones, in Voice I or Voice II. voice_version must match the voice. Returns MP3 audio_url (which may be a data URL). Uses platform TTS pricing; reuse the same Idempotency-Key for retries.",
        "parameters": [
          {
            "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
            }
          }
        ],
        "x-required-scope": "audio:write",
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "audio_url": "data:audio/mpeg;base64,<mp3_bytes>",
                    "format": "mp3",
                    "voice_id": "<voice_id>",
                    "voice_version": 1,
                    "billing_basis": "platform_tts",
                    "cost_credits": 0
                  }
                }
              }
            }
          },
          "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>"
                }
              }
            }
          },
          "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>"
                }
              }
            }
          },
          "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 \\\n  --url \"$XPILOT_API_BASE_URL/v1/voices/speech\" \\\n  --header \"Authorization: Bearer $XPILOT_API_KEY\" \\\n  --header 'Content-Type: application/json' \\\n  --header 'Idempotency-Key: lesson-request-001' \\\n  --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/voices/speech\", {\n  method: \"POST\",\n  headers: {\n    Authorization: `Bearer ${process.env.XPILOT_API_KEY}`,\n    \"Content-Type\": \"application/json\",\n    \"Idempotency-Key\": \"lesson-request-001\",\n  },\n  body: JSON.stringify({\n  \"text\": \"Welcome to our lesson.\",\n  \"voice_id\": \"<voice_id>\",\n  \"voice_version\": 1\n}),\n});\nconst result = await response.json();\nif (!response.ok) throw new Error(JSON.stringify(result));\nconsole.log(result);"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os, json, requests\n\nresponse = requests.request(\n    \"POST\",\n    os.environ[\"XPILOT_API_BASE_URL\"] + \"/v1/voices/speech\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"XPILOT_API_KEY\"],\n        \"Content-Type\": \"application/json\",\n        \"Idempotency-Key\": \"lesson-request-001\",\n    },\n    json=json.loads(\"{\\\"text\\\":\\\"Welcome to our lesson.\\\",\\\"voice_id\\\":\\\"<voice_id>\\\",\\\"voice_version\\\":1}\"),\n    timeout=70,\n)\nprint(response.status_code, response.text)\nresponse.raise_for_status()"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "text": {
                    "type": "string",
                    "description": "Spoken text.",
                    "example": "Welcome to our lesson.",
                    "maxLength": 1000
                  },
                  "voice_id": {
                    "type": "string",
                    "description": "Catalog voice ID or owned ready clone ID."
                  },
                  "voice_version": {
                    "type": "integer",
                    "description": "Voice version of voice_id: Voice I (1, default) or Voice II (2). Never substitute one version for the other.",
                    "enum": [
                      1,
                      2
                    ],
                    "default": 1
                  },
                  "locale": {
                    "type": "string",
                    "description": "Speech locale. Voice II catalog voices accept their native or secondary locales; Voice II clones accept the locales they support."
                  },
                  "speed": {
                    "type": "number",
                    "description": "Playback speed.",
                    "minimum": 0.5,
                    "maximum": 2
                  }
                },
                "required": [
                  "text",
                  "voice_id"
                ]
              }
            }
          }
        }
      }
    },
    "/v1/voices/clone/config": {
      "get": {
        "operationId": "get-voice-clone-config",
        "tags": [
          "Voices & audio"
        ],
        "summary": "get voice clone config",
        "description": "Read Voice II clone requirements before clone_voice with voice_version 2: availability, the authorized company_name, supported locales with the consent_statement the speaker must read aloud, and sample duration/size limits. When voice_ii_available is false (for example voice_ii_unavailable_reason clone_disabled), do not attempt a Voice II clone; offer Voice I instead.",
        "parameters": [],
        "x-required-scope": "voices:read",
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "default_voice_version": 1,
                    "voice_ii_available": true,
                    "voice_ii_unavailable_reason": "",
                    "company_name": "X-Pilot",
                    "locales": [
                      {
                        "locale": "en-US",
                        "consent_statement": "I {voice_talent_name} am aware that recordings of my voice will be used by {company_name} to create and use a synthetic version of my voice."
                      }
                    ],
                    "sample_min_seconds": 5,
                    "sample_max_seconds": 90,
                    "max_sample_bytes": 31457280
                  }
                }
              }
            }
          },
          "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>"
                }
              }
            }
          },
          "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>"
                }
              }
            }
          },
          "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 GET \\\n  --url \"$XPILOT_API_BASE_URL/v1/voices/clone/config\" \\\n  --header \"Authorization: Bearer $XPILOT_API_KEY\""
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const response = await fetch(process.env.XPILOT_API_BASE_URL + \"/v1/voices/clone/config\", {\n  method: \"GET\",\n  headers: {\n    Authorization: `Bearer ${process.env.XPILOT_API_KEY}`,\n  },\n});\nconst result = await response.json();\nif (!response.ok) throw new Error(JSON.stringify(result));\nconsole.log(result);"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os, json, requests\n\nresponse = requests.request(\n    \"GET\",\n    os.environ[\"XPILOT_API_BASE_URL\"] + \"/v1/voices/clone/config\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"XPILOT_API_KEY\"],\n    },\n    timeout=70,\n)\nprint(response.status_code, response.text)\nresponse.raise_for_status()"
          }
        ]
      }
    },
    "/v1/voices/clone": {
      "post": {
        "operationId": "clone-voice",
        "tags": [
          "Voices & audio"
        ],
        "summary": "clone voice",
        "description": "Clone a private voice from audio already uploaded to your account. Voice I (default) is an instant clone from one sample. Voice II needs the speaker's consent: call get_voice_clone_config, have the speaker record the consent_statement for the chosen locale with their name and company_name filled in, upload it separately, then pass voice_talent_name, locale, consent_audio_url and consent_accepted=true. Never fabricate consent or set consent_accepted without the speaker's explicit agreement. Voice II returns 403 voice_ii_unavailable while cloning is not open for the account. Poll get_voice until state is trained or failed. Reuse Idempotency-Key on retry.",
        "parameters": [
          {
            "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
            }
          }
        ],
        "x-required-scope": "audio:write",
        "responses": {
          "202": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "_id": "<voice_id>",
                    "title": "My clone",
                    "voice_version": 2,
                    "state": "training",
                    "selectable": false
                  }
                }
              }
            }
          },
          "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>"
                }
              }
            }
          },
          "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>"
                }
              }
            }
          },
          "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 \\\n  --url \"$XPILOT_API_BASE_URL/v1/voices/clone\" \\\n  --header \"Authorization: Bearer $XPILOT_API_KEY\" \\\n  --header 'Content-Type: application/json' \\\n  --header 'Idempotency-Key: lesson-request-001' \\\n  --data '{\"name\":\"<name>\",\"audio_url\":\"<audio_url>\",\"voice_version\":1}'"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const response = await fetch(process.env.XPILOT_API_BASE_URL + \"/v1/voices/clone\", {\n  method: \"POST\",\n  headers: {\n    Authorization: `Bearer ${process.env.XPILOT_API_KEY}`,\n    \"Content-Type\": \"application/json\",\n    \"Idempotency-Key\": \"lesson-request-001\",\n  },\n  body: JSON.stringify({\n  \"name\": \"<name>\",\n  \"audio_url\": \"<audio_url>\",\n  \"voice_version\": 1\n}),\n});\nconst result = await response.json();\nif (!response.ok) throw new Error(JSON.stringify(result));\nconsole.log(result);"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os, json, requests\n\nresponse = requests.request(\n    \"POST\",\n    os.environ[\"XPILOT_API_BASE_URL\"] + \"/v1/voices/clone\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"XPILOT_API_KEY\"],\n        \"Content-Type\": \"application/json\",\n        \"Idempotency-Key\": \"lesson-request-001\",\n    },\n    json=json.loads(\"{\\\"name\\\":\\\"<name>\\\",\\\"audio_url\\\":\\\"<audio_url>\\\",\\\"voice_version\\\":1}\"),\n    timeout=70,\n)\nprint(response.status_code, response.text)\nresponse.raise_for_status()"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "Voice title.",
                    "maxLength": 80
                  },
                  "audio_url": {
                    "type": "string",
                    "description": "Owned uploaded training audio URL. Voice II: 5–90 seconds of the same speaker."
                  },
                  "cover_image_url": {
                    "type": "string",
                    "description": "Optional owned uploaded cover image URL. Voice I only."
                  },
                  "voice_version": {
                    "type": "integer",
                    "description": "Voice I (1, default) or Voice II (2, consent-based personal voice).",
                    "enum": [
                      1,
                      2
                    ],
                    "default": 1
                  },
                  "voice_talent_name": {
                    "type": "string",
                    "description": "Voice II only: the speaker's name exactly as spoken in the consent recording.",
                    "maxLength": 128
                  },
                  "locale": {
                    "type": "string",
                    "description": "Voice II only: recording locale from get_voice_clone_config, for example en-US or zh-CN.",
                    "maxLength": 16
                  },
                  "consent_audio_url": {
                    "type": "string",
                    "description": "Voice II only: owned uploaded recording of the speaker reading the consent_statement for locale. Must be a separate file from audio_url, at most 90 seconds."
                  },
                  "consent_accepted": {
                    "type": "boolean",
                    "description": "Voice II only: true when the speaker has explicitly agreed that their voice may be cloned. Required for Voice II.",
                    "enum": [
                      true,
                      false
                    ]
                  }
                },
                "required": [
                  "name",
                  "audio_url"
                ]
              }
            }
          }
        }
      }
    },
    "/v1/avatars/{avatar_id}": {
      "get": {
        "operationId": "get-avatar",
        "tags": [
          "Avatars"
        ],
        "summary": "get avatar",
        "description": "Read an owned avatar. status is the overall state (draft, generating, ready, failed, deleting, migration_required); training_status and preview_status track training and the preview sample; selectable must be true before video generation can use it; stage names the step in progress (queued, generating_training_video, provider_processing, generating_preview, deleting_provider_asset) or null when idle; error is {code, message} on failure. Training ready alone does not mean it can be used in a video.",
        "parameters": [
          {
            "name": "avatar_id",
            "in": "path",
            "required": true,
            "description": "Owned avatar ID.",
            "schema": {
              "type": "string",
              "description": "Owned avatar ID."
            }
          }
        ],
        "x-required-scope": "avatars:read",
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "id": "<avatar_id>",
                    "name": "Presenter",
                    "avatar_type": "human_video",
                    "status": "ready",
                    "training_status": "ready",
                    "preview_status": "ready",
                    "selectable": true,
                    "stage": null,
                    "preview_image_url": "<image_url>",
                    "preview_video_url": "<video_url>",
                    "error": null,
                    "created_at": 1791849600,
                    "updated_at": 1791849680
                  }
                }
              }
            }
          },
          "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>"
                }
              }
            }
          },
          "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>"
                }
              }
            }
          },
          "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 GET \\\n  --url \"$XPILOT_API_BASE_URL/v1/avatars/%3Cavatar_id%3E\" \\\n  --header \"Authorization: Bearer $XPILOT_API_KEY\""
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const response = await fetch(process.env.XPILOT_API_BASE_URL + \"/v1/avatars/%3Cavatar_id%3E\", {\n  method: \"GET\",\n  headers: {\n    Authorization: `Bearer ${process.env.XPILOT_API_KEY}`,\n  },\n});\nconst result = await response.json();\nif (!response.ok) throw new Error(JSON.stringify(result));\nconsole.log(result);"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os, json, requests\n\nresponse = requests.request(\n    \"GET\",\n    os.environ[\"XPILOT_API_BASE_URL\"] + \"/v1/avatars/%3Cavatar_id%3E\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"XPILOT_API_KEY\"],\n    },\n    timeout=70,\n)\nprint(response.status_code, response.text)\nresponse.raise_for_status()"
          }
        ]
      },
      "delete": {
        "operationId": "delete-avatar",
        "tags": [
          "Avatars"
        ],
        "summary": "delete avatar",
        "description": "Delete an owned avatar. Poll get_avatar or list_avatars until it disappears. Reuse Idempotency-Key on retry.",
        "parameters": [
          {
            "name": "avatar_id",
            "in": "path",
            "required": true,
            "description": "Owned avatar ID.",
            "schema": {
              "type": "string",
              "description": "Owned avatar ID."
            }
          },
          {
            "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
            }
          }
        ],
        "x-required-scope": "avatars:write",
        "responses": {
          "202": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "id": "<avatar_id>",
                    "status": "deleting"
                  }
                }
              }
            }
          },
          "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>"
                }
              }
            }
          },
          "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>"
                }
              }
            }
          },
          "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 DELETE \\\n  --url \"$XPILOT_API_BASE_URL/v1/avatars/%3Cavatar_id%3E\" \\\n  --header \"Authorization: Bearer $XPILOT_API_KEY\" \\\n  --header 'Idempotency-Key: lesson-request-001'"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const response = await fetch(process.env.XPILOT_API_BASE_URL + \"/v1/avatars/%3Cavatar_id%3E\", {\n  method: \"DELETE\",\n  headers: {\n    Authorization: `Bearer ${process.env.XPILOT_API_KEY}`,\n    \"Idempotency-Key\": \"lesson-request-001\",\n  },\n});\nconst result = await response.json();\nif (!response.ok) throw new Error(JSON.stringify(result));\nconsole.log(result);"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os, json, requests\n\nresponse = requests.request(\n    \"DELETE\",\n    os.environ[\"XPILOT_API_BASE_URL\"] + \"/v1/avatars/%3Cavatar_id%3E\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"XPILOT_API_KEY\"],\n        \"Idempotency-Key\": \"lesson-request-001\",\n    },\n    timeout=70,\n)\nprint(response.status_code, response.text)\nresponse.raise_for_status()"
          }
        ]
      }
    },
    "/v1/avatars/{avatar_id}/videos": {
      "post": {
        "operationId": "create-avatar-video",
        "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.",
        "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
            }
          }
        ],
        "x-required-scope": "avatars:write",
        "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 \\\n  --url \"$XPILOT_API_BASE_URL/v1/avatars/%3Cavatar_id%3E/videos\" \\\n  --header \"Authorization: Bearer $XPILOT_API_KEY\" \\\n  --header 'Content-Type: application/json' \\\n  --header 'Idempotency-Key: lesson-request-001' \\\n  --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\", {\n  method: \"POST\",\n  headers: {\n    Authorization: `Bearer ${process.env.XPILOT_API_KEY}`,\n    \"Content-Type\": \"application/json\",\n    \"Idempotency-Key\": \"lesson-request-001\",\n  },\n  body: JSON.stringify({\n  \"text\": \"Welcome to our lesson.\",\n  \"voice_id\": \"<voice_id>\",\n  \"voice_version\": 1\n}),\n});\nconst result = await response.json();\nif (!response.ok) throw new Error(JSON.stringify(result));\nconsole.log(result);"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os, json, requests\n\nresponse = requests.request(\n    \"POST\",\n    os.environ[\"XPILOT_API_BASE_URL\"] + \"/v1/avatars/%3Cavatar_id%3E/videos\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"XPILOT_API_KEY\"],\n        \"Content-Type\": \"application/json\",\n        \"Idempotency-Key\": \"lesson-request-001\",\n    },\n    json=json.loads(\"{\\\"text\\\":\\\"Welcome to our lesson.\\\",\\\"voice_id\\\":\\\"<voice_id>\\\",\\\"voice_version\\\":1}\"),\n    timeout=70,\n)\nprint(response.status_code, response.text)\nresponse.raise_for_status()"
          }
        ],
        "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
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/avatars/{avatar_id}/videos/{video_id}": {
      "get": {
        "operationId": "get-avatar-video",
        "tags": [
          "Avatars"
        ],
        "summary": "get avatar video",
        "description": "Read an avatar video job: status (queued, processing, completed, failed), video_url (transparent WebM) once completed, duration_seconds, width, height and the settled cost_credits. Poll at least 5 seconds apart.",
        "parameters": [
          {
            "name": "avatar_id",
            "in": "path",
            "required": true,
            "description": "Owned avatar ID.",
            "schema": {
              "type": "string",
              "description": "Owned avatar ID."
            }
          },
          {
            "name": "video_id",
            "in": "path",
            "required": true,
            "description": "Video ID returned by create_avatar_video.",
            "schema": {
              "type": "string",
              "description": "Video ID returned by create_avatar_video."
            }
          }
        ],
        "x-required-scope": "avatars:read",
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "id": "<video_id>",
                    "avatar_id": "<avatar_id>",
                    "status": "completed",
                    "source": "text",
                    "video_url": "<webm_url>",
                    "format": "webm",
                    "has_alpha": true,
                    "duration_seconds": 12.4,
                    "width": 1080,
                    "height": 1920,
                    "cost_credits": 9.18,
                    "error": null,
                    "created_at": 1791849600,
                    "updated_at": 1791849680
                  }
                }
              }
            }
          },
          "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>"
                }
              }
            }
          },
          "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>"
                }
              }
            }
          },
          "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 GET \\\n  --url \"$XPILOT_API_BASE_URL/v1/avatars/%3Cavatar_id%3E/videos/%3Cvideo_id%3E\" \\\n  --header \"Authorization: Bearer $XPILOT_API_KEY\""
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const response = await fetch(process.env.XPILOT_API_BASE_URL + \"/v1/avatars/%3Cavatar_id%3E/videos/%3Cvideo_id%3E\", {\n  method: \"GET\",\n  headers: {\n    Authorization: `Bearer ${process.env.XPILOT_API_KEY}`,\n  },\n});\nconst result = await response.json();\nif (!response.ok) throw new Error(JSON.stringify(result));\nconsole.log(result);"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os, json, requests\n\nresponse = requests.request(\n    \"GET\",\n    os.environ[\"XPILOT_API_BASE_URL\"] + \"/v1/avatars/%3Cavatar_id%3E/videos/%3Cvideo_id%3E\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"XPILOT_API_KEY\"],\n    },\n    timeout=70,\n)\nprint(response.status_code, response.text)\nresponse.raise_for_status()"
          }
        ]
      }
    }
  },
  "components": {
    "securitySchemes": {
      "BearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "Scoped X-Pilot API key"
      }
    }
  }
}
