Skip to main content
API referenceVideo generations

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

POST/v1/video/generations

Auth: API key required (Authorization: Bearer ***).

  • modelstringrequired
    Model ID, e.g. venice-runway-gen4-5-text; legacy venice-video-gen maps to a live Venice model
  • promptstringrequired
    Text prompt (max 2000 chars)
  • duration_secondsinteger
    Video duration. Optional; omitted values use the model's cheapest/default duration when known
  • image_urlstring
    Image-to-video start frame — an https:// URL or a data: URI. Required by image-to-video-only models (see Image-to-Video below)
  • end_image_urlstring
    Transition end frame for models that interpolate between two stills (equivalent to input_images with role: "end")
  • input_imagesarray
    Source images for image-to-video / transition / reference models. Each entry is an https/data: URI string — positional [start] or [start, end] — or an object { "url": "...", "role": "start" | "end" | "reference" }. Max 8 images per request
  • resolutionstring
    Provider-supported resolution such as 480p, 720p, 1080p, 4k
  • aspect_ratiostring
    Provider-supported ratio such as 16:9, 9:16, 1:1, 4:3, 3:4, 21:9
  • audioboolean
    Include audio track when the model supports it
  • webhook_urlstring
    Accepted and validated, but not delivered yet — terminal-state callbacks are not enabled in production. Poll instead
  • metadataobject
    Client 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.

Response — 202 Acceptedjson
{
  "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-video id suffix (e.g. seedance-2-0-image-to-video, wan-2-7-image-to-video, seedance-1-5-pro-image-to-video) and list image-to-video in their supported_parameters. Query /v1/models and /api/markets for 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 a start and an end frame.
  • Frames & roles: the simplest form is a single image_url (the start frame). For a transition, add end_image_url, or use input_images with explicit roles. Untagged input_images are 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 or data: URI; bare base64 (without the data: prefix) and http:// URLs are rejected. URLs are passed to the provider as-is — the marketplace never fetches them.
Image-to-video submitjson
{
  "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

GET/v1/video/generations/:id

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:

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.

Response — 202 (pending) or 200 (terminal)json
{
  "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:

bash
curl -L -H "X-Job-Token: $JOB_TOKEN" \
  $SURPLUS_BASE_URL/media/artifacts/$JOB_ID/0 -o out.mp4

Follow 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

DELETE/v1/video/generations/:id

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

400Code · invalid_requestWhen · A malformed parameter, or an image-to-video-only model submitted with no source image
402Code · insufficient_credit / insufficient_balance / insufficient_allowanceWhen · The job's max_cost_usdc is more than you can cover on any rail
402Code · account_frozen / org_frozen / org_closedWhen · The paying account is under review or closed
404Code · model_not_foundWhen · The model is not in the media catalog
404Code · 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 charged
503Code · no_healthy_sellersWhen · Sellers exist and can serve the endpoint, but none is currently healthy or able to accept this input. Retryable

A 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_SECONDS can 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.
Why the ceiling is so much bigger than the estimate
estimated_cost_usdc — the quote for the chosen seller$0.08
max_cost_usdc — the reservation ceiling we hold$0.82
The hold is sized so the job can fail over to ANY seller in the candidate set without asking you again — so it is priced off the dearest candidate, not the one we chose. You are charged what the render actually costs.
  • estimated_cost_usdc is the buyer estimate at submit time.
  • max_cost_usdc is 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.