Skip to Content

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.

FieldTypeRequiredDescription
titlestringJob name — shown in the dashboard and used as the YouTube video title.
text_contentstringScript for the video. The TTS engine converts this to speech.
avatarfileTalking-head image (JPG/PNG). A portrait photo with a clear face works best.
reference_audiofileWAV or MP3 audio clip for voice cloning. 10–30 seconds of clean speech recommended.
reference_voiceintegerID of a saved Voice object (alternative to uploading a file).
processing_paramsJSON stringAdvanced 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

FieldDescription
idJob ID.
titleJob title.
status"PENDING", "PROCESSING", "COMPLETED", or "FAILED".
text_contentThe script provided at creation.
processed_video_urlS3 pre-signed download URL (set when COMPLETED). Valid for 1 hour — re-fetch the job to get a fresh URL.
error_messageError detail if status is "FAILED".
external_job_idID of the job in the rendering backend (for support queries).
created_atSubmission timestamp.
updated_atLast 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