Create a video job
POST /api/video-jobs/Submits a new rendering job. Processing is asynchronous — poll the job until status is "COMPLETED".
curl -X POST https://api.oshara.ai/api/video-jobs/ \
-H "Authorization: Bearer <token>" \
-F "title=Product Demo" \
-F "text_content=Welcome to Acme! Today I'll show you our key features..." \
-F "avatar=@/path/to/avatar.jpg" \
-F "reference_audio=@/path/to/voice-sample.wav"Request fields
Send as multipart/form-data.
| Field | Type | Required | Description |
|---|---|---|---|
title | string | ✓ | Job name — shown in the dashboard and used as the YouTube video title. |
text_content | string | ✓ | Script for the video. The TTS engine converts this to speech. |
avatar | file | ✓ | Talking-head image (JPG/PNG). A portrait photo with a clear face works best. |
reference_audio | file | WAV or MP3 audio clip for voice cloning. 10–30 seconds of clean speech recommended. | |
reference_voice | integer | ID of a saved Voice object (alternative to uploading a file). | |
processing_params | JSON string | Advanced renderer configuration (passed through to the rendering backend). |
Response
{
"id": 42,
"title": "Product Demo",
"status": "PENDING",
"text_content": "Welcome to Acme!...",
"processed_video_url": null,
"error_message": null,
"created_at": "2025-06-10T15:00:00Z"
}List jobs
GET /api/video-jobs/Returns all jobs for the authenticated user, newest first.
curl https://api.oshara.ai/api/video-jobs/ \
-H "Authorization: Bearer <token>"Retrieve a job
GET /api/video-jobs/{id}/curl https://api.oshara.ai/api/video-jobs/42/ \
-H "Authorization: Bearer <token>"Response when completed:
{
"id": 42,
"title": "Product Demo",
"status": "COMPLETED",
"text_content": "Welcome to Acme!...",
"processed_video_url": "https://storage.oshara.ai/videos/42/output.mp4?X-Amz-Expires=3600&...",
"error_message": null,
"external_job_id": "imtk-abc123",
"created_at": "2025-06-10T15:00:00Z",
"updated_at": "2025-06-10T15:03:45Z"
}Job fields
| Field | Description |
|---|---|
id | Job ID. |
title | Job title. |
status | "PENDING", "PROCESSING", "COMPLETED", or "FAILED". |
text_content | The script provided at creation. |
processed_video_url | S3 pre-signed download URL (set when COMPLETED). Valid for 1 hour — re-fetch the job to get a fresh URL. |
error_message | Error detail if status is "FAILED". |
external_job_id | ID of the job in the rendering backend (for support queries). |
created_at | Submission timestamp. |
updated_at | Last status change. |
Poll for completion
async function waitForVideo(jobId, token) {
while (true) {
const res = await fetch(`https://api.oshara.ai/api/video-jobs/${jobId}/`, {
headers: { Authorization: `Bearer ${token}` }
});
const job = await res.json();
if (job.status === "COMPLETED") return job.processed_video_url;
if (job.status === "FAILED") throw new Error(job.error_message);
await new Promise(resolve => setTimeout(resolve, 5000)); // wait 5s
}
}Job statistics
GET /api/video-jobs/stats/Returns aggregate statistics for the authenticated user.
curl https://api.oshara.ai/api/video-jobs/stats/ \
-H "Authorization: Bearer <token>"{
"total": 15,
"completed": 13,
"failed": 1,
"pending": 1
}Video-only rendering (use your own audio)
POST /api/video-only/Use this if you already have an audio file and only need the lip-sync video — no TTS is applied.
curl -X POST https://api.oshara.ai/api/video-only/ \
-H "Authorization: Bearer <token>" \
-F "title=My Video" \
-F "avatar=@/path/to/avatar.jpg" \
-F "audio=@/path/to/narration.mp3"Same polling pattern as regular jobs.
Last updated on