Videos
Jobs & polling
Video endpoints return a workflow_id, and this endpoint is how you follow it: status, cost as it settles, and the finished video URL. No webhooks — poll it.
The status endpoint
GET/api/partner/v1/jobs/{workflowId}/status
Free to call, as often as you like. The response is the job's whole story:
| Field | Type | Description |
|---|---|---|
| workflow_id | string | The id you got when queueing. |
| status | enum | queued → running → completed or failed. |
| video_url / image_url | string | null | The finished output, present once completed. |
| result | object | null | Generic envelope with video_url / image_url / audio_url / asset_id when present. |
| credits_estimated | int | null | The reservation made at queue time. |
| credits_actual | int | null | The measured charge, recorded at completion. |
| credits_consumed | int | null | The one to display: null while queued/running, the actual charge once completed, 0 on failed (full refund) unless partial work was billed. |
| error_message | string | null | Why a failed job failed. |
| queued_at / completed_at | timestamps | For your own duration metrics. |
A completed multi-scene job (real shape)
{
"workflow_id": "partner_scn_1783515143595_pnusyce",
"status": "completed",
"error_message": null,
"credits_estimated": 620,
"credits_actual": 561,
"credits_consumed": 561,
"video_url": "https://…/video.mp4",
"result": { "video_url": "https://…/video.mp4", "asset_id": "…" },
"queued_at": "2026-07-08T04:12:23.595Z",
"completed_at": "2026-07-08T04:31:02.114Z"
}A sane poll loop
- Interval: every 5–10 seconds is plenty — jobs take minutes, not milliseconds.
- Timeout: give talking-head jobs ~10 minutes and multi-scene ~25 before alarming. A job that's still
runningis genuinely still working. - Terminal states are terminal. Once
completedorfailed, the record never changes — cache it and stop polling.
Node example
async function waitForJob(workflowId) {
for (;;) {
const res = await fetch(
`https://platform.promoat.ai/api/partner/v1/jobs/${workflowId}/status`,
{ headers: { Authorization: `Bearer ${process.env.PROMOAT_KEY}` } },
);
const job = await res.json();
if (job.status === 'completed') return job;
if (job.status === 'failed') throw new Error(job.error_message ?? 'job failed');
await new Promise((r) => setTimeout(r, 8000));
}
}Showing progress to your users
While status is running, the job's row in GET /usage/jobs carries a metadata.phase field you can surface as a progress label — multi-scene jobs move from generating to finalizing as the video is produced.
404 on a status poll?
The workflow_id is wrong or belongs to a different key — existence is never leaked. Ids are returned only once, at queue time; if you lost one, find it in GET /usage/jobs.
Try it
Paste any workflow_id from a video you've queued (or grab one from your job history below):
Try itGET/api/partner/v1/usage/jobsfree
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.