The visionstory package is the official Python SDK for the VisionStory API. This zero-dependency client uses only the Python standard library and handles authentication, JSON, base64 uploads, asynchronous polling, errors, and media downloads.
Requires Python 3.10+.
Install the VisionStory Python SDK
pip install visionstory
Discover new SDK features
In an interactive Python session, the SDK checks the VisionStory release manifest at most once per day and displays an upgrade notice at most once per week when a newer version is available. The notice includes the latest version, release title, upgrade command, and release notes. Update checks fail silently when you are offline and never change the installed package.
Check explicitly in a notebook, server process, or CI job:
from visionstory import check_for_updates
print(check_for_updates())
# installed_version, latest_version, update_available, highlights, update_command
Disable passive notices with VISIONSTORY_UPDATE_CHECK=0, or force the interactive notice behavior with VISIONSTORY_UPDATE_CHECK=1. The machine-readable release manifest is available at /releases/latest.json.
Authenticate the Python client
Default setup: use the official API
For most applications, configure only VISIONSTORY_API_KEY and use from_env(). You do not need to set a domain or a timeout.
Create a key on the API keys page, then provide it through your application's environment or deployment secret store. Never put a real key in source code, chat, or a committed environment file.
from visionstory import VisionStoryClient
client = VisionStoryClient.from_env()
print(client.get_credits()) # Read-only authentication check; does not generate media
For a local test without a configured environment, run this in your own terminal before creating the client. Input stays hidden; the key is available only to this Python process, not future terminals:
import getpass
import os
os.environ["VISIONSTORY_API_KEY"] = getpass.getpass("VisionStory API key (hidden): ")
| Setting | Default behavior | How to customize |
|---|---|---|
| API key | from_env() reads VISIONSTORY_API_KEY; a missing or empty key raises an error | Supply the environment variable or pass api_key to the constructor |
| API address | https://openapi.visionstory.ai when VISIONSTORY_API_BASE is not set | Set VISIONSTORY_API_BASE for from_env(), or pass base_url to the constructor |
| HTTP timeout | 60 seconds for requests without an operation-specific override | Pass request_timeout in seconds |
SDK authentication is separate from CLI login.
from_env()reads the current process environment. It does not load.envfiles or credentials saved byvisionstory login; your application must load or inject environment variables before creating the client.
Custom setup: choose another API address
Use this only for a trusted proxy, gateway, or test server that implements the VisionStory API. The simplest option is to change the environment and keep your Python code unchanged:
# macOS / Linux / WSL shell; applies to this terminal and its child processes
export VISIONSTORY_API_BASE="https://your-api.example.com"
from visionstory import VisionStoryClient
client = VisionStoryClient.from_env(request_timeout=120)
To return to the official API, remove the override (unset VISIONSTORY_API_BASE in the same shell), then create a new client. Do not set it to an empty string.
For per-client settings, pass the values explicitly:
import os
from visionstory import VisionStoryClient
client = VisionStoryClient(
api_key=os.environ["VISIONSTORY_API_KEY"],
base_url="https://your-api.example.com",
request_timeout=120,
)
Configuration precedence: from_env() reads both environment variables. The direct constructor uses its arguments and defaults; it does not read VISIONSTORY_API_BASE. If you omit base_url from the constructor, it uses the official address even when that environment variable is set. Changes to environment variables do not update an existing client.
Use a trusted HTTPS address. SDK requests send your key in the
X-API-Keyheader to the configured server. Provide the base address without/api/v1: SDK methods append paths such as/api/v1/models. Changing the domain does not make an unrelated API compatible.
request_timeout controls HTTP requests, not total video rendering time. Some operations use their own request timeout. Configure asynchronous waiting separately with wait_for_video(..., timeout=600); downloads have their own client.download(url, path, timeout=120) setting.
Generate a talking avatar video in Python
generate_video submits the job and polls until it finishes — one call in, a finished video out:
from pathlib import Path
from visionstory import VisionStoryClient, build_video_payload
client = VisionStoryClient.from_env()
payload = build_video_payload(
avatar_id="YOUR_AVATAR_ID", # select from client.list_avatars()
text="Hello World, this is my first video.",
voice_id="YOUR_VOICE_ID", # select from client.list_voices()
)
video = client.generate_video(payload) # submit + poll until "created"
client.download(video["video_url"], Path("result.mp4"))
print("saved result.mp4")
build_video_payload takes text or audio_url / audio_file (exactly one), plus optional model_id, aspect_ratio, resolution, speech_rate, and more — it maps directly to the POST /api/v1/video body.
Use the VisionStory CLI
A separate visionstory-cli package provides a visionstory command that covers the same surface — no code required:
visionstory create-video --avatar-id YOUR_AVATAR_ID --text "Hello from VisionStory." --voice-id YOUR_VOICE_ID --output result.mp4
See the CLI guide for every command, flag, and example.
List models, avatars, voices, and credits
Don't hardcode IDs — list them and pick at runtime:
client.list_models() # avatar render models
client.list_avatars(limit=20) # owned avatars
client.list_avatars(is_public=True, limit=20) # public avatar library
client.list_voices(locale="es-MX", provider="minimax", limit=50)
client.get_credits() # remaining balance
Verify SDK, CLI, and MCP compatibility
from visionstory import get_contract_info
print(get_contract_info())
# contract_version, SHA-256 contract_hash, and operation_count=28
The same fingerprint is available through visionstory contract and the MCP
resource visionstory://contract. Matching values mean the SDK, CLI, and MCP
server were built from the same OpenAPI and channel mapping.
Create avatars, clone voices, and upload assets
avatar = client.create_avatar(image_url="https://your.site/face.jpg") # or image_file=Path("face.jpg")
client.update_avatar_framing(
avatar_id=avatar["avatar_id"],
aspect_ratio="9:16",
zoom=1.2,
offset_x=0,
offset_y=-0.25,
)
client.clone_voice(audio_url="https://your.site/sample.mp3") # or audio_file=Path("sample.mp3")
client.upload_asset(url="https://your.site/clip.mp4") # or file_path=Path("clip.mp4")
Avatar listing is cursor-paginated and returns one collection at a time. Omit is_public for avatars owned by the current account, or set is_public=True for the public library. Follow next_cursor with cursor= and choose a limit from 1 to 100. Only owned avatars can be reframed; read the avatar's current framing entries before updating one aspect ratio.
upload_asset returns a reusable asset_id you can reference from AI Video requests.
Transcribe audio and create subtitles
Transcribe WAV or MP3 audio from a local path, public URL, or reusable asset. Add diarize=True for speaker labels and srt=True for subtitle output:
from pathlib import Path
transcript = client.transcribe_audio(
audio_file=Path("interview.mp3"),
diarize=True,
srt=True,
)
Path("interview.srt").write_text(transcript["srt"], encoding="utf-8")
alignment = client.align_audio(
text="Welcome to VisionStory.",
asset_id="YOUR_AUDIO_ASSET_ID",
)
See Audio Transcription and Alignment for request shapes, limits, word timestamps, and billing.
Synthesize localized speech
speech = client.create_speech(
text="Welcome to VisionStory.",
voice_id="YOUR_VOICE_ID",
locale="en-GB",
)
Path("speech.mp3").write_bytes(speech["audio"])
Control asynchronous polling
Submit and poll separately when you want to show progress or do other work in between:
created = client.create_video(payload) # returns immediately with a video_id
video = client.wait_for_video(created["video_id"], poll_interval=5, timeout=600)
generate_video(payload, wait=False) is equivalent to create_video.
Handle SDK errors and timeouts
from visionstory import VisionStoryAPIError, VideoTimeoutError
try:
video = client.generate_video(payload)
except VideoTimeoutError:
... # still not finished after `timeout` seconds
except VisionStoryAPIError as e:
... # API returned an error, or the task failed — credits for failed tasks are refunded automatically
Related VisionStory developer guides
- Quick start — the same flow, step by step.
- For agents — let an AI agent drive the API via the Skill or MCP server.
- Audio Transcription and Alignment — speech-to-text, SRT, and forced alignment.
- API reference — every endpoint the SDK wraps.
Structured media extraction and speech rate
Use understand_media for schema-constrained JSON from images, audio, or video. It takes required prompt, inputs, and schema, waits synchronously for up to 180 seconds, and returns output, usage, and cost_credit.
from visionstory import VisionStoryClient
client = VisionStoryClient.from_env()
result = client.understand_media(
prompt="Identify the subject",
inputs=[{"asset_id": "YOUR_ASSET_ID"}],
schema={"type": "object", "properties": {"subject": {"type": "string"}}, "required": ["subject"]},
)
print(result["output"])
speech = client.create_speech(text="Hello", voice_id="YOUR_VOICE_ID", speech_rate="slow")
# Save speech["audio"] as MP3. Omit speech_rate to keep normal speed.
speech_rate accepts slow, normal, or fast; None leaves the field out. See Media Understanding for input limits, billing, and timeout handling, and Text to Speech for binary responses.