curl --fail-with-body --request POST \
--url "$XPILOT_API_BASE_URL/v1/video-agents/conversations" \
--header "Authorization: Bearer $XPILOT_API_KEY" \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: lesson-request-001' \
--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"}'const response = await fetch(process.env.XPILOT_API_BASE_URL + "/v1/video-agents/conversations", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.XPILOT_API_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": "lesson-request-001",
},
body: JSON.stringify({
"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"
}),
});
const result = await response.json();
if (!response.ok) throw new Error(JSON.stringify(result));
console.log(result);import os, json, requests
response = requests.request(
"POST",
os.environ["XPILOT_API_BASE_URL"] + "/v1/video-agents/conversations",
headers={
"Authorization": "Bearer " + os.environ["XPILOT_API_KEY"],
"Content-Type": "application/json",
"Idempotency-Key": "lesson-request-001",
},
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\"}"),
timeout=70,
)
print(response.status_code, response.text)
response.raise_for_status(){
"data": {
"conversation_id": "<conversation_id>",
"message_id": "<message_id>",
"status": "running",
"cost_credits": 12
}
}{
"error": {
"code": "invalid_parameter",
"message": "Check parameter types, required fields and idempotency key."
},
"request_id": "<request_id>"
}{
"error": {
"code": "invalid_token",
"message": "Use an active scoped API Key. MCP OAuth tokens cannot call REST."
},
"request_id": "<request_id>"
}{
"error": {
"code": "insufficient_credits",
"message": "The balance cannot cover the platform reserve, or the credential monthly budget is used up."
},
"request_id": "<request_id>"
}{
"error": {
"code": "insufficient_scope",
"message": "Check the credential scope and resource ownership."
},
"request_id": "<request_id>"
}{
"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>"
}{
"error": {
"code": "rate_limited",
"message": "Credential/workspace rate or concurrency limit reached. Respect Retry-After before retrying.",
"retry_after": 60
},
"request_id": "<request_id>"
}Create conversation
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.
curl --fail-with-body --request POST \
--url "$XPILOT_API_BASE_URL/v1/video-agents/conversations" \
--header "Authorization: Bearer $XPILOT_API_KEY" \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: lesson-request-001' \
--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"}'const response = await fetch(process.env.XPILOT_API_BASE_URL + "/v1/video-agents/conversations", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.XPILOT_API_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": "lesson-request-001",
},
body: JSON.stringify({
"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"
}),
});
const result = await response.json();
if (!response.ok) throw new Error(JSON.stringify(result));
console.log(result);import os, json, requests
response = requests.request(
"POST",
os.environ["XPILOT_API_BASE_URL"] + "/v1/video-agents/conversations",
headers={
"Authorization": "Bearer " + os.environ["XPILOT_API_KEY"],
"Content-Type": "application/json",
"Idempotency-Key": "lesson-request-001",
},
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\"}"),
timeout=70,
)
print(response.status_code, response.text)
response.raise_for_status(){
"data": {
"conversation_id": "<conversation_id>",
"message_id": "<message_id>",
"status": "running",
"cost_credits": 12
}
}{
"error": {
"code": "invalid_parameter",
"message": "Check parameter types, required fields and idempotency key."
},
"request_id": "<request_id>"
}{
"error": {
"code": "invalid_token",
"message": "Use an active scoped API Key. MCP OAuth tokens cannot call REST."
},
"request_id": "<request_id>"
}{
"error": {
"code": "insufficient_credits",
"message": "The balance cannot cover the platform reserve, or the credential monthly budget is used up."
},
"request_id": "<request_id>"
}{
"error": {
"code": "insufficient_scope",
"message": "Check the credential scope and resource ownership."
},
"request_id": "<request_id>"
}{
"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>"
}{
"error": {
"code": "rate_limited",
"message": "Credential/workspace rate or concurrency limit reached. Respect Retry-After before retrying.",
"retry_after": 60
},
"request_id": "<request_id>"
}Documentation by X-Pilot
video_agents:write. A stable Idempotency-Key is required for exact retries.
Manage API keys · Authentication and recovery

Authorizations
Scoped X-Pilot API key
Headers
Stable key for exact retries only. Use a different key for a different operation or input.
8 - 128Body
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.
20000"Create a short English lesson about solar energy."
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.
false
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.
Show child attributes
Show child attributes
{
"target_language": "en",
"video_duration": "short",
"video_style": "clean_lecture"
}
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).
Show child attributes
Show child attributes
[
{
"url": "https://cdn.example.com/course.pdf",
"files_role": "primary"
}
]
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. event signed with the workspace callback secret (Developer console → Webhooks). Deliveries retry up to 6 times and are listed in the console.
2048"https://your-domain.com/xpilot/callback"
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.
128^[\w.:-]{1,128}$"order-1024"
Response
Success
