API
On this section
View as Markdown ↗

Guide

Getting started with the Node SDK

Install the SDK, submit your first job, and poll it to completion — the submit-and-poll loop every VEED model shares.

Every VEED model works the same way: you submit a job, the API accepts it immediately, and you poll until it is done. This guide walks that loop end to end in Node, using Fabric 1.0 as the example — swap the client method and the inputs and the shape is identical for every other model.

Install

bash
npm install @veedstudio/sdk

The client reads VEED_API_KEY from the environment, so export the workspace key you created in the dashboard:

bash
export VEED_API_KEY="vp_..."

The whole loop

example.mjs
import { Veed } from "@veedstudio/sdk";

const client = new Veed(); // reads VEED_API_KEY

const job = await client.fabric.generate({
  audio_url: "https://static-assets.veed.io/api-examples/fabric-input.mp3",
  image_url: "https://static-assets.veed.io/api-examples/fabric-input.png",
  resolution: "720p",
});
console.log(job.result);

That is the entire integration. generate() submits the job and polls for you, honouring the interval the API advertises (10 seconds for this model), so you do not write a retry loop by hand.

What this model takes

image_urlurlrequired

URL of the source image to animate.

Must be an http(s) URL.
audio_urlurlrequired

URL of the audio track to lip-sync to.

Must be an http(s) URL.
resolutionenumrequired

Output video resolution.

Accepts720p480p

Both URLs must be publicly reachable over http(s) — the renderer fetches them itself, so a signed URL is fine but a localhost address is not.

resolution accepts 720p, 480p. It is required, and the reference and playground both show 720p as the example, which is the resolution most callers want.

Submitting and polling by hand

If you would rather drive the two calls yourself — a queue worker that persists the job id, say — they are just the two endpoints the SDK wraps:

POST
/v1/fabric-1.0
GET
/v1/fabric-1.0/{job_id}
example.mjs
import { Veed } from "@veedstudio/sdk";

const client = new Veed(); // reads VEED_API_KEY

const job = await client.fabric.submit({
  audio_url: "https://static-assets.veed.io/api-examples/fabric-input.mp3",
  image_url: "https://static-assets.veed.io/api-examples/fabric-input.png",
  resolution: "720p",
});
console.log(job.status);

The submit call answers 202 with a job_id and a status. Poll the second endpoint with that id until status leaves PROCESSING:

example.mjs
import { Veed } from "@veedstudio/sdk";

const client = new Veed(); // reads VEED_API_KEY

const job = await client.fabric.get("<job_id>");
console.log(job.status);

The job envelope you get back is the same either way:

credits_chargedintegeroptional

Credits charged for the job. Present once the job is COMPLETED and the final charge is known.

credits_estimatedintegeroptional

Credits quoted before the job ran. Present only on the response that created the job. This is an estimate, not the price: the charged amount can be higher or lower.

errorobjectoptionalJobErrorFabricErrorCode ↗

Failure information. Present once the job has FAILED.

Show 3 nested fields
codeenumrequired

Stable, machine-readable failure code for this job type.

Acceptsinput_validationcontent_moderationinvalid_fileaudio_too_longtransload_failedgeneration_failedtimeout
detailsarray of objectoptionalJobErrorDetail ↗

Optional structured failure details.

Show 3 nested fields
fieldstringoptional

Dotted path to the offending input, when applicable.

messagestringrequired

Human-readable explanation of this detail.

typestringrequired

The category of this detail entry.

messagestringrequired

Human-readable failure message.

job_iduuidrequired

Stable identifier of the job and of the resource it produces.

resultobjectoptionalFabricVideo ↗

The produced resource. Present once the job is COMPLETED.

Show 1 nested field
videoobjectrequiredFile ↗

Generated lip-synced video.

Show 4 nested fields
content_typestringoptional

The mime type of the file.

file_namestringoptional

The name of the file.

file_sizeintegeroptional

The size of the file in bytes.

urlstringrequired

The URL where the file can be downloaded from.

statusenumrequired

Current lifecycle state of the job.

AcceptsPROCESSINGCOMPLETEDFAILEDCANCELLED

status moves through PROCESSING, COMPLETED, FAILED, CANCELLED. Only COMPLETED carries a result; only FAILED carries an error.

When a job fails

An accepted job can still fail while rendering, and the failure is reported on the poll response rather than as an HTTP error. The codes this model can return are input_validation, content_moderation, invalid_file, audio_too_long, transload_failed, generation_failed, timeout.

Treat anything other than COMPLETED and PROCESSING as terminal: a CANCELLED or FAILED job will not change state again, and polling it further only burns rate limit.

What it costs

It costs $0.08–$0.15 per second of the generated video, billed on the output rather than on the source image. The pricing page breaks that down per resolution.

Next

  • Try the same inputs in the playground before you write any code
  • Every other model follows this submit-and-poll shape — the reference pages list the inputs each one takes