LLM Gateway
Features

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) through fal-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 through bytedance (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 through atlascloud (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/videos
  • GET /v1/videos/{video_id}
  • GET /v1/videos/{video_id}/content
  • Optional signed callbacks with callback_url and callback_secret

Request Format

LLMGateway currently supports a focused subset of the OpenAI video API.

Supported fields

FieldTypeRequiredDescription
modelstringyesAny video-capable model from the filtered models page
promptstringyesText prompt for the video
secondsnumberyesDuration in seconds. Supported values depend on the model (see below)
sizestringnowidthxheight, limited to the sizes supported by the selected model and provider
audiobooleannoWhether to include audio in the output (default true). Only honored when the model supports both audio and silent output
reasoning_effortstringnoFLUX 3 Max only: prompt reasoning effort, low or high (default high); not a visual-quality or resolution setting
imageobjectnoOptional first frame for image-to-video generation (see first/last frame inputs below)
last_frameobjectnoOptional ending frame when image is provided (see first/last frame inputs below)
reference_imagesarraynoOne to three provider-specific image inputs
input_referenceobjectnoAlias for one or more reference_images
reference_videosarraynoOne to three reference video HTTPS URLs (Seedance 2.x and Gemini Omni, see below)
reference_audiosarraynoOne to three reference audio HTTPS URLs (Seedance 2.x and VEED Fabric, see below)
videostring or objectnoLLMGateway extension: source video HTTPS URL to edit or extend (Gemini Omni only, see below)
video_taskstringnoLLMGateway extension: edit (default) or extend for video
callback_urlstringnoLLMGateway extension for completion webhooks
callback_secretstringnoLLMGateway extension used to sign webhook deliveries

Sizes and durations by model

Model familyProviderSupported sizesSupported durations
FLUX 3 Maxfal-ai1280x720, 720x1280, 1920x1080, 1080x19205–20
Veo 3.1google-vertex1280x720, 720x1280, 1920x1080, 1080x1920, 3840x2160, 2160x38404, 6, 8, 10
Gemini Omni 1.1 Flashgoogle-ai-studio640x360, 360x640, 1280x720, 720x1280, 1920x1080, 1080x1920, 3840x2160, 2160x38403–10
Seedance 2.5bytedance848x480, 854x480, 480x854, 1280x720, 720x1280, 1920x1080, 1080x19204–30
Seedance 2.0bytedance1280x720, 720x1280, 1920x1080, 1080x19204–15
Seedance 2.0 Fastbytedance1280x720, 720x12804–15
Seedance 2.0 Minibytedance1280x720, 720x1280, 848x480, 854x480, 480x8544–15
Seedance 1.5 Probytedance1280x720, 720x1280, 1920x1080, 1080x19205, 10
KLING v3.0atlascloud1280x720, 720x1280, 1920x1080, 1080x1920, 3840x2160, 2160x38405, 10
KLING v3.0 Turboatlascloud1280x720, 720x1280, 1920x1080, 1080x19205, 10
KLING v3.0 Proatlascloud1920x1080, 1080x19205, 10
MiniMax H3 Maxminimax848x480, 854x480, 480x854, 1366x768, 768x13665–15
VEED Fabric 1.0, Fastatlascloud854x480, 480x854, 1280x720, 720x1280audio 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.

FieldRequiredAccepted inputAvailable on
imagefor frame modeHTTPS URL or base64 data URLFLUX 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_frameno (needs image)HTTPS URL or base64 data URLFLUX 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). Sending image/last_frame to Seedance 1.5 Pro or any other ByteDance model returns a 400.
  • 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; use image for the start and last_frame for the optional end.
  • last_frame requires image. Providing last_frame without image returns a 400.
  • 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 typePayload fieldCountAccepted inputAvailable on
Imagereference_images (input_reference alias)1–3HTTPS URL or base64 data URLSeedance 2.x, Veo 3.1 (google-vertex), Gemini Omni (google-ai-studio), VEED Fabric (exactly 1)
Videoreference_videos1–3HTTPS URL onlySeedance 2.x, Gemini Omni (google-ai-studio)
Audioreference_audios1–3HTTPS URL onlySeedance 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_videos and reference_audios must 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 failed and are logged with a content_filter finish reason. The gateway content filter may also reject the request with a 403 before 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.

  • size only 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. seconds is still required (up to 300); set it to the audio's length, since it is billed only when the output length cannot be measured.
  • prompt is 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_taskResult
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
extendThe 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
  • n values other than 1
  • 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:

ModelProviderSupported sizesPrice
veo-3.1-generate-previewgoogle-vertex1280x720, 720x1280, 1920x1080, 1080x1920$0.40 / second
veo-3.1-fast-generate-previewgoogle-vertex1280x720, 720x1280, 1920x1080, 1080x1920$0.15 / second
veo-3.1-generate-previewgoogle-vertex3840x2160, 2160x3840$0.60 / second
veo-3.1-fast-generate-previewgoogle-vertex3840x2160, 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:

ModelProviderResolutionVideo output
gemini-omni-1.1-flashgoogle-ai-studio360p$0.0338 / second
gemini-omni-1.1-flashgoogle-ai-studio720p$0.1014 / second
gemini-omni-1.1-flashgoogle-ai-studio1080p$0.1520 / second
gemini-omni-1.1-flashgoogle-ai-studio4k$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:

ModelResolutionWithout video input (USD / 1M tokens)With video input (USD / 1M tokens)
seedance-2-5480p, 720p$10.70$6.40
seedance-2-51080p$11.70$7.00
seedance-2-0720p$7.00$4.30
seedance-2-01080p$7.70$4.70
seedance-2-0-fast720p$5.60$3.30
seedance-2-0-mini480p, 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):

ModelProviderResolutionWith audioVideo only
kling-v3-0atlascloud720p$0.126 / second$0.084 / second
kling-v3-0atlascloud1080p$0.168 / second$0.112 / second
kling-v3-0atlascloud4k$0.42 / second$0.42 / second
kling-v3-0-proatlascloud1080p$0.168 / second$0.112 / second
kling-v3-0-turboatlascloud720p$0.168 / secondn/a (audio only)
kling-v3-0-turboatlascloud1080p$0.21 / secondn/a (audio only)

VEED Fabric (AtlasCloud), billed per second of generated video; the reservation assumes the 300-second maximum:

ModelProvider480p720p
veed-fabric-1-0atlascloud$0.088 / second$0.165 / second
veed-fabric-1-0-fastatlascloud$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:

  • queued
  • in_progress
  • completed
  • failed
  • canceled
  • expired

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.mp4

Signed 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.completed and video.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-id
  • webhook-timestamp
  • webhook-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));
}

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

On this page

Ready for production?

Ship to production with SSO, audit logs, spend controls, and guardrails your security team will approve.

Explore Enterprise