curl --request POST \
--url https://toapis.com/v1/videos/generations \
--header 'Authorization: Bearer YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--data '{
"model": "sora-2",
"url": "https://example.com/character-video.mp4",
"timestamps": "1,3"
}'
curl --request POST \
--url https://toapis.com/v1/videos/generations \
--header 'Authorization: Bearer YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--data '{
"model": "sora-2",
"from_task": "task_01KBYT59JDHB4A3KDDR9N9JVWP",
"timestamps": "1,3"
}'
import requests
# Create character from video URL
response = requests.post(
"https://toapis.com/v1/videos/generations",
headers={
"Authorization": "Bearer YOUR_API_KEY",
"Content-Type": "application/json"
},
json={
"model": "sora-2",
"url": "https://example.com/character-video.mp4",
"timestamps": "1,3"
}
)
task = response.json()
print(f"Task ID: {task['id']}")
print(f"Status: {task['status']}")
# Create character from existing task
response = requests.post(
"https://toapis.com/v1/videos/generations",
headers={
"Authorization": "Bearer YOUR_API_KEY",
"Content-Type": "application/json"
},
json={
"model": "sora-2",
"from_task": "task_01KBYT59JDHB4A3KDDR9N9JVWP",
"timestamps": "1,3"
}
)
// Create character from video URL
const response = await fetch('https://toapis.com/v1/videos/generations', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
model: 'sora-2',
url: 'https://example.com/character-video.mp4',
timestamps: '1,3'
})
});
const task = await response.json();
console.log(`Task ID: ${task.id}`);
console.log(`Status: ${task.status}`);
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
)
func main() {
url := "https://toapis.com/v1/videos/generations"
payload := map[string]interface{}{
"model": "sora-2",
"url": "https://example.com/character-video.mp4",
"timestamps": "1,3",
}
jsonData, _ := json.Marshal(payload)
req, _ := http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
req.Header.Set("Authorization", "Bearer YOUR_API_KEY")
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Println(string(body))
}
{
"id": "task_01KBYT59JDHB4A3KDDR9N9JVWP",
"object": "generation.task",
"model": "sora-2",
"status": "queued",
"progress": 0,
"created_at": 1703884800,
"metadata": {}
}
{
"id": "task_01KC0JZCMTMQ70D68XTM56Q5D0",
"object": "generation.task",
"model": "sora-2",
"status": "completed",
"progress": 100,
"created_at": 1765251461,
"completed_at": 1765251507,
"result": {
"type": "character",
"data": {
"characters": [
{
"id": "ch_6937998961208191a45ef08447a554df",
"display_name": "Turbo Whiskers",
"profile_picture_url": "https://upload.toapis.com/f/image/character_task_xxx.jpg",
"username": "duksvfkf.turbo_whis"
}
]
}
},
"metadata": {}
}
{
"error": {
"code": 400,
"message": "Invalid request: timestamps range must be between 1-3 seconds",
"type": "invalid_request_error"
}
}
{
"error": {
"code": 401,
"message": "Authentication failed, please check your API key",
"type": "authentication_error"
}
}
{
"error": {
"code": 402,
"message": "Insufficient account balance, please top up",
"type": "payment_required"
}
}
Sora2
Sora2 Create Character
Extract characters from video for subsequent video generation
POST
/
v1
/
videos
/
generations
curl --request POST \
--url https://toapis.com/v1/videos/generations \
--header 'Authorization: Bearer YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--data '{
"model": "sora-2",
"url": "https://example.com/character-video.mp4",
"timestamps": "1,3"
}'
curl --request POST \
--url https://toapis.com/v1/videos/generations \
--header 'Authorization: Bearer YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--data '{
"model": "sora-2",
"from_task": "task_01KBYT59JDHB4A3KDDR9N9JVWP",
"timestamps": "1,3"
}'
import requests
# Create character from video URL
response = requests.post(
"https://toapis.com/v1/videos/generations",
headers={
"Authorization": "Bearer YOUR_API_KEY",
"Content-Type": "application/json"
},
json={
"model": "sora-2",
"url": "https://example.com/character-video.mp4",
"timestamps": "1,3"
}
)
task = response.json()
print(f"Task ID: {task['id']}")
print(f"Status: {task['status']}")
# Create character from existing task
response = requests.post(
"https://toapis.com/v1/videos/generations",
headers={
"Authorization": "Bearer YOUR_API_KEY",
"Content-Type": "application/json"
},
json={
"model": "sora-2",
"from_task": "task_01KBYT59JDHB4A3KDDR9N9JVWP",
"timestamps": "1,3"
}
)
// Create character from video URL
const response = await fetch('https://toapis.com/v1/videos/generations', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
model: 'sora-2',
url: 'https://example.com/character-video.mp4',
timestamps: '1,3'
})
});
const task = await response.json();
console.log(`Task ID: ${task.id}`);
console.log(`Status: ${task.status}`);
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
)
func main() {
url := "https://toapis.com/v1/videos/generations"
payload := map[string]interface{}{
"model": "sora-2",
"url": "https://example.com/character-video.mp4",
"timestamps": "1,3",
}
jsonData, _ := json.Marshal(payload)
req, _ := http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
req.Header.Set("Authorization", "Bearer YOUR_API_KEY")
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Println(string(body))
}
{
"id": "task_01KBYT59JDHB4A3KDDR9N9JVWP",
"object": "generation.task",
"model": "sora-2",
"status": "queued",
"progress": 0,
"created_at": 1703884800,
"metadata": {}
}
{
"id": "task_01KC0JZCMTMQ70D68XTM56Q5D0",
"object": "generation.task",
"model": "sora-2",
"status": "completed",
"progress": 100,
"created_at": 1765251461,
"completed_at": 1765251507,
"result": {
"type": "character",
"data": {
"characters": [
{
"id": "ch_6937998961208191a45ef08447a554df",
"display_name": "Turbo Whiskers",
"profile_picture_url": "https://upload.toapis.com/f/image/character_task_xxx.jpg",
"username": "duksvfkf.turbo_whis"
}
]
}
},
"metadata": {}
}
{
"error": {
"code": 400,
"message": "Invalid request: timestamps range must be between 1-3 seconds",
"type": "invalid_request_error"
}
}
{
"error": {
"code": 401,
"message": "Authentication failed, please check your API key",
"type": "authentication_error"
}
}
{
"error": {
"code": 402,
"message": "Insufficient account balance, please top up",
"type": "payment_required"
}
}
Note for users in mainland China: Please use
https://toapis.cn as the API endpoint (Base URL). Replace https://toapis.com with https://toapis.cn in the examples in this document.Overview
The Sora2 character creation feature allows you to extract characters from existing videos. Once created, you can reuse the character in subsequent video generations to maintain character consistency.Important:
- Video must contain audio and identifiable characters
- Time range limit: minimum 1 second, maximum 3 seconds
- Either
urlorfrom_taskis required - must provide one promptparameter is not required in this mode- After creation, the character task ID can be used for subsequent video generation
Authentication
string
required
Bearer Token authenticationGet your API Key from the API Key Management Page
Authorization: Bearer YOUR_API_KEY
Request Parameters
string
default:"sora-2"
required
Video generation model nameSupported models:
sora-2- Standard versionsora-2-pro- Professional version (higher quality)sora-2-vip- VIP version, higher priority
string
required
Character appearance timestamp rangeUnit is seconds, format is
"start_second,end_second"Constraints:- Time range difference minimum: 1 second
- Time range difference maximum: 3 seconds
"1,3" means the character appearing from second 1 to second 3 in the videostring
Video URL containing the character to extractRequirements:
- Video must contain audio
- Video must contain identifiable characters
url or from_task requiredExample: "https://example.com/my-video.mp4"string
Task ID of a previously generated videoCreate character from an existing video generation taskNote: Either
url or from_task requiredExample: "task_01KBYT59JDHB4A3KDDR9N9JVWP"Response Fields
string
Unique task identifier for querying character creation statusAfter completion, this character task ID can be used in video generation via the
character_url parameterstring
Object type, always
generation.taskstring
Model name used
string
Task status:
queued- Queued for processingin_progress- Processingcompleted- Successfully completedfailed- Failed
integer
Task progress percentage (0-100)
integer
Task creation time (Unix timestamp)
integer
Task completion time (Unix timestamp, only available after completion)
object
Character creation result (only available after completion)Contains created character information such as character ID, name, profile picture, etc.
curl --request POST \
--url https://toapis.com/v1/videos/generations \
--header 'Authorization: Bearer YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--data '{
"model": "sora-2",
"url": "https://example.com/character-video.mp4",
"timestamps": "1,3"
}'
curl --request POST \
--url https://toapis.com/v1/videos/generations \
--header 'Authorization: Bearer YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--data '{
"model": "sora-2",
"from_task": "task_01KBYT59JDHB4A3KDDR9N9JVWP",
"timestamps": "1,3"
}'
import requests
# Create character from video URL
response = requests.post(
"https://toapis.com/v1/videos/generations",
headers={
"Authorization": "Bearer YOUR_API_KEY",
"Content-Type": "application/json"
},
json={
"model": "sora-2",
"url": "https://example.com/character-video.mp4",
"timestamps": "1,3"
}
)
task = response.json()
print(f"Task ID: {task['id']}")
print(f"Status: {task['status']}")
# Create character from existing task
response = requests.post(
"https://toapis.com/v1/videos/generations",
headers={
"Authorization": "Bearer YOUR_API_KEY",
"Content-Type": "application/json"
},
json={
"model": "sora-2",
"from_task": "task_01KBYT59JDHB4A3KDDR9N9JVWP",
"timestamps": "1,3"
}
)
// Create character from video URL
const response = await fetch('https://toapis.com/v1/videos/generations', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
model: 'sora-2',
url: 'https://example.com/character-video.mp4',
timestamps: '1,3'
})
});
const task = await response.json();
console.log(`Task ID: ${task.id}`);
console.log(`Status: ${task.status}`);
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
)
func main() {
url := "https://toapis.com/v1/videos/generations"
payload := map[string]interface{}{
"model": "sora-2",
"url": "https://example.com/character-video.mp4",
"timestamps": "1,3",
}
jsonData, _ := json.Marshal(payload)
req, _ := http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
req.Header.Set("Authorization", "Bearer YOUR_API_KEY")
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Println(string(body))
}
{
"id": "task_01KBYT59JDHB4A3KDDR9N9JVWP",
"object": "generation.task",
"model": "sora-2",
"status": "queued",
"progress": 0,
"created_at": 1703884800,
"metadata": {}
}
{
"id": "task_01KC0JZCMTMQ70D68XTM56Q5D0",
"object": "generation.task",
"model": "sora-2",
"status": "completed",
"progress": 100,
"created_at": 1765251461,
"completed_at": 1765251507,
"result": {
"type": "character",
"data": {
"characters": [
{
"id": "ch_6937998961208191a45ef08447a554df",
"display_name": "Turbo Whiskers",
"profile_picture_url": "https://upload.toapis.com/f/image/character_task_xxx.jpg",
"username": "duksvfkf.turbo_whis"
}
]
}
},
"metadata": {}
}
{
"error": {
"code": 400,
"message": "Invalid request: timestamps range must be between 1-3 seconds",
"type": "invalid_request_error"
}
}
{
"error": {
"code": 401,
"message": "Authentication failed, please check your API key",
"type": "authentication_error"
}
}
{
"error": {
"code": 402,
"message": "Insufficient account balance, please top up",
"type": "payment_required"
}
}
Usage Flow
1
Submit Character Creation Request
Call this API with a video URL or existing task ID containing the character, along with the time range
2
Get Task ID
API returns task ID with status
queued or in_progress3
Query Task Status
Use the Query Video Task Status API to poll task progress
4
Use Character in Video Generation
After character creation completes, use
character_url parameter to reference the character task ID in subsequent video generationBest Practices
- Choose Clear Character Segments: Select 1-3 second segments where character features are most prominent
- Ensure Video Quality: High-definition video allows better character feature extraction
- Include Audio: Video must contain an audio track
- Avoid Multiple Characters: The selected time range should ideally contain only one main character