Promoat / Partner API docs

Videos

Talking-head videos

One continuous shot of your character presenting to camera — the workhorse format for updates, promos, and UGC-style ads. Up to 59 seconds, vertical, studio lipsync always on, ready to post.

How a job runs

POST /videos with mode: "talking_head" queues an async job and returns immediately. The workflow then: plans the shot from your video_idea (or takes your ready-made first frame) → gets the speech audio (synthesized from your script, or your uploaded audio) → renders the character speaking it → runs the studio lipsync pass (always — there's no tier to pick) → burns in captions if you asked for them. You poll the job until it hands you a video_url.

The request

POST/api/partner/v1/videos
FieldTypeDescription
mode"talking_head" requiredOr "scenes" — see Multi-scene videos.
character_iduuid requiredWho is on camera.
voice_id + scriptstringsAudio source A — the job runs TTS on script with your voice. Spoken verbatim, never trimmed.
audio_urlhttps urlAudio source B — pre-recorded speech (yours or from POST /tts). Provide exactly one source: A or B, never both. Duration is probed server-side automatically.
video_ideastring ≤2000The scene to stage ("standing in a bright modern kitchen…"). Required unless first_frame_url is given.
first_frame_urlhttps urlSkip scene planning and animate exactly this still — usually one you made via first-frame images.
resolution"480p" | "720p"Default 480p. 720p costs ~2× per second on the render line.
use_dynamic_captionsbooleanBurn in dynamic captions (bold, word-by-word, on a solid legible band). Omit or false for none. Flat 10 credits — see below.
captions_languagestringOptional speech language for the captions, e.g. "en" or "ar". Omit to auto-detect. Latin and Arabic scripts both render correctly.
captions_position"top" | "bottom"Which edge the caption band sits on. Default "bottom". Use it to keep captions off your subject — see below.
Lipsync is always on

Every talking-head gets the studio lipsync pass — the best mouths we can produce, no knob to turn. It's included in the price below (~13.4 credits/second). If an older integration still sends a lipsync field, it's silently ignored.

Dynamic captions

Set use_dynamic_captions: true to burn in dynamic captions — big, bold captions that reveal word by word as your character speaks, with the key words popped in colour for emphasis. They render in a heavy weight on a solid background band, so they stay readable over any footage, and cover both Latin and Arabic scripts (pass captions_language: "ar" for Arabic). Flat 10 credits, quoted and charged like every other line item.

Make sure they're visible over your shot

The captions sit in a band at the bottom of the frame by default, and emphasized words pop larger toward the centre. So when you pick or generate the shot, leave room for them: keep the speaker's face in the upper-to-middle of the frame and don't put anything you can't cover along the bottom edge. If your composition needs the bottom clear instead, move the band up with captions_position: "top" and keep the top clear. When you build the opening still on first-frame images, frame it with that clear strip in mind.

The 59-second cap

Audio must measure ≤ 59s

Over-length input is rejected with 400 at queue time — an over-long script (estimated) or audio_url (measured) never starts a job or touches your balance. Scripts that estimate under the cap but measure over it after TTS fail the job with a full refund. Rule of thumb: ~140 spoken words ≈ 55s — keep scripts under that.

What it costs

Line items sum: render seconds × rate, the always-on studio lipsync at ~13.4/s, plus speech synthesis (when using a script), a first frame (when the job generates one), and captions if chosen. Two worked examples for a 30-second script:

Line itemEveryday clip (480p)Hero clip (720p + captions)
Render (30s)240450
Studio lipsync (30s, always on)400400
TTS (script ≤1k chars)1010
First frame (generated)66
Dynamic captions10
Total656 credits876 credits

Don't do this math yourself — POST /videos/estimate quotes any request exactly, for free, before you commit. The exact estimate is reserved at queue time (credits_reserved) and settles to the measured actual on completion — how billing settles.

Quote it, then queue it

1. Estimate (free, no side effects) — every param populated
curl -X POST https://platform.promoat.ai/api/partner/v1/videos/estimate \
  -H "Authorization: Bearer $PROMOAT_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "mode": "talking_head",
    "character_id": "CHARACTER_ID",
    "voice_id": "VOICE_ID",
    "script": "Hi! Three quick updates from the shop this week…",
    "video_idea": "standing in a bright modern kitchen, smiling at the camera",
    "resolution": "720p",
    "use_dynamic_captions": true
  }'

# → { "credits_required": 290, "credits_balance": 961, "sufficient_credits": true,
#     "estimated_seconds": 7.4,
#     "breakdown": { "render_credits": 111, "lipsync_credits": 99, "tts_credits": 10,
#                    "first_frame_credits": 6, "captions_credits": 10 } }
2. Queue (same body — reserves exactly the quoted amount)
curl -X POST https://platform.promoat.ai/api/partner/v1/videos \
  -H "Authorization: Bearer $PROMOAT_KEY" \
  -H "Content-Type: application/json" \
  -d '{ ...same body... }'

# → { "workflow_id": "partner_thv_1783…", "status": "queued", "credits_reserved": 290 }
3. Poll (every 5–10s)
curl https://platform.promoat.ai/api/partner/v1/jobs/partner_thv_1783…/status \
  -H "Authorization: Bearer $PROMOAT_KEY"

# → { "status": "completed",
#     "video_url": "https://…/final.mp4",
#     "credits_consumed": 284, … }

Typical wall-clock: 4–8 minutes for a 480p clip (the lipsync pass is part of every run). Up to 5 jobs can run at once (429 beyond that).

The other two audio/frame sources

Instead of voice_id + script, drop in pre-recorded audio; instead of video_idea, drop in a ready-made frame:

Pre-recorded audio + a ready-made first frame
curl -X POST https://platform.promoat.ai/api/partner/v1/videos \
  -H "Authorization: Bearer $PROMOAT_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "mode": "talking_head",
    "character_id": "CHARACTER_ID",
    "audio_url": "https://your-cdn.com/audio/narration.mp3",
    "first_frame_url": "https://your-cdn.com/frames/opening-shot.jpg",
    "resolution": "720p",
    "use_dynamic_captions": true
  }'

Try it

Try itGET/api/partner/v1/charactersfree
Add your API key in the sidebar to enable this.
Try itPOST/api/partner/v1/videos/estimatefree
Add your API key in the sidebar to enable this.
Try itPOST/api/partner/v1/videoscharges the quoted amount (real video job)
Add your API key in the sidebar to enable this.
Try itGET/api/partner/v1/jobs/{workflow_id}/statusfree
Add your API key in the sidebar to enable this.