@molecule/api-ai-video-generation-ltx
Provider bond · ai-video-generation · API (Node) · v1.1.2 · Apache-2.0
LTX video generation provider for molecule.dev — Lightricks' hosted LTX-2.5/LTX-2.3 text/image-to-video-with-audio over the async V2 job API
npm install @molecule/api-ai-video-generation-ltxnpm · Source on GitHub · Implements @molecule/api-ai-video-generation
How it works
@molecule/api-ai-video-generation-ltx is a provider bond on the API (Node) side: it implements the ai-video-generation core interface (@molecule/api-ai-video-generation) with a concrete vendor or library behind it.
Your code calls the core; you wire this provider once at startup. Swapping vendors later is one line in that wiring, not a rewrite.
import { requireProvider, setProvider } from '@molecule/api-ai-video-generation'
import { provider } from '@molecule/api-ai-video-generation-ltx'
// Reads LTXV_API_KEY (from console.ltx.video) on each call.
setProvider(provider)
const job = await requireProvider().generate({
prompt: 'A majestic eagle soaring through clouds at sunset',
model: 'ltx-2-5-pro',
durationSeconds: 8,
resolution: '1920x1080',
})
let status = await requireProvider().getStatus(job.id)
while (status.status === 'pending' || status.status === 'processing') {
await new Promise((resolve) => setTimeout(resolve, 5000))
status = await requireProvider().getStatus(job.id)
}
// status.result?.url — it EXPIRES; download and re-host it now.Works with: @molecule/api-ai-video-generation, @molecule/api-secrets
Secrets: LTXV_API_KEY, LTX_MODEL (optional), LTX_BASE_URL (optional)
Reference
LTX video-generation provider for @molecule/api-ai-video-generation.
Generates short video clips with a synchronized audio track through
Lightricks' hosted LTX API (LTX-2.5 / LTX-2.3, ltx-2-5-fast by default)
over its asynchronous V2 job flow: submit, poll, download. Raw first-frame
bytes are uploaded through the API's own /v1/upload ticket flow.
Auto-generated, AI-first package reference for the molecule.dev ecosystem. It is written to be read by coding agents as much as by people, and is generated from this package's source — edit
src/index.tsJSDoc, not this file.
Quick Start
import { requireProvider, setProvider } from '@molecule/api-ai-video-generation'
import { provider } from '@molecule/api-ai-video-generation-ltx'
// Reads LTXV_API_KEY (from console.ltx.video) on each call.
setProvider(provider)
const job = await requireProvider().generate({
prompt: 'A majestic eagle soaring through clouds at sunset',
model: 'ltx-2-5-pro',
durationSeconds: 8,
resolution: '1920x1080',
})
let status = await requireProvider().getStatus(job.id)
while (status.status === 'pending' || status.status === 'processing') {
await new Promise((resolve) => setTimeout(resolve, 5000))
status = await requireProvider().getStatus(job.id)
}
// status.result?.url — it EXPIRES; download and re-host it now.
Type
provider
Installation
npm install @molecule/api-ai-video-generation-ltx @molecule/api-ai-video-generation @molecule/api-secrets
API
Interfaces
LtxVideoGenerationConfig
Configuration for the LTX video generation provider. Every field falls back to its env var, read on each call (never at import time).
interface LtxVideoGenerationConfig {
/** API key from the LTX developer console. Defaults to the `LTXV_API_KEY` env var (required). */
apiKey?: string
/** Base URL override. Defaults to `LTX_BASE_URL`, then `https://api.ltx.io`. */
baseUrl?: string
/** Default model id. Defaults to `LTX_MODEL`, then `ltx-2-5-fast`. */
defaultModel?: string
/** Per-request timeout in milliseconds. Defaults to 120000. */
timeoutMs?: number
}
Classes
LtxVideoError
Error thrown when the LTX API refuses or fails a request. Carries the
API's HTTP status (0 when it could not be reached or timed out) and the
error type from its error body (content_filtered_error,
insufficient_funds_error, …). Deliberately NOT tagged with
statusCode/errorKey, so API middleware answers its generic 500 instead
of echoing the vendor's status to the caller.
class LtxVideoError extends Error {
/** HTTP status from the LTX API; 0 for a network failure or timeout. */
readonly status: number
/** Error type from the LTX error body, when present. */
readonly code: string | undefined
/**
* Create the error.
*
* @param message - Human-readable message.
* @param status - HTTP status (0 for network failure/timeout).
* @param code - LTX error type, when it sent one.
* @param cause - The underlying error, if any.
*/
constructor(message: string, status: number, code?: string, cause?: unknown) {
super(message, cause === undefined ? undefined : { cause })
this.name = 'LtxVideoError'
this.status = status
this.code = code
}
}
Functions
createProvider(config)
Creates an LTX video generation provider.
function createProvider(config?: LtxVideoGenerationConfig): AIVideoGenerationProvider
config— Optional overrides (API key, base URL, default model, timeout).
Returns: An AIVideoGenerationProvider backed by the LTX hosted API.
Constants
DEFAULT_BASE_URL
Default API base URL.
const DEFAULT_BASE_URL: 'https://api.ltx.io'
DEFAULT_MODEL
Default model: the fast LTX-2.5 tier.
const DEFAULT_MODEL: 'ltx-2-5-fast'
DEFAULT_RESOLUTION
Default output resolution (720p landscape) when the caller sets none.
const DEFAULT_RESOLUTION: '1280x720'
LTX_MODELS
The model ids the V2 API accepts.
const LTX_MODELS: readonly ['ltx-2-3-fast', 'ltx-2-3-pro', 'ltx-2-5-fast', 'ltx-2-5-pro']
LTX_CAMERA_MOTIONS
The camera motions the V2 API accepts.
const LTX_CAMERA_MOTIONS: readonly [
'dolly_in',
'dolly_out',
'dolly_left',
'dolly_right',
'jib_up',
'jib_down',
'static',
'focus_shift',
]
DEFAULT_TIMEOUT_MS
Default per-request timeout.
const DEFAULT_TIMEOUT_MS: 120000
provider
The default provider, configured from env vars on each call (wire with
setProvider). Safe to import before secrets are loaded.
const provider: AIVideoGenerationProvider
aiVideoGenerationLtxSecretDefinitions
Secret definitions used by the LTX video generation bond.
const aiVideoGenerationLtxSecretDefinitions: SecretDefinition[]
Core Interface
Implements @molecule/api-ai-video-generation interface.
Bond Wiring
Setup function to register this provider with the core interface:
import { setProvider } from '@molecule/api-ai-video-generation'
import { provider } from '@molecule/api-ai-video-generation-ltx'
export function setupAiVideoGenerationLtx(): void {
setProvider(provider)
}
Injection Notes
Requirements
Peer dependencies:
@molecule/api-ai-video-generation>=1.0.0@molecule/api-secrets^1.0.1
Environment Variables
LTXV_API_KEY(required) — LTX API key- Setup: Create one in the LTX developer console (console.ltx.video); sent as a Bearer token on every request. This is the env-var name the LTX docs themselves use.
- Get it here: https://console.ltx.video
- Example:
ltx-...
LTX_MODEL(optional) — LTX model id- Setup: One of ltx-2-5-fast, ltx-2-5-pro, ltx-2-3-fast, ltx-2-3-pro. Defaults to ltx-2-5-fast.
- Get it here: https://docs.ltx.io/models
- Example:
ltx-2-5-fast
LTX_BASE_URL(optional) — LTX API base URL- Setup: Override only for a broker or compatible endpoint. Defaults to https://api.ltx.io.
- Get it here: https://docs.ltx.io
- Example:
https://api.ltx.io
Runtime Dependencies
-
@molecule/api-ai-video-generation -
@molecule/api-secrets -
Only the async V2 job API is used. The synchronous V1 endpoints (
POST /v1/text-to-videoreturning the MP4 body directly) are deprecated and stop working after October 26, 2026 — this bond never touches them. Submit isPOST /v2/text-to-videoor/v2/image-to-video(202 +{id, created_at}); pollGET /v2/{endpoint}/{id}— the docs recommend waiting at least 5 seconds between polls (vary 5–6 s). -
durationis required but nullable — omittingdurationSecondssendsnull, which ONLY ltx-2-5 tiers accept (automatic duration: the model picks the length from the prompt). With nodurationSecondson anltx-2-3-*model this bond throws before any request. On a prepaid account,duration: nullHOLDS credits for the maximum (20 s on fast, 10 s on pro) even if the clip comes out shorter. -
resolutionis a"WxH"string (landscape"1920x1080", portrait"1080x1920"), never an enum, and model ids (ltx-2-5-fast,ltx-2-5-pro,ltx-2-3-fast,ltx-2-3-pro) ride in the body, not the URL. With no resolution the bond sends"1280x720"(720p landscape). Supported resolutions are per model tier — 720p/1080p/1440p/4K on 2.5. -
Output URLs expire on their own, independently of job status (which itself is only kept ≤24 h after completion): download the finished MP4 and re-host it (e.g. via the uploads bond) immediately — never store the
result.urlas if it were permanent. -
Job ids this bond returns are prefixed —
ltx/<endpoint>/<model>/<api id>— because the poll path embeds the submit endpoint. Pass the id exactly asgenerate()returned it; a bare API id is rejected with a clear error. An API id this bond could never poll back (dot segments, empty segments,?,#) is refused at submit time instead of minted into a handlegetStatus()would reject. -
Auth is
Authorization: BearerwithLTXV_API_KEY(the env-var name the LTX docs themselves use; create the key at console.ltx.video). A missing key throws the taggedconfig.notConfigurederror.LTX_BASE_URLoverrideshttps://api.ltx.iofor brokers/tests. -
First frames: URIs pass through, bytes upload. An
imagethat is an http(s) orltx:URI is sent asimage_uriunchanged; a Buffer, base64 string or data URL is uploaded viaPOST /v1/upload(pre-signed PUT; uploads expire after 1 h and stored files after 24 h) and the returnedstorage_uriis used. -
Diffusion controls do not exist here.
negativePrompt,seed,stepsandguidanceScaleare silently NOT forwarded — the V2 API has no such fields (they are Diffusers-pipeline knobs, not hosted-API ones).fpsandgenerateAudio(→generate_audio) forward only when the caller sets them — this bond sends no default of its own — as doescameraMotion(→camera_motion, validated against the eight documented motions). -
Errors are
LtxVideoErrorcarrying the HTTPstatus(400 invalid, 401 auth, 402 insufficient credits, 422 content filtered, 429 concurrency, 500/503/504 server; 0 = unreachable/timeout) and the API's errortypeascode(content_filtered_error, …). A failed JOB surfaces throughgetStatus()asstatus: 'failed'with the same error shape, not as a throw. Nothing is retried; the default timeout is 120 s. -
License asymmetry vs the sibling bond: LTX-2.5 model weights are NOT open source — the LTX-2.x Community License excludes ≥$10M-revenue entities and bans building competing products; you are responsible for your own compliance when reselling access (outputs themselves are unencumbered — "Licensor claims no rights in the Output"). Kandinsky 6.0 (the
-kandinskybond) is MIT with no such limits.
E2E Tests
Integration checklist — drive the real UI (live preview, no mocks), adapt each item to this app's actual screens/flows, and check every box off one by one. A box you can't check is an integration bug to fix — not a skip:
- Entering a prompt in the UI and submitting produces a REAL playable
video in the live preview once the job completes — not a broken video
element, a spinner that never ends, or an error toast. Confirm the video
element actually loaded (its
readyState/durationare set) and the clip visibly reflects the prompt (a "waves on a beach" prompt shows waves, not a placeholder). - Two different prompts produce two visibly different clips — a fixed stub, or a cached first result that never changes, is a broken integration.
- The video is STORED AND SERVED FROM THE APP'S OWN ORIGIN: the played
source/src(and any saved record) points at the app's uploads/storage, not the provider's temporary URL. Providerurlresults expire — reload the page (or revisit the record later) and the video must still play. Download the provider result server-side and persist it (uploads bond) once the job completes; never hotlink the provider URL. (dataresults must likewise be saved, not held only in the response.) - Job progress is visible while polling: the UI shows the job is pending/processing (not frozen), and a failed job surfaces the provider's error message clearly so the user can recover and try another prompt.
- Any exposed generation options take effect: changing durationSeconds/resolution yields a different-length/-sized clip. If the UI exposes no such options, this box is n/a — say so.
- Generation is server-side and authorized: the provider API key never reaches the browser (check the network tab / built client bundle — no key, no direct provider call from the page), the generate endpoint requires auth, and a caller cannot run unbounded costly generations through an open or unrate-limited route. Every clip is billed or GPU-expensive.