Video Generation
Generate videos with an OpenAI-compatible async API and signed completion callbacks
LLMGateway supports asynchronous video generation through an OpenAI-compatible POST /v1/videos flow.
Currently available models:
- FLUX 3 Max (
flux-3-max) throughfal-ai(720p, 1080p; 5–20 seconds; optional audio; first/last frames) - Veo 3.1 through
google-vertex(720p, 1080p, 4k) - Gemini Omni 1.1 Flash through
google-ai-studio(360p, 720p, 1080p, 4k; frames, references, and source video edit/extend; always with audio) - Seedance 2.5 through
bytedance(480p, 720p, 1080p; clips up to 30 seconds) - Seedance 2.0 and Seedance 1.5 Pro through
bytedance(720p, 1080p), Seedance 2.0 Fast throughbytedance(720p only) - Seedance 2.0 Mini through
bytedance(480p, 720p) - KLING v3.0 and KLING v3.0 Turbo through
atlascloud(720p, 1080p; KLING v3.0 also 4k), KLING v3.0 Pro throughatlascloud(1080p only) - MiniMax H3 Max through
minimax(480p, 768p; clips from 5 to 15 seconds, always with audio) - VEED Fabric 1.0 and VEED Fabric 1.0 Fast through
atlascloud(480p, 720p; lip-synced talking video from one image and one speech track, as long as the audio)
You can find the current list of video-capable models on our models page with the video filter enabled or programmatically through the /v1/models endpoint.
BytePlus retires Seedance 1.5 Pro on November 11, 2026 at 17:00 UTC+8 (09:00 UTC). Migrate to Seedance 2.0 Mini before then; existing endpoints will not migrate automatically. Review BytePlus’s retirement notice and evaluate the replacement before switching.
What Works Today
POST /v1/videosGET /v1/videos/{video_id}GET /v1/videos/{video_id}/content- Optional signed callbacks with
callback_urlandcallback_secret
Request Format
LLMGateway currently supports a focused subset of the OpenAI video API.
Supported fields
| Field | Type | Required | Description |
|---|---|---|---|
model | string | yes | Any video-capable model from the filtered models page |
prompt | string | yes | Text prompt for the video |
seconds | number | yes | Duration in seconds. Supported values depend on the model (see below) |
size | string | no | widthxheight, limited to the sizes supported by the selected model and provider |
audio | boolean | no | Whether to include audio in the output (default true). Only honored when the model supports both audio and silent output |
reasoning_effort | string | no | FLUX 3 Max only: prompt reasoning effort, low or high (default high); not a visual-quality or resolution setting |
image | object | no | Optional first frame for image-to-video generation (see first/last frame inputs below) |
last_frame | object | no | Optional ending frame when image is provided (see first/last frame inputs below) |
reference_images | array | no | One to three provider-specific image inputs |
input_reference | object | no | Alias for one or more reference_images |
reference_videos | array | no | One to three reference video HTTPS URLs (Seedance 2.x and Gemini Omni, see below) |
reference_audios | array | no | One to three reference audio HTTPS URLs (Seedance 2.x and VEED Fabric, see below) |
video | string or object | no | LLMGateway extension: source video HTTPS URL to edit or extend (Gemini Omni only, see below) |
video_task | string | no | LLMGateway extension: edit (default) or extend for video |
callback_url | string | no | LLMGateway extension for completion webhooks |
callback_secret | string | no | LLMGateway extension used to sign webhook deliveries |
Sizes and durations by model
| Model family | Provider | Supported sizes | Supported durations |
|---|---|---|---|
| FLUX 3 Max | fal-ai | 1280x720, 720x1280, 1920x1080, 1080x1920 | 5–20 |
| Veo 3.1 | google-vertex | 1280x720, 720x1280, 1920x1080, 1080x1920, 3840x2160, 2160x3840 | 4, 6, 8, 10 |
| Gemini Omni 1.1 Flash | google-ai-studio | 640x360, 360x640, 1280x720, 720x1280, 1920x1080, 1080x1920, 3840x2160, 2160x3840 | 3–10 |
| Seedance 2.5 | bytedance | 848x480, 854x480, 480x854, 1280x720, 720x1280, 1920x1080, 1080x1920 | 4–30 |
| Seedance 2.0 | bytedance | 1280x720, 720x1280, 1920x1080, 1080x1920 | 4–15 |
| Seedance 2.0 Fast | bytedance | 1280x720, 720x1280 | 4–15 |
| Seedance 2.0 Mini | bytedance | 1280x720, 720x1280, 848x480, 854x480, 480x854 | 4–15 |
| Seedance 1.5 Pro | bytedance | 1280x720, 720x1280, 1920x1080, 1080x1920 | 5, 10 |
| KLING v3.0 | atlascloud | 1280x720, 720x1280, 1920x1080, 1080x1920, 3840x2160, 2160x3840 | 5, 10 |
| KLING v3.0 Turbo | atlascloud | 1280x720, 720x1280, 1920x1080, 1080x1920 | 5, 10 |
| KLING v3.0 Pro | atlascloud | 1920x1080, 1080x1920 | 5, 10 |
| MiniMax H3 Max | minimax | 848x480, 854x480, 480x854, 1366x768, 768x1366 | 5–15 |
| VEED Fabric 1.0, Fast | atlascloud | 854x480, 480x854, 1280x720, 720x1280 | audio length, ≤ 300 |
Requests return 400 when the selected provider cannot serve the requested size or seconds. Seedance and KLING v3.0 derive aspect_ratio from the requested size (16:9 for landscape, 9:16 for portrait).
KLING v3.0 Turbo, MiniMax H3 Max, and Gemini Omni 1.1 Flash always generate audio and do not support audio: false; silent requests return a 400. Use KLING v3.0 (kling-v3-0) when you need silent output.
FLUX 3 Max options
Use flux-3-max for automatic routing or fal-ai/flux-3-max to pin fal. Choose 720p or 1080p in landscape (16:9) or portrait (9:16), and any integer duration from 5 through 20 seconds. audio can be true (default) or false.
reasoning_effort controls prompt reasoning: low or high (default). The gateway forwards it as fal's reasoning_level. It does not select visual quality; use size for output resolution. Other models reject an explicit reasoning_effort.
FLUX accepts a start frame (image) and an optional end frame (last_frame, requires image). It does not accept arbitrary reference images, reference video/audio, or source video inputs.
curl -X POST "https://api.llmgateway.io/v1/videos" \
-H "Authorization: Bearer $LLM_GATEWAY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "fal-ai/flux-3-max",
"prompt": "A cinematic aerial shot above a rainforest waterfall at sunrise",
"seconds": 5,
"size": "1920x1080",
"audio": false,
"reasoning_effort": "low"
}'First/last frame inputs
Frame inputs interpolate a video between a starting frame and an optional ending frame. You provide the first frame as image and, optionally, the ending frame as last_frame. The gateway tags each one with the correct role for the provider, so you don't set roles yourself.
| Field | Required | Accepted input | Available on |
|---|---|---|---|
image | for frame mode | HTTPS URL or base64 data URL | FLUX 3 Max (fal-ai), Seedance 2.x (bytedance), KLING v3.0 / Pro / Turbo (atlascloud), Veo 3.1 (google-vertex), Gemini Omni (google-ai-studio), minimax, xai |
last_frame | no (needs image) | HTTPS URL or base64 data URL | FLUX 3 Max (fal-ai), Seedance 2.x (bytedance), KLING v3.0 / Pro / Turbo (atlascloud), Veo 3.1 (google-vertex), Gemini Omni (google-ai-studio), MiniMax H3 Max (minimax) |
Rules and limits
- Seedance scope. Frame inputs are supported on Seedance 2.5, Seedance 2.0, Seedance 2.0 Fast, and Seedance 2.0 Mini (
seedance-2-5,seedance-2-0,seedance-2-0-fast,seedance-2-0-mini). Sendingimage/last_frameto Seedance 1.5 Pro or any other ByteDance model returns a400. - KLING scope. Frame inputs are supported on KLING v3.0, KLING v3.0 Pro, and KLING v3.0 Turbo (
kling-v3-0,kling-v3-0-pro,kling-v3-0-turbo). The gateway uploads base64 frames to AtlasCloud's media endpoint automatically, so both HTTPS URLs and base64 data URLs are accepted. - FLUX scope. FLUX 3 Max (
fal-ai) accepts first and last frames as HTTPS URLs or base64 data URLs; useimagefor the start andlast_framefor the optional end. last_framerequiresimage. Providinglast_framewithoutimagereturns a400.- Not combinable with references. First/last frame inputs (
image,last_frame) cannot be combined with reference inputs (reference_images,input_reference,reference_videos,reference_audios).
Example (Seedance 2.0)
curl -X POST "https://api.llmgateway.io/v1/videos" \
-H "Authorization: Bearer $LLM_GATEWAY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "seedance-2-0",
"prompt": "Morph smoothly from the first frame into the last frame",
"seconds": 5,
"size": "1280x720",
"image": { "image_url": "https://example.com/first-frame.png" },
"last_frame": { "image_url": "https://example.com/last-frame.png" }
}'Example (KLING v3.0 image-to-video)
curl -X POST "https://api.llmgateway.io/v1/videos" \
-H "Authorization: Bearer $LLM_GATEWAY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "kling-v3-0",
"prompt": "Animate the scene with gentle camera motion",
"seconds": 5,
"size": "1280x720",
"image": { "image_url": "https://example.com/first-frame.png" }
}'Reference-guided generation
Seedance 2.x (seedance-2-5, seedance-2-0, seedance-2-0-fast, seedance-2-0-mini) can generate a video that is guided by reference images, videos, and audio — sometimes called omni-reference. You attach references as top-level fields in the same POST /v1/videos payload; the gateway forwards each one to the provider tagged with the correct role, so you don't set roles yourself.
| Reference type | Payload field | Count | Accepted input | Available on |
|---|---|---|---|---|
| Image | reference_images (input_reference alias) | 1–3 | HTTPS URL or base64 data URL | Seedance 2.x, Veo 3.1 (google-vertex), Gemini Omni (google-ai-studio), VEED Fabric (exactly 1) |
| Video | reference_videos | 1–3 | HTTPS URL only | Seedance 2.x, Gemini Omni (google-ai-studio) |
| Audio | reference_audios | 1–3 | HTTPS URL only | Seedance 2.x, VEED Fabric (exactly 1) |
Each list item accepts either a bare URL string or an object form:
reference_images:"https://…/subject.png"or{ "image_url": "https://…/subject.png" }reference_videos:"https://…/motion.mp4"or{ "video_url": "https://…/motion.mp4" }reference_audios:"https://…/track.mp3"or{ "audio_url": "https://…/track.mp3" }
You can mix all three reference types in one request. The prompt can be a light instruction (for example "adapt this to show more detail") — the references drive the result.
Rules and limits
- HTTPS only for video and audio.
reference_videosandreference_audiosmust be publicly reachable HTTPS URLs (the provider fetches them). base64 data URLs are rejected for video/audio; images may be HTTPS URLs or base64 data URLs. - Reference video resolution. Seedance requires reference video frames to be at least ~409,600 pixels (roughly 480p or larger). Low-resolution clips such as 360p are rejected with a
400. - Not combinable with frames. Reference inputs (
reference_images,reference_videos,reference_audios) cannot be combined with the first/last frame inputs (image,last_frame). - Provider scope. Reference videos are only supported on Seedance 2.x and Gemini Omni, and reference audio only on Seedance 2.x and VEED Fabric; sending them to other models returns a
400. KLING v3.0 does not support any reference inputs (reference_images,reference_videos,reference_audios); use first/last frame inputs instead. - Gemini Omni references. Use up to 3 reference video clips of about 3 seconds each; their audio is ignored. Refer to references in the prompt as
<IMAGE_REF_0>or<VIDEO_REF_0>to say how each one is used. - Moderation still applies. The output is subject to the provider's content moderation. Blocked generations finish as
failedand are logged with acontent_filterfinish reason. The gateway content filter may also reject the request with a403before a job is created.
Examples
Reference images only (subjects / style):
curl -X POST "https://api.llmgateway.io/v1/videos" \
-H "Authorization: Bearer $LLM_GATEWAY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "seedance-2-0",
"prompt": "The subject walks through a neon-lit market at night",
"seconds": 5,
"size": "1280x720",
"reference_images": [
{ "image_url": "https://example.com/subject.png" },
{ "image_url": "https://example.com/style.png" }
]
}'Reference video only (motion / scene — let the clip drive the output):
curl -X POST "https://api.llmgateway.io/v1/videos" \
-H "Authorization: Bearer $LLM_GATEWAY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "seedance-2-0",
"prompt": "adapt this to show more detail",
"seconds": 5,
"size": "1280x720",
"reference_videos": ["https://example.com/reference-motion.mp4"]
}'All three reference types combined:
curl -X POST "https://api.llmgateway.io/v1/videos" \
-H "Authorization: Bearer $LLM_GATEWAY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "seedance-2-0",
"prompt": "The subject performs the choreography from the reference video",
"seconds": 5,
"size": "1280x720",
"reference_images": [
{ "image_url": "https://example.com/subject.png" }
],
"reference_videos": [
"https://example.com/reference-motion.mp4"
],
"reference_audios": [
"https://example.com/reference-track.mp3"
]
}'Talking video (VEED Fabric)
veed-fabric-1-0 and veed-fabric-1-0-fast animate one image with a face into a lip-synced video of it speaking an audio track. Send exactly one image as input_reference (or reference_images; HTTPS URL or base64 data URL) and exactly one speech clip as reference_audios (HTTPS URL only). Other inputs and audio: false return a 400.
sizeonly selects the resolution (480p or 720p); the output keeps the image's aspect ratio.- The video is as long as the audio, up to 300 seconds. Credits are reserved for the 300-second maximum and settled to the measured length of the generated video.
secondsis still required (up to300); set it to the audio's length, since it is billed only when the output length cannot be measured. promptis required but does not steer the output; it is still checked by the content filter.
curl -X POST "https://api.llmgateway.io/v1/videos" \
-H "Authorization: Bearer $LLM_GATEWAY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "veed-fabric-1-0",
"prompt": "The presenter reads the script",
"seconds": 12,
"size": "1280x720",
"input_reference": { "image_url": "https://example.com/presenter.png" },
"reference_audios": ["https://example.com/script.mp3"]
}'Edit or extend a video (Gemini Omni)
gemini-omni-1.1-flash can edit or extend a source video passed as video, a publicly reachable HTTPS URL (or { "video_url": "…" }) of up to 10 seconds. video_task selects the operation:
video_task | Result |
|---|---|
edit (default) | The source with the prompt's changes, at the source's length and aspect ratio; seconds must still be a supported duration (3–10) but does not set the length |
extend | The source followed by a seconds-long continuation; only the continuation's video tokens are billed |
size selects the output resolution. A source video cannot be combined with frame or reference inputs. Simple prompts work best for edits, for example "Make this video anime. Keep everything else the same." Editing or extending an uploaded video is not available to callers in the EEA, Switzerland, and the United Kingdom.
curl -X POST "https://api.llmgateway.io/v1/videos" \
-H "Authorization: Bearer $LLM_GATEWAY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gemini-omni-1.1-flash",
"prompt": "Extend this video. The camera keeps walking along the path.",
"size": "1280x720",
"seconds": 6,
"video": "https://example.com/source.mp4",
"video_task": "extend"
}'Not supported yet
- multipart uploads
nvalues other than1- remix/list/delete video endpoints
Create a Video
Credits-billed video jobs are gated on their estimated cost before anything is submitted upstream. The estimate is the model's per-second rate for the requested resolution (the audio-inclusive rate when the model prices audio separately) times the duration, plus any input-image price. Your organization must hold at least that amount, and never less than $1.00, beyond what its still-running video jobs already reserve; otherwise the request fails with 402. The estimate is reserved when the job is created and settled to the actual cost when the job finishes, so a burst of submissions cannot spend more than the balance covers. Seedance requests with reference videos reserve the output duration plus the maximum total input-video duration: 30 seconds for Seedance 2.5 or 15 seconds for the 2.0 series. This conservative estimate uses the undiscounted per-second equivalent; final billing uses actual provider tokens and the video-input tier.
Video pricing is per generated second or per reported video token, depending on the model. Audio changes the price only on models with separate audio and silent rates.
Veo 3.1:
| Model | Provider | Supported sizes | Price |
|---|---|---|---|
veo-3.1-generate-preview | google-vertex | 1280x720, 720x1280, 1920x1080, 1080x1920 | $0.40 / second |
veo-3.1-fast-generate-preview | google-vertex | 1280x720, 720x1280, 1920x1080, 1080x1920 | $0.15 / second |
veo-3.1-generate-preview | google-vertex | 3840x2160, 2160x3840 | $0.60 / second |
veo-3.1-fast-generate-preview | google-vertex | 3840x2160, 2160x3840 | $0.35 / second |
Gemini Omni 1.1 Flash bills video output at $17.50 / 1M video tokens, which works out to the per-second rates below, plus input tokens (text, images, and input video) at $1.50 / 1M and thinking tokens at $9.00 / 1M, all as reported by the upstream usage. An edit's length follows its source, so the reservation assumes the 10-second maximum:
| Model | Provider | Resolution | Video output |
|---|---|---|---|
gemini-omni-1.1-flash | google-ai-studio | 360p | $0.0338 / second |
gemini-omni-1.1-flash | google-ai-studio | 720p | $0.1014 / second |
gemini-omni-1.1-flash | google-ai-studio | 1080p | $0.1520 / second |
gemini-omni-1.1-flash | google-ai-studio | 4k | $0.3041 / second |
Seedance (ByteDance) bills the provider's usage.completion_tokens, not rounded output seconds. These token counts include reference-video consumption and any provider minimum. The rate depends on output resolution and whether the input contains a video:
| Model | Resolution | Without video input (USD / 1M tokens) | With video input (USD / 1M tokens) |
|---|---|---|---|
seedance-2-5 | 480p, 720p | $10.70 | $6.40 |
seedance-2-5 | 1080p | $11.70 | $7.00 |
seedance-2-0 | 720p | $7.00 | $4.30 |
seedance-2-0 | 1080p | $7.70 | $4.70 |
seedance-2-0-fast | 720p | $5.60 | $3.30 |
seedance-2-0-mini | 480p, 720p | $3.50 | $2.10 |
Generated audio does not change these Seedance 2.x token rates. Reference images or audio alone use the without video input tier. Pixel dimensions, aspect ratio, input-video length, and output frames determine token consumption; a per-second estimate is not the final charge. For example, Seedance 2.0 Mini's 480p landscape output is 864×496, regardless of its nominal requested size.
seedance-1-5-pro costs $2.40 / 1M tokens with generated audio or $1.20 / 1M tokens without audio, at either supported resolution. Its requested resolution is forwarded explicitly. This mapping retires on November 11, 2026. Offline/flex and Draft settings are not exposed by this API.
A successful provider response without valid billing usage is retried up to 12 times before settlement and completion callbacks. If billing data is still missing, the completed video remains available with its cost unsettled, automatic polling stops, and an operator must reconcile the verified usage and pricing context. Its credit reservation remains held beyond the normal two-hour window until settlement; the gateway never substitutes a guessed charge. See the official BytePlus pricing and billing rules.
KLING (AtlasCloud):
| Model | Provider | Resolution | With audio | Video only |
|---|---|---|---|---|
kling-v3-0 | atlascloud | 720p | $0.126 / second | $0.084 / second |
kling-v3-0 | atlascloud | 1080p | $0.168 / second | $0.112 / second |
kling-v3-0 | atlascloud | 4k | $0.42 / second | $0.42 / second |
kling-v3-0-pro | atlascloud | 1080p | $0.168 / second | $0.112 / second |
kling-v3-0-turbo | atlascloud | 720p | $0.168 / second | n/a (audio only) |
kling-v3-0-turbo | atlascloud | 1080p | $0.21 / second | n/a (audio only) |
VEED Fabric (AtlasCloud), billed per second of generated video; the reservation assumes the 300-second maximum:
| Model | Provider | 480p | 720p |
|---|---|---|---|
veed-fabric-1-0 | atlascloud | $0.088 / second | $0.165 / second |
veed-fabric-1-0-fast | atlascloud | $0.11 / second | $0.22 / second |
curl -X POST "https://api.llmgateway.io/v1/videos" \
-H "Authorization: Bearer $LLM_GATEWAY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "veo-3.1-generate-preview",
"prompt": "A cinematic aerial shot flying above a rainforest waterfall at sunrise",
"seconds": 8,
"size": "1920x1080"
}'Example response:
{
"id": "v_123",
"object": "video",
"model": "veo-3.1-generate-preview",
"status": "queued",
"progress": 0,
"created_at": 1773600000,
"completed_at": null,
"expires_at": null,
"error": null
}Retrieve Job Status
curl "https://api.llmgateway.io/v1/videos/v_123" \
-H "Authorization: Bearer $LLM_GATEWAY_API_KEY"Typical statuses:
queuedin_progresscompletedfailedcanceledexpired
Once a job reaches a terminal status and has been billed, the response (and the signed callback payload) includes its cost in USD:
"usage": {
"cost": 0.4,
"cost_details": { "video_output_cost": 0.4, "image_input_cost": 0 }
}Failed, canceled, and expired jobs report a cost of 0.
google-vertex follows Vertex AI's long-running operation flow. The gateway submits Veo generation with predictLongRunning, polls with fetchPredictOperation, and streams the final bytes through the gateway content endpoint once the operation is done.
google-ai-studio uses the Gemini Interactions API. The gateway creates a background interaction, polls it until the video is ready, and streams the generated file through the gateway content endpoint. Google deletes the generated file after 48 hours, which the job reports as expires_at.
fal-ai uses fal's asynchronous queue API. The gateway submits FLUX 3 Max to the text-to-video or image-to-video endpoint, polls the queued request, and exposes the final video through the gateway content endpoint.
bytedance uses the ModelArk /contents/generations/tasks endpoint. The gateway submits the job, polls the upstream task status, and exposes the final video bytes through the gateway content endpoint once the task succeeds.
atlascloud uses the AtlasCloud /api/v1/model/generateVideo endpoint and polls /api/v1/model/prediction/{id} for status. The gateway resolves the upstream KLING variant (standard, pro, turbo, or 4k) and task type (text-to-video or image-to-video) from your request, then streams the final video bytes through the gateway content endpoint once the prediction completes.
Download the Video
Job polling and the direct /v1/videos/{video_id}/content endpoint require a valid key with project access and, for end-user sessions, ownership of the job’s wallet. Applicable source-IP restrictions still apply. Enabled key policies additionally check historical video access against both organization and key requirements; organization-only policies do not retroactively block historical downloads.
Signed bearer URLs can appear in completed job responses (content[].url), dashboard links, and exports. They are scoped to one video job or log and an expiry. Treat the whole URL as a credential: anyone holding it can download that output without an API key until the signed expiry (normally seven days), provided the underlying video is still available. BytePlus Seedance provider URLs expire after 24 hours: download those videos within that window even if the gateway token remains valid. Changing an API key or compliance policy does not revoke a previously issued signed link.
Production deployments must configure LLM_VIDEO_CONTENT_JWT_SECRET. Both job- and log-scoped links honor its development-fallback and revocation controls: rotating this secret revokes both. Gateway hash-keyring rotations preserve job links while their previous key remains retained. Never enable VIDEO_CONTENT_TOKEN_ALLOW_DEV=true in production: without a configured secret it activates the fixed, public development signing key regardless of NODE_ENV, allowing video-download tokens to be forged. Use that fallback only for local development; false or another value does not enable it.
Once the job is complete, stream the resulting video bytes from the content endpoint:
curl "https://api.llmgateway.io/v1/videos/v_123/content" \
-H "Authorization: Bearer $LLM_GATEWAY_API_KEY" \
--output video.mp4Signed Callbacks
LLMGateway can notify your application when the job reaches a terminal state.
curl -X POST "https://api.llmgateway.io/v1/videos" \
-H "Authorization: Bearer $LLM_GATEWAY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "veo-3.1-fast-generate-preview",
"prompt": "A slow-motion close-up of waves crashing against black volcanic rock",
"seconds": 8,
"callback_url": "https://example.com/webhooks/video",
"callback_secret": "whsec_your_secret_here"
}'Delivery behavior
- Callbacks are sent only for terminal states in v1
- Event types are
video.completedandvideo.failed - Deliveries retry with exponential backoff on network errors, timeouts, and non-2xx responses
- Each attempt is recorded internally in the webhook delivery log table
Headers
webhook-idwebhook-timestampwebhook-signature
Signature format
LLMGateway signs the string:
{webhook-id}.{webhook-timestamp}.{raw-request-body}using HMAC-SHA256 with your callback_secret, then sends:
webhook-signature: v1,{base64_signature}Verification example
import { createHmac, timingSafeEqual } from "node:crypto";
function verifyWebhook(
body: string,
webhookId: string,
webhookTimestamp: string,
webhookSignature: string,
secret: string,
) {
const expected = createHmac("sha256", secret)
.update(`${webhookId}.${webhookTimestamp}.${body}`)
.digest("base64");
const provided = webhookSignature.replace(/^v1,/, "");
return timingSafeEqual(Buffer.from(expected), Buffer.from(provided));
}Related Docs
Playback and seeking
Video content endpoints forward Range and If-Range requests to the upstream
storage service and preserve partial-content responses. Inline video results also
support single byte ranges. A satisfiable range returns 206 with Content-Range;
an unsatisfiable range returns 416. This lets native players load and seek
without downloading the entire video first when the upstream supports ranges.
How is this guide?
Last updated on