Everything every other skill in this library depends on. Read this once.
Always — but transparently. Other skills assume the agent already knows:
text
POST https://www.revid.ai/api/public/v3/render
Header: key: $REVID_API_KEY
Body: { "workflow": "<one-of-9>", "source": { … }, … }
↓
{ "success": 1, "pid": "p_…" }
↓
GET https://www.revid.ai/api/public/v3/status?pid=p_…
↓ (poll every 5–8 s)
{ "status": "ready", "videoUrl": "https://cdn.revid.ai/v/…mp4", … }
That's the entire contract. Skills only differ in the body of POST /render.
text
key: $REVID_API_KEY
The header is literally named key (not Authorization). If unset, fail with a
clear message instead of calling the API.
WorkflowUse when input is…script-to-videoAlready-written script (text).prompt-to-videoA one-liner idea — the API writes the script.article-to-videoAny URL with text content (blog/product/news).avatar-to-videoA script + an avatar image (talking-head).ad-generatorA product description — AI writes ad hooks.music-to-videoA music URL + visuals.motion-transferA reference image animated with motion from a clip.caption-videoAn existing video that needs captions.static-background-videoA voiceover over a fixed background.
Pick the workflow that matches the input shape, not the output you want.
The same script-to-video workflow can produce a Reel, a YouTube short, or a
LinkedIn square — that's just aspectRatio.
Each workflow expects one of these source.* fields:
WorkflowFieldscript-to-video``source.text``prompt-to-video``source.prompt (+ optional source.stylePrompt, durationSeconds)article-to-video``source.url (+ optional source.scrapingPrompt)ad-generator``source.prompt (the product description)avatar-to-video``source.text (script) + top-level avatar.url``music-to-video / caption-video / motion-transfer``source.url``static-background-video``source.text + media.backgroundVideo
If you put text in the wrong field, the call fails 422 with a schema error.
aspectRatio — pick from the consumer surface:
9:161:116:9voice.enabled — true for narrated content; false for music-only or
caption-only outputs.
captions.enabled — keep true by default. Most short-form watches happen
on mute.
music.enabled — true for promo / ad / story content; false for
talking-head where the avatar voice should breathe.
render.resolution — 1080p is the right default. Use 720p for cheap
previews; 4k only when downstream needs it.
media.quality / media.videoModel — start at pro. Bump to ultra /
veo3 / sora2 only when the cost is justified. Mirror the /render body
to POST /api/public/v3/calculate-credits first to get a price estimate
without spending.
webhookUrl — pass it whenever the caller can receive webhooks. Saves polling
entirely.
Success:
json
{ "success": 1, "pid": "p_…", "workflow": "…", "endpoint": "…", "docs": {…} }
Failure:
json
{ "success": 0, "error": "human-readable string" }
Skills should always check success === 1 and fail loudly otherwise.
After POST /render, poll until status === "ready":
bash
PID="<pid-from-render>"
while :; do
R=$(curl -fsSL "https://www.revid.ai/api/public/v3/status?pid=$PID" \
-H "key: $REVID_API_KEY")
S=$(echo "$R" | jq -r .status)
case "$S" in
ready) echo "$R" | jq .; break ;;
failed) echo "FAILED: $R"; exit 1 ;;
*) sleep 5 ;;
esac
done
Recommended cadence: poll every 5 s; back off to 8 s once progress > 30.
In production prefer setting webhookUrl in the request body and skip polling
entirely.
The two most common errors every skill must handle:
scrape failed / 403 from source URL — the page is JS-only or blocks
bots. Either pre-scrape it yourself and switch to script-to-video, or pass
source.scrapingPrompt with the manual title + body.insufficient_credits — drop media.quality / videoModel / resolution
and retry, or top up with POST /api/public/v3/buy-credit-pack.