API
On this section
View as Markdown ↗

Get started

Core concepts

The VEED API gives you programmatic access to VEED's AI video models over a simple REST interface. Every model is reached the same way, so what you learn here holds for all 4 of them.

Models

  • Clean Audio — Remove background noise from speech, keeping quiet and distant words intact.
  • Fabric 1.0 — Turn an image and an audio track into a talking, lip-synced video.
  • Lipsync 2.0 — Re-sync an existing video to a new audio track.
  • Video Background Removal — Cut the background out of any video.

Authentication

Every request carries a workspace API key as a bearer token:

terminal
curl https://api.veed.io/v1/fabric-1.0 \
-H "Authorization: Bearer $VEED_API_KEY"

Create and revoke keys from your workspace dashboard. A key is a secret — keep it out of anything that runs in a browser or on a phone, where anyone can read it. A request without a valid key is rejected with 401 and the error code unauthenticated; a key that is valid but not entitled to the model gets permission_denied.

How generation works

Every generation endpoint is asynchronous, in two steps.

1. Submit a job. POST your inputs. The API either accepts the job — 202 Accepted, with a job_id and status PROCESSING — or rejects it outright, in which case no job is created and nothing is billed.

POST
/v1/fabric-1.0

2. Poll for the result. GET the job until it settles.

GET
/v1/fabric-1.0/{job_id}

The job envelope is the same for every model:

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. Poll at the interval the model advertises — 10 seconds for Fabric 1.0 — and treat anything other than PROCESSING as final. A GET for an unknown job_id returns 404.

There are two distinct kinds of failure, and they are reported differently. A submit can be rejected at the HTTP layer, before a job exists. An accepted job can still end in FAILED while rendering — reported on the poll response, not as an HTTP error. Handle both.

Media

Pass inputs as public http(s) URLs; the renderer fetches them itself, so a signed URL works and a localhost address does not. Results come back as URLs too, and those expire — X-Veed-Media-Expiration-Seconds on the request sets how long, defaulting to a day. Media retention covers that window and what the API keeps of the calls themselves.

Errors

Every HTTP error carries the same envelope, with a stable machine-readable code and a request id worth quoting to support:

error response
{
"error": {
  "code": "invalid_request",
  "message": "audio_url must be an http(s) URL",
  "request_id": "3f6f2b6e-8b1a-4b9e-9f0e-2f4a1c9d7e51",
  "details": [
    { "type": "validation", "field": "audio_url", "message": "must match an http(s) URL" }
  ]
}
}

The codes are:

invalid_requestunauthenticatedinsufficient_tokenspermission_deniednot_foundconflictrate_limitedunavailableinternal

Pricing

Usage-based, with no subscription: you are billed per job, only once it completes. Rates run from $0.008–$0.15, and each model is priced per second, frame, or minute of media, some with rounding or a minimum. See the full breakdown per model.

Every endpoint