Video Generations
Minimum-discount routing: Prefix the path with a min{N} segment (e.g. /min30/v1/video/generations) to require marketplace seller offers to meet a minimum estimated buyer discount before routing. Buyer-owned providers are not covered. See Minimum-Discount Routing.
Async video generation via the marketplace. Submit a job, poll for status, retrieve results.
This endpoint produces video. It does not analyze video you already have. There is no supported way to send a video file to a model for understanding; see Media Inputs, which covers what happens to a data:video/mp4 payload and why YouTube URLs are not supported.
Submit Job
Auth: API key required (Authorization: Bearer ***).
modelstringrequiredModel ID, e.g.venice-runway-gen4-5-text; legacyvenice-video-genmaps to a live Venice modelpromptstringrequiredText prompt (max 2000 chars)duration_secondsintegerVideo duration. Optional; omitted values use the model's cheapest/default duration when knownimage_urlstringImage-to-video start frame — anhttps://URL or adata:URI. Required by image-to-video-only models (see Image-to-Video below)end_image_urlstringTransition end frame for models that interpolate between two stills (equivalent toinput_imageswithrole: "end")input_imagesarraySource images for image-to-video / transition / reference models. Each entry is anhttps/data:URI string — positional[start]or[start, end]— or an object{ "url": "...", "role": "start" | "end" | "reference" }. Max 8 images per requestresolutionstringProvider-supported resolution such as480p,720p,1080p,4kaspect_ratiostringProvider-supported ratio such as16:9,9:16,1:1,4:3,3:4,21:9audiobooleanInclude audio track when the model supports itwebhook_urlstringAccepted and validated, but not delivered yet — terminal-state callbacks are not enabled in production. Poll insteadmetadataobjectClient pass-through metadata
Current Venice-backed examples include venice-runway-gen4-5-text, venice-seedance-2-fast-t2v, and venice-pixverse-c1-t2v. Query /v1/models and /api/markets for the live catalog and active order book.
Idempotency: Include Idempotency-Key header to prevent duplicate submissions.
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"object": "media.job",
"kind": "video",
"status": "queued",
"created": 1713200000,
"expires_at": 1713201800,
"estimated_cost_usdc": "102000",
"max_cost_usdc": "112200",
"poll_url": "/v1/video/generations/550e8400-...",
"cancel_url": "/v1/video/generations/550e8400-...",
"job_token": "mjt_abc123..."
}Image-to-Video
Pass a source image to animate a still (image-to-video), interpolate between two stills (transition), or condition on reference frames.
- Discovering models: image-to-video models carry an
-image-to-videoid suffix (e.g.seedance-2-0-image-to-video,wan-2-7-image-to-video,seedance-1-5-pro-image-to-video) and listimage-to-videoin theirsupported_parameters. Query/v1/modelsand/api/marketsfor the live set. - Required input: an image-to-video-only model (no text-to-video) requires a source image; a request without one returns
400. Transition models require both astartand anendframe. - Frames & roles: the simplest form is a single
image_url(the start frame). For a transition, addend_image_url, or useinput_imageswith explicit roles. Untaggedinput_imagesare positional —[start]or[start, end]; with three or more images, tag each with a role. Roles a model doesn't support are ignored — an extra frame won't fail the request. - Source form:
https://URL ordata:URI; bare base64 (without thedata:prefix) andhttp://URLs are rejected. URLs are passed to the provider as-is — the marketplace never fetches them.
{
"model": "seedance-2-0-image-to-video",
"prompt": "slow dolly-in as the waves roll",
"image_url": "https://example.com/first-frame.png",
"duration_seconds": 5
}Poll Status
Auth: API key OR X-Job-Token header (returned from submit).
Status values: queued → submitted → running → succeeded | failed | canceled | expired.
Rolling out. The error object below is the shape the API is moving to. Until the rollout completes,
a terminal job may instead carry type set to its status ("failed", "canceled") and no retryable
field. Write your handler to tolerate both: treat a missing retryable as "safe to retry unless type is
invalid_request", and do not assume error is absent on a cancel.
The error object. Present on a terminal job that failed, and absent on one that succeeded or was
cleanly canceled. type comes from a closed vocabulary, so it is safe to branch on:
type | retryable | Means |
|---|---|---|
invalid_request | false | The request was refused on its merits. It will be refused again — change the request. |
provider_error | true | The job failed while it was being generated. |
provider_unavailable | true | The job could not be completed in time, or could not be confirmed with any provider. |
expired | true | The job passed its deadline before it completed. |
execution_start_failed | true | The job could not be started. |
unknown | true | The job failed without a reported reason. |
invalid_requestretryable · falseMeans · The request was refused on its merits. It will be refused again — change the request.provider_errorretryable · trueMeans · The job failed while it was being generated.provider_unavailableretryable · trueMeans · The job could not be completed in time, or could not be confirmed with any provider.expiredretryable · trueMeans · The job passed its deadline before it completed.execution_start_failedretryable · trueMeans · The job could not be started.unknownretryable · trueMeans · The job failed without a reported reason.retryable is the field to branch on rather than type: it is false for exactly one value today, and a
new type added later will carry the right retryable without your code changing. You are not charged for
a job that ends in any of these.
{
"id": "550e8400-...",
"object": "media.job",
"kind": "video",
"status": "succeeded",
"created": 1713200000,
"expires_at": 1713201800,
"progress": 1.0,
"results": [
{
"artifact_index": 0,
"url": "$SURPLUS_BASE_URL/media/artifacts/550e8400-.../0",
"content_type": "video/mp4",
"duration_seconds": 10,
"width": 1920,
"height": 1080,
"bytes": 5000000
}
],
"usage": {
"seller_cost_usdc": "80000",
"buyer_cost_usdc": "96000",
"settlement_status": "confirmed"
}
}Downloading the result
results[].url is an authenticated URL on this API, not a public link. Fetch it with the same
Authorization: Bearer *** you submitted with, or with the job's job_token:
curl -L -H "X-Job-Token: $JOB_TOKEN" \
$SURPLUS_BASE_URL/media/artifacts/$JOB_ID/0 -o out.mp4Follow redirects (-L): SI-hosted artifacts answer with a 302 to short-lived storage. A few models return a
provider-hosted URL instead, in which case url is that provider link and needs no header.
Artifacts do not live forever. The retention window runs from when the job reached a terminal state — 3 hours
by default, and never longer than the provider keeps a relayed file — and stored artifacts are purged within a day
regardless. Download promptly: past the window a fetch may still succeed for a short time, and then stops working.
We are rolling out a clear 404 artifact_expired for that case; until then an expired fetch surfaces as a plain
404.
Cancel Job
Auth: API key OR X-Job-Token header.
Cancellation is best-effort. If the provider has already completed the job, it may transition to succeeded instead.
Errors
| Status | Code | When |
|---|---|---|
400 | invalid_request | A malformed parameter, or an image-to-video-only model submitted with no source image |
402 | insufficient_credit / insufficient_balance / insufficient_allowance | The job's max_cost_usdc is more than you can cover on any rail |
402 | account_frozen / org_frozen / org_closed | The paying account is under review or closed |
404 | model_not_found | The model is not in the media catalog |
404 | no_sellers_for_model | No seller can serve this model on this endpoint. This includes a model whose only offers are listed against a host that does not run async video at all — those offers are excluded from routing rather than accepted and failed later, so the refusal arrives before you are charged |
503 | no_healthy_sellers | Sellers exist and can serve the endpoint, but none is currently healthy or able to accept this input. Retryable |
400Code · invalid_requestWhen · A malformed parameter, or an image-to-video-only model submitted with no source image402Code · insufficient_credit / insufficient_balance / insufficient_allowanceWhen · The job's max_cost_usdc is more than you can cover on any rail402Code · account_frozen / org_frozen / org_closedWhen · The paying account is under review or closed404Code · model_not_foundWhen · The model is not in the media catalog404Code · no_sellers_for_modelWhen · No seller can serve this model on this endpoint. This includes a model whose only offers are listed against a host that does not run async video at all — those offers are excluded from routing rather than accepted and failed later, so the refusal arrives before you are charged503Code · no_healthy_sellersWhen · Sellers exist and can serve the endpoint, but none is currently healthy or able to accept this input. RetryableA 404 is a statement about supply and will not fix itself on retry; a 503 is transient.
Cost Model
- Costs are USDC microdollars (1 USD = 1,000,000 microdollars).
- Download artifacts are cached/proxied for buyer access. Default artifact retention is 3 hours (
MEDIA_ARTIFACT_TTL_SECONDScan override it). - Seller selection prices every candidate offer from the catalog at submit time; a cost-multiplier offer applies its multiplier to that price. The provider's own final price is reconciled at settlement.
estimated_cost_usdcis the buyer estimate at submit time.max_cost_usdcis the reservation ceiling and the most you can be charged for the job — settlement is capped at it.- It is not simply a percentage of
estimated_cost_usdc, and it can be several times larger. We reserve enough to fail over to any seller in the candidate set without asking you again, so the ceiling is sized on the priciest candidate, not on the one we chose. A safety buffer is then applied on top: 10% for text-to-video and music, and 2× for image-input (image-to-video, transition, reference) jobs, whose final price is the provider's own and is only known when the render finishes. A job quoted at $0.08 against a set whose dearest member is 5× the cheapest therefore discloses a ceiling near $0.82. You are charged what the render actually costs, never the ceiling — the ceiling is only what we hold. - Jobs expire after 30 minutes if not completed. Completed artifact download retention defaults to 3 hours.