Tasks & polling
Submit an asynchronous task, poll it to completion, paginate your task history, and cancel — including idempotent retries.
Asynchronous jobs run as tasks. You create one, then poll it (or receive a webhook) until it reaches a terminal state.
Create a task
POST /v1/tasks with the capability type, a source_url, and params:
curl -X POST https://api.fotovid.co/v1/tasks \
-H "Authorization: Bearer p6_<key_id>:<secret>" \
-H "Content-Type: application/json" \
-d '{
"type": "video.watermark",
"source_url": "https://cdn.example.com/clip.mp4",
"params": { "watermark_type": "text", "text": "Fotovid.co" }
}'It returns 201 right away:
{
"id": "01JAB...",
"task_type": "video.watermark",
"status": "starting",
"urls": { "get": "https://api.fotovid.co/v1/tasks/01JAB..." }
}Credits are reserved when the task is created; if your balance is too low the
call returns 402 INSUFFICIENT_CREDITS before any work starts.
Status lifecycle
A task moves through five states:
starting → processing → succeeded
↳ failed
↳ canceledsucceeded, failed, and canceled are terminal.
Poll for the result
GET /v1/tasks/{id} returns the current task. Poll until status is terminal:
curl https://api.fotovid.co/v1/tasks/01JAB... \
-H "Authorization: Bearer p6_<key_id>:<secret>"{
"id": "01JAB...",
"task_type": "video.watermark",
"status": "succeeded",
"outputs": [{ "kind": "video", "url": "https://tempfile.fotovid.co/v/<hex>.mp4" }],
"created_at": "2026-06-03T12:00:00Z",
"completed_at": "2026-06-03T12:00:07Z",
"expires_at": "2026-06-10T12:00:00Z"
}The output lives in outputs[].url. A polling interval of 1–2 seconds is
reasonable (light jobs finish in seconds); this is a recommendation, not a
contract.
Prefer not to poll? Pass a webhook URL when you create the task and Fotovid will
POST a signed event to it on completion. See Webhooks.
Each outputs[].url is an opaque, time-limited link — it stops working at
expires_at (7 days) and isn't refreshed, so download what you need before then.
Treat the URL as an opaque handle: don't parse or derive anything from its path.
List your tasks
GET /v1/tasks returns your task history, newest first, with cursor
pagination:
curl "https://api.fotovid.co/v1/tasks?limit=25" \
-H "Authorization: Bearer p6_<key_id>:<secret>"{
"results": [ /* … */ ],
"next_cursor": "djIsMTcxOTk5…",
"has_next": true
}To fetch the next page, pass the returned next_cursor back as the cursor
query parameter. limit defaults to 25 (max 100). You can also filter by
status, created_from, and created_to.
Cancel a task
POST /v1/tasks/{id}/cancel cancels a task that is still starting or
processing and refunds the reserved credits. Canceling an already-terminal task
returns 409 TASK_NOT_CANCELABLE.
Cancellation is best-effort on already-running work: a task that is mid-flight may finish computing before the cancel lands, but its result is discarded and you are not charged.
Idempotent retries
Pass an idempotency_key (≤ 64 chars) when creating a task to make retries safe.
If you submit the same key twice, Fotovid returns the existing task instead of
creating a second one — a single task, a single charge:
{ "type": "image.watermark", "source_url": "…", "params": { }, "idempotency_key": "order-4823" }The replay returns 200 (rather than a fresh 201). Scope is per-account; an
empty key means no deduplication.