Fabric 1.0
image to talking video
POST /v1/fabric-1.0
Add an API key to run jobs
The playground calls the live API with your workspace key, which stays in this browser. Don't have one? API access is granted on request.
Input
URL of the audio track to lip-sync to.
URL of the source image to animate.
Output video resolution.
Output
Your generated result will appear here.
Fill in the inputs and hit run — jobs typically take a minute or two.
Fabric 1.0 — image to talking video
Turn a still image and an audio track into a talking video, with mouth movements synchronized to the speech. Give Fabric an image with a face plus the audio you want spoken, and it renders a lip-synced video at up to 720p.
The same endpoint handles the entire image-to-talking-video pipeline — there are no separate face detection, audio analysis, or video synthesis steps to run.
- Inputs: an image URL and an audio URL
- Output resolution:
480por720p - Output: an MP4 video
Common use cases: talking-avatar creation · video personalization · educational content · marketing videos
Failure codes
An accepted job can still fail during rendering. When status is FAILED, the error code is one of:
input_validationcontent_moderationinvalid_fileaudio_too_longtransload_failedgeneration_failedtimeoutFull flow
# Submit a job
curl -X POST "https://api.veed.io/v1/fabric-1.0" \
-H "Authorization: Bearer $VEED_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"audio_url": "https://media.veed.io/in.mp3",
"image_url": "https://media.veed.io/in.png",
"resolution": "720p"
}'
# Poll until COMPLETED (response includes data.job_id)
curl "https://api.veed.io/v1/fabric-1.0/{job_id}" \
-H "Authorization: Bearer $VEED_API_KEY"import { Veed } from "@veedstudio/sdk";
const client = new Veed(); // reads VEED_API_KEY
const job = await client.fabric.generate({
audio_url: "https://media.veed.io/in.mp3",
image_url: "https://media.veed.io/in.png",
resolution: "720p",
});
console.log(job.result);package main
import (
"context"
"fmt"
"log"
veed "github.com/veedstudio/veed-sdk-go"
)
func main() {
client, err := veed.NewClient() // reads VEED_API_KEY
if err != nil {
log.Fatal(err)
}
job, err := client.Fabric.Generate(context.Background(), veed.FabricInput{
AudioURL: "https://media.veed.io/in.mp3",
ImageURL: "https://media.veed.io/in.png",
Resolution: "720p",
})
if err != nil {
log.Fatal(err)
}
fmt.Printf("%+v\n", job.Result)
}/v1/fabric-1.0Submit a fabric-1.0 job
Start an asynchronous job that animates a source image to lip-sync it to an audio track, producing a talking video at the resolution you choose.
Inputs
image_url— public URL of the source image (should contain a face)audio_url— public URL of the audio track to speakresolution— output resolution:480por720p
What happens next
The job is accepted immediately — you get 202 Accepted with a job_id and status PROCESSING. Rendering runs in the background; poll GET /v1/fabric-1.0/{job_id} until the job is COMPLETED or FAILED.
Headers
X-Veed-Store-IOenumoptionalSet to 0 to not store this request's and response's bodies. They will then not be available in your request logs for debugging. Defaults to 1 (stored).
01Defaults to "1".X-Veed-Media-Expiration-SecondsintegeroptionalNumber of seconds before signed media URLs returned for this request expire. Defaults to 86400 (1 day).
86400.Request body FabricInput ↗
audio_urlurlrequiredURL of the audio track to lip-sync to.
image_urlurlrequiredURL of the source image to animate.
resolutionenumrequiredOutput video resolution.
720p480pResponses
Show 4 nested fields
Failure information. Present once the job has FAILED.
Show 3 nested fields
codeenumrequiredStable, machine-readable failure code for this job type.
input_validationcontent_moderationinvalid_fileaudio_too_longtransload_failedgeneration_failedtimeoutOptional structured failure details.
Show 3 nested fields
fieldstringoptionalDotted path to the offending input, when applicable.
messagestringrequiredHuman-readable explanation of this detail.
typestringrequiredThe category of this detail entry.
messagestringrequiredHuman-readable failure message.
job_iduuidrequiredStable identifier of the job and of the resource it produces.
The produced resource. Present once the job is COMPLETED.
Show 1 nested field
Generated lip-synced video.
Show 4 nested fields
content_typestringoptionalThe mime type of the file.
file_namestringoptionalThe name of the file.
file_sizeintegeroptionalThe size of the file in bytes.
urlstringrequiredThe URL where the file can be downloaded from.
statusenumrequiredCurrent lifecycle state of the job.
PROCESSINGCOMPLETEDFAILEDCANCELLEDX-Request-IDCorrelation id for this request, adopted from the request or minted at the edge.401UnauthorizedErrorResponse ↗
Show 4 nested fields
codeenumrequiredinvalid_requestunauthenticatedpermission_deniednot_foundconflictrate_limitedunavailableinternalShow 6 nested fields
fieldstringoptionalmessagestringoptionalreasonenumoptionalapi_key_expiredapi_key_inactiveapi_key_invalidapi_key_revokedjob_not_foundretry_after_msintegeroptionaltypestringrequiredvalueobjectoptionalmessagestringrequiredrequest_idstringrequiredX-Request-IDCorrelation id for this request, adopted from the request or minted at the edge.422Unprocessable EntityErrorResponse ↗
Show 4 nested fields
codeenumrequiredinvalid_requestunauthenticatedpermission_deniednot_foundconflictrate_limitedunavailableinternalShow 6 nested fields
fieldstringoptionalmessagestringoptionalreasonenumoptionalapi_key_expiredapi_key_inactiveapi_key_invalidapi_key_revokedjob_not_foundretry_after_msintegeroptionaltypestringrequiredvalueobjectoptionalmessagestringrequiredrequest_idstringrequiredX-Request-IDCorrelation id for this request, adopted from the request or minted at the edge.429Rate limit exceededErrorResponse ↗
Show 4 nested fields
codeenumrequiredinvalid_requestunauthenticatedpermission_deniednot_foundconflictrate_limitedunavailableinternalShow 6 nested fields
fieldstringoptionalmessagestringoptionalreasonenumoptionalapi_key_expiredapi_key_inactiveapi_key_invalidapi_key_revokedjob_not_foundretry_after_msintegeroptionaltypestringrequiredvalueobjectoptionalmessagestringrequiredrequest_idstringrequiredRetry-AfterSeconds until the rate limit resets.X-RateLimit-ClassThe rate-limit class that was hit (read, mutation, ai-generation).X-RateLimit-LimitRequest budget for the matched class.X-RateLimit-RemainingRemaining requests in the current window.X-RateLimit-ResetUnix time (seconds) when the budget resets.X-Request-IDCorrelation id for this request, adopted from the request or minted at the edge.500Internal Server ErrorErrorResponse ↗
Show 4 nested fields
codeenumrequiredinvalid_requestunauthenticatedpermission_deniednot_foundconflictrate_limitedunavailableinternalShow 6 nested fields
fieldstringoptionalmessagestringoptionalreasonenumoptionalapi_key_expiredapi_key_inactiveapi_key_invalidapi_key_revokedjob_not_foundretry_after_msintegeroptionaltypestringrequiredvalueobjectoptionalmessagestringrequiredrequest_idstringrequiredX-Request-IDCorrelation id for this request, adopted from the request or minted at the edge.Example request
curl -X POST "https://api.veed.io/v1/fabric-1.0" \
-H "Authorization: Bearer $VEED_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"audio_url": "https://media.veed.io/in.mp3",
"image_url": "https://media.veed.io/in.png",
"resolution": "720p"
}'import { Veed } from "@veedstudio/sdk";
const client = new Veed(); // reads VEED_API_KEY
const job = await client.fabric.submit({
audio_url: "https://media.veed.io/in.mp3",
image_url: "https://media.veed.io/in.png",
resolution: "720p",
});
console.log(job.status);package main
import (
"context"
"fmt"
"log"
veed "github.com/veedstudio/veed-sdk-go"
)
func main() {
client, err := veed.NewClient() // reads VEED_API_KEY
if err != nil {
log.Fatal(err)
}
job, err := client.Fabric.Submit(context.Background(), veed.FabricInput{
AudioURL: "https://media.veed.io/in.mp3",
ImageURL: "https://media.veed.io/in.png",
Resolution: "720p",
})
if err != nil {
log.Fatal(err)
}
fmt.Println(job.Status)
}Example response
{
"data": {
"error": {
"code": "input_validation",
"details": [
{
"field": "<field>",
"message": "<message>",
"type": "<type>"
}
],
"message": "<message>"
},
"job_id": "123e4567-e89b-12d3-a456-426614174000",
"result": {
"video": {
"content_type": "video/mp4",
"file_name": "<file_name>",
"file_size": 0,
"url": "<url>"
}
},
"status": "PROCESSING"
}
}/v1/fabric-1.0/{job_id}Get a fabric-1.0 job
Retrieve the current state of a fabric-1.0 job by its job_id.
The response uses the shared job envelope, whose status is one of:
PROCESSING— still rendering; the result is emptyCOMPLETED— done; the result holds the rendered videoFAILED— the job was accepted but rendering failed; the error holds a fabric-1.0 failure code
Poll this endpoint until the status is COMPLETED or FAILED. An unknown job_id returns 404 Not Found.
Path parameters
job_iduuidrequiredIdentifier of the fabric-1.0 job, returned when the job was submitted.
Headers
X-Veed-Store-IOenumoptionalSet to 0 to not store this request's and response's bodies. They will then not be available in your request logs for debugging. Defaults to 1 (stored).
01Defaults to "1".X-Veed-Media-Expiration-SecondsintegeroptionalNumber of seconds before signed media URLs returned for this request expire. Defaults to 86400 (1 day).
86400.Responses
Show 4 nested fields
Failure information. Present once the job has FAILED.
Show 3 nested fields
codeenumrequiredStable, machine-readable failure code for this job type.
input_validationcontent_moderationinvalid_fileaudio_too_longtransload_failedgeneration_failedtimeoutOptional structured failure details.
Show 3 nested fields
fieldstringoptionalDotted path to the offending input, when applicable.
messagestringrequiredHuman-readable explanation of this detail.
typestringrequiredThe category of this detail entry.
messagestringrequiredHuman-readable failure message.
job_iduuidrequiredStable identifier of the job and of the resource it produces.
The produced resource. Present once the job is COMPLETED.
Show 1 nested field
Generated lip-synced video.
Show 4 nested fields
content_typestringoptionalThe mime type of the file.
file_namestringoptionalThe name of the file.
file_sizeintegeroptionalThe size of the file in bytes.
urlstringrequiredThe URL where the file can be downloaded from.
statusenumrequiredCurrent lifecycle state of the job.
PROCESSINGCOMPLETEDFAILEDCANCELLEDX-Request-IDCorrelation id for this request, adopted from the request or minted at the edge.401UnauthorizedErrorResponse ↗
Show 4 nested fields
codeenumrequiredinvalid_requestunauthenticatedpermission_deniednot_foundconflictrate_limitedunavailableinternalShow 6 nested fields
fieldstringoptionalmessagestringoptionalreasonenumoptionalapi_key_expiredapi_key_inactiveapi_key_invalidapi_key_revokedjob_not_foundretry_after_msintegeroptionaltypestringrequiredvalueobjectoptionalmessagestringrequiredrequest_idstringrequiredX-Request-IDCorrelation id for this request, adopted from the request or minted at the edge.404Not FoundErrorResponse ↗
Show 4 nested fields
codeenumrequiredinvalid_requestunauthenticatedpermission_deniednot_foundconflictrate_limitedunavailableinternalShow 6 nested fields
fieldstringoptionalmessagestringoptionalreasonenumoptionalapi_key_expiredapi_key_inactiveapi_key_invalidapi_key_revokedjob_not_foundretry_after_msintegeroptionaltypestringrequiredvalueobjectoptionalmessagestringrequiredrequest_idstringrequiredX-Request-IDCorrelation id for this request, adopted from the request or minted at the edge.422Unprocessable EntityErrorResponse ↗
Show 4 nested fields
codeenumrequiredinvalid_requestunauthenticatedpermission_deniednot_foundconflictrate_limitedunavailableinternalShow 6 nested fields
fieldstringoptionalmessagestringoptionalreasonenumoptionalapi_key_expiredapi_key_inactiveapi_key_invalidapi_key_revokedjob_not_foundretry_after_msintegeroptionaltypestringrequiredvalueobjectoptionalmessagestringrequiredrequest_idstringrequiredX-Request-IDCorrelation id for this request, adopted from the request or minted at the edge.429Rate limit exceededErrorResponse ↗
Show 4 nested fields
codeenumrequiredinvalid_requestunauthenticatedpermission_deniednot_foundconflictrate_limitedunavailableinternalShow 6 nested fields
fieldstringoptionalmessagestringoptionalreasonenumoptionalapi_key_expiredapi_key_inactiveapi_key_invalidapi_key_revokedjob_not_foundretry_after_msintegeroptionaltypestringrequiredvalueobjectoptionalmessagestringrequiredrequest_idstringrequiredRetry-AfterSeconds until the rate limit resets.X-RateLimit-ClassThe rate-limit class that was hit (read, mutation, ai-generation).X-RateLimit-LimitRequest budget for the matched class.X-RateLimit-RemainingRemaining requests in the current window.X-RateLimit-ResetUnix time (seconds) when the budget resets.X-Request-IDCorrelation id for this request, adopted from the request or minted at the edge.500Internal Server ErrorErrorResponse ↗
Show 4 nested fields
codeenumrequiredinvalid_requestunauthenticatedpermission_deniednot_foundconflictrate_limitedunavailableinternalShow 6 nested fields
fieldstringoptionalmessagestringoptionalreasonenumoptionalapi_key_expiredapi_key_inactiveapi_key_invalidapi_key_revokedjob_not_foundretry_after_msintegeroptionaltypestringrequiredvalueobjectoptionalmessagestringrequiredrequest_idstringrequiredX-Request-IDCorrelation id for this request, adopted from the request or minted at the edge.Example request
curl "https://api.veed.io/v1/fabric-1.0/{job_id}" \
-H "Authorization: Bearer $VEED_API_KEY"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);package main
import (
"context"
"fmt"
"log"
veed "github.com/veedstudio/veed-sdk-go"
)
func main() {
client, err := veed.NewClient() // reads VEED_API_KEY
if err != nil {
log.Fatal(err)
}
job, err := client.Fabric.Get(context.Background(), "<job_id>")
if err != nil {
log.Fatal(err)
}
fmt.Println(job.Status)
}Example response
{
"data": {
"error": {
"code": "input_validation",
"details": [
{
"field": "<field>",
"message": "<message>",
"type": "<type>"
}
],
"message": "<message>"
},
"job_id": "123e4567-e89b-12d3-a456-426614174000",
"result": {
"video": {
"content_type": "video/mp4",
"file_name": "<file_name>",
"file_size": 0,
"url": "<url>"
}
},
"status": "PROCESSING"
}
}Rates
The price depends on how the job is submitted. Every rate is per second of the generated video.
Resolutionresolution | Price |
|---|---|
480p | $0.08 |
720p Default | $0.15 |
How it is billed
- Charged per second of the generated video, in USD.
resolutionchanges the rate — Output video resolution.
Estimate a job
Prices are per second of the generated video.
resolution- Measured
- 10 seconds
- Rate
- $0.15 / second