VisionStory Docs
llms.txt Get API key

Generate your first talking-avatar video in five steps. The whole flow is: get a key, set up a client, submit a script, poll, download.

1. Get your API key

Sign up and create an API key at visionstory.ai/openapi (available on Pro plans and up). Send it with every request in the X-API-Key header:

X-API-Key: sk-vs-xxxxxxxxxxxxxxxxxxx

Keep the key on your server and never expose it in browser code or a public repository. The examples below read it from an environment variable:

export VISIONSTORY_API_KEY="sk-vs-xxxxxxxxxxxxxxxxxxx"

2. Set up your client

Two ways to start — pick one:

Option A — install the Agent Skill package (recommended if you use a coding agent, or just want a ready-made CLI). It ships SKILL.md plus a dependency-free Python CLI that handles auth, base64 encoding, polling, and downloads:

mkdir -p .agents/skills
curl -fsSL https://openapi.visionstory.ai/skills/visionstory-video-api.zip -o visionstory-video-api.zip
unzip -o visionstory-video-api.zip -d .agents/skills && rm visionstory-video-api.zip

Then create a video in one command:

python3 .agents/skills/visionstory-video-api/scripts/visionstory_api.py create-video --avatar-id 4321918387609092991 --text "Hello from VisionStory." --voice-id Alice --output result.mp4

Option B — copy the standalone script at the end of this page. It only needs requests.

3. Create your first video

Submit a text script with a public avatar and a public voice. The request returns a video_id immediately — generation happens asynchronously:

curl -s -H "X-API-Key: $VISIONSTORY_API_KEY" -H "Content-Type: application/json" -d '{"model_id": "vs_character_v4", "avatar_id": "4321918387609092991", "text_script": {"text": "Hello World, this is my first test video.", "voice_id": "Alice", "speech_rate": "normal"}, "aspect_ratio": "9:16", "resolution": "720p"}' https://openapi.visionstory.ai/api/v1/video
{ "data": { "video_id": "7241059991822401536" } }

Before building a production integration, discover current IDs instead of hardcoding them: GET /api/v1/models, GET /api/v1/avatars, and GET /api/v1/voices. To use your own audio instead of text, send an audio_script (with audio_url or base64 inline_data) in place of text_script — never both.

4. Poll until the video is ready

Query the task every 5 seconds until it reaches a final state:

curl -s -H "X-API-Key: $VISIONSTORY_API_KEY" "https://openapi.visionstory.ai/api/v1/video?video_id=7241059991822401536"
status Meaning
queued Accepted, waiting for a worker
creating Generating
created Done — video_url is ready
failed Generation failed — stop polling and inspect the error

Avoid polling faster than every 5 seconds, and give up after about 10 minutes.

5. Download the result

When the status is created, the response carries a video_url. Completed videos are retained for 7 days — download the file if you need permanent storage:

curl -sL -o result.mp4 "<video_url from the response>"

Full script

The five steps above as one standalone Python script:

import requests
import time
import os

headers = {"X-API-Key": os.environ["VISIONSTORY_API_KEY"]}

# Submit the video generation task
payload = {
    "model_id": "vs_character_v4",
    "avatar_id": "4321918387609092991",
    "text_script": {
        "text": "Hello World, this is my first test video.",
        "voice_id": "Alice",  # select voice_id from GET /api/v1/voices
        "speech_rate": "normal"
    },
    "aspect_ratio": "9:16",
    "resolution": "720p"
}
response = requests.post("https://openapi.visionstory.ai/api/v1/video", json=payload, headers=headers)
response.raise_for_status()
video_id = response.json()["data"]["video_id"]

# Poll every 5 seconds until the task finishes (10 minute timeout)
video_data = None
for _ in range(120):
    time.sleep(5)
    response = requests.get("https://openapi.visionstory.ai/api/v1/video", params={"video_id": video_id}, headers=headers)
    response.raise_for_status()
    data = response.json()["data"]
    if data["status"] == "created":
        video_data = data
        break
    if data["status"] == "failed":
        raise RuntimeError(f"Video {video_id} generation failed")
if video_data is None:
    raise TimeoutError(f"Video {video_id} timed out")

# Download the result (videos are retained for 7 days)
video = requests.get(video_data["video_url"], timeout=120)
with open("result.mp4", "wb") as f:
    f.write(video.content)
print("saved result.mp4")

Next steps