The VisionStory AI Avatar API provides the on-screen character for a talking-avatar video. List your own avatars or the public library, create a reusable custom avatar from one portrait, and control how an owned avatar is framed in each supported aspect ratio.
AI avatar API endpoints
| Method | Path | What it does |
|---|---|---|
GET | /api/v1/avatars | List either owned avatars or the public library, with cursor pagination |
POST | /api/v1/avatar | Create a custom avatar from an image |
POST | /api/v1/avatar/framing | Update one aspect ratio's framing for an owned avatar |
DELETE | /api/v1/avatar | Delete one of your custom avatars |
List owned or public avatars
Each request returns one collection. By default, GET /api/v1/avatars lists avatars owned by the authenticated account. Set is_public=true to list the public library instead. Results are newest first and use cursor pagination:
curl -s -H "X-API-Key: $VISIONSTORY_API_KEY" "https://openapi.visionstory.ai/api/v1/avatars?is_public=false&limit=20"
import os
import requests
headers = {"X-API-Key": os.environ["VISIONSTORY_API_KEY"]}
params = {"is_public": False, "limit": 20}
while True:
response = requests.get(
"https://openapi.visionstory.ai/api/v1/avatars",
headers=headers,
params=params,
timeout=10,
)
data = response.json()["data"]
for avatar in data["avatars"]:
print(avatar["avatar_id"], avatar["default_voice_id"])
if not data["next_cursor"]:
break
params["cursor"] = data["next_cursor"]
The response shape is { "avatars": [...], "next_cursor": 0 }; next_cursor=0 means there are no more pages. limit accepts 1–100 and defaults to 20. Owned avatars include their real created_at and a three-entry framing array ordered 9:16, 16:9, 1:1. Public avatars always return framing: null.
Always choose an avatar_id from this endpoint instead of hardcoding one. To use the avatar's configured voice, copy its non-empty default_voice_id into text_script.voice_id.
Create an AI avatar from a photo
Send one portrait image, get back an avatar_id. Provide the image as either a public HTTPS URL or base64 inline_data — exactly one of the two:
curl -s -H "X-API-Key: $VISIONSTORY_API_KEY" -H "Content-Type: application/json" -d '{"img_url": "https://your.site/portrait.jpg"}' https://openapi.visionstory.ai/api/v1/avatar
With a local file, base64-encode it into inline_data:
import base64
import os
import requests
headers = {"X-API-Key": os.environ["VISIONSTORY_API_KEY"]}
with open("/path/to/image.jpg", "rb") as f:
encoded = base64.b64encode(f.read()).decode("utf-8")
payload = {"inline_data": {"mime_type": "image/jpg", "data": encoded}}
response = requests.post("https://openapi.visionstory.ai/api/v1/avatar", json=payload, headers=headers)
print(response.json()["data"]["avatar_id"])
Store the returned avatar_id — you will pass it to every video request that should feature this avatar.
Photo requirements: use a single, clear, front-facing portrait for best results. Supported formats are JPEG, PNG, WEBP, and HEIC, up to 10 MB.
Adjust avatar framing
Owned avatars expose current framing for all three aspect ratios. Start with the values returned by GET /api/v1/avatars, change one ratio at a time, and send all five required fields:
curl -s -X POST -H "X-API-Key: $VISIONSTORY_API_KEY" -H "Content-Type: application/json" -d '{"avatar_id":"YOUR_AVATAR_ID","aspect_ratio":"9:16","zoom":1.2,"offset_x":0,"offset_y":-0.25}' https://openapi.visionstory.ai/api/v1/avatar/framing
zoom=1 uses the widest frame that fits the selected aspect ratio; larger values move closer. offset_x and offset_y range from -1 to 1, where 0 is centered. The API keeps the frame inside the source image, verifies that it contains a visible face, saves it, and uses it for later videos in that aspect ratio.
Only avatars owned by the account can be reframed. Older avatars without source-image dimensions may return framing_unavailable. A source image that is too small for one aspect ratio returns zoom, offset_x, and offset_y as null for that ratio; its image_url remains available and other ratios may still be adjustable. Check each ratio before writing framing back. If a requested zoom makes the crop too small, the 400 response includes max_zoom in its details. When max_zoom is null, create the avatar again with a larger source image or choose a ratio with non-null framing values.
Use an avatar in a talking video
Pass the avatar_id when creating a video:
{
"model_id": "vs_character_v4",
"avatar_id": "YOUR_AVATAR_ID",
"text_script": { "text": "Hello!", "voice_id": "YOUR_VOICE_ID" }
}
See the Quick start for the full generate-poll-download flow.
Delete a custom avatar
Deleting only affects your own custom avatars; videos already generated with it are unaffected:
curl -s -X DELETE -H "X-API-Key: $VISIONSTORY_API_KEY" "https://openapi.visionstory.ai/api/v1/avatar?avatar_id=YOUR_AVATAR_ID"
Related VisionStory API guides
- Voices — pick or clone the voice your avatar speaks with.
- Quick start — generate your first video.
- Avatar API reference — inspect exact framing fields, bounds, responses, and error details.
- API reference — full request and response schemas.