# LTX 2.3 Outpaint

> Expand a video past its original frame — the source stays put inside a wider canvas and the surrounding region is generated to match.

## Overview

- **Model ID**: `ltx-v2.3-outpaint`
- **Workflow**: `ltx-2.3-quality/outpaint`
- **Provider**: LTX
- **Category**: Video → Video (video)
- **Output**: A video URL.
- **Tags**: video input, outpaint, audio, up to 1080p
- **Unified endpoint**: `POST https://api.picsart.com/workflows/v1/models/execute` (model id in the body)
- **Compatibility endpoint**: `POST https://api.picsart.com/workflows/ltx-2.3-quality/outpaint/execute` (vendor's own parameters)
- **Execution**: long-running — use the async submit/poll pair or the SDK, which polls for you
- **Model page**: https://picsart.com/api-platform/models/ltx-v2.3-outpaint

## Pricing

Rates are in USD. Every row below is an exact rate for the settings it names — the columns are the settings that change the price for this model. Every response reports what was actually charged in `response.usage.credits`.

| Rate |
| --- |
| $0.0027 / MP |

Published rates. Volume pricing, invoicing and annual agreements: https://picsart.com/api-platform/contact-sales

## Authentication

The SDK and the REST API authenticate with a Picsart API key sent as a bearer token. Create a key in the console at https://picsart.com/api-platform/dashboard/api-keys, keep it in a server-side environment variable, and never ship it in browser code or commit it.

```bash
export PICSART_API_KEY="YOUR_KEY"
```

```http
Authorization: Bearer $PICSART_API_KEY
```

The CLI and the MCP server do not use an API key: `gen-ai login` signs in through the browser once per machine and stores a token locally.

## Interfaces

- **SDK** — `@picsart/ai-sdk` (TypeScript, Node 20+, ESM). Type-safe `ai.generate()` / `ai.generateText()` with per-model parameter types; polls long jobs for you.
- **REST** — the API gateway at `https://api.picsart.com`. Sync `/execute`, or async `/submit` + `/{taskId}/result`.
- **CLI** — `@picsart/gen-ai` (`gen-ai`). Generate from a terminal, quote cost before spending, emit JSON for pipelines.
- **MCP** — the same models inside Claude Code, Cursor, Windsurf and other MCP hosts. Setup: https://picsart.com/gen-ai-mcp/

```bash
npm install @picsart/ai-sdk      # SDK
npm install -g @picsart/gen-ai   # CLI (also drives the MCP server)
```

## Unified API (recommended)

One parameter set, used by the SDK and by REST alike: the names below are what `ai.generate('ltx-v2.3-outpaint', …)` takes, and what goes inside the inner `params` of a REST call. Over REST the model id travels in the body, not the path — one workflow, `v1/models`, fronts the whole catalogue.

### Execution modes

- **Sync** — `POST /workflows/v1/models/execute` returns the result in one call. Only for jobs that finish within ~20 seconds; otherwise it times out.
- **Async** — `POST /workflows/v1/models/submit` returns a task id; poll `GET /workflows/v1/models/{taskId}/result` until `response.status` is `COMPLETED` or `FAILED`. Task statuses: `ACCEPTED` · `IN_PROGRESS` · `COMPLETED` · `FAILED`.
- **SDK** — `ai.generate()` always awaits the finished result; polling is hidden.

Video jobs routinely outrun the sync limit: use async over REST, or the SDK, which polls for you.

### Input parameters

- **`prompt`** (`string`, _required_): Prompt
  - Max length: 5000 characters
- **`videoUrl`** (`string`, _required_): Source Video
  - Accepts: video URL
- **`negativePrompt`** (`string`, _optional_): Negative Prompt
- **`aspectRatio`** (`string`, _optional_)
  - Default: `"21:9"`
  - Options: `21:9`, `16:9`, `4:3`, `1:1`, `3:4`, `9:16`, `9:21`
- **`resolution`** (`string`, _optional_)
  - Default: `"720p"`
  - Options: `480p`, `720p`, `1080p`
- **`duration`** (`number`, _optional_)
  - Default: `6`
  - Options: `1`, `2`, `3`, `4`, `5`, `6`, `7`, `8`, `9`, `10`, `11`, `12`, `13`, `14`, `15`, `16`, `17`, `18`, `19`, `20`
- **`fps`** (`number`, _optional_): FPS
  - Default: `24`
  - Range: 1–60 (step 1)
- **`sourceScale`** (`number`, _optional_): Source Scale
  - Default: `1`
  - Range: 0.25–1 (step 0.05)
- **`videoStrength`** (`number`, _optional_): Source Strength
  - Default: `1`
  - Range: 0–1 (step 0.05)
- **`cfgScale`** (`number`, _optional_): CFG Scale
  - Default: `1`
  - Range: 1–20
- **`numInferenceSteps`** (`number`, _optional_): Inference Steps
  - Default: `15`
  - Range: 8–30
- **`videoQuality`** (`string`, _optional_): Video Quality
  - Default: `"high"`
  - Options: `low`, `medium`, `high`, `maximum`
- **`videoWriteMode`** (`string`, _optional_): Write Mode
  - Default: `"balanced"`
  - Options: `fast`, `balanced`, `small`
- **`enhancePrompt`** (`boolean`, _optional_)
  - Default: `true`
- **`generateAudio`** (`boolean`, _optional_)
  - Default: `true`
- **`enableSafetyChecker`** (`boolean`, _optional_): Safety Checker
  - Default: `true`
- **`seed`** (`number`, _optional_): Seed
  - Range: 0–2147483647 (step 1)

### Input JSON Schema

The inner `params` object. Over REST it is wrapped as `{ "params": { "model": "<id>", "params": <this> } }`; the SDK takes it directly.

```json
{
  "type": "object",
  "required": [
    "prompt",
    "videoUrl"
  ],
  "properties": {
    "prompt": {
      "type": "string",
      "maxLength": 5000,
      "description": "Prompt"
    },
    "videoUrl": {
      "type": "string",
      "format": "uri",
      "description": "Source Video"
    },
    "negativePrompt": {
      "type": "string",
      "description": "Negative Prompt"
    },
    "aspectRatio": {
      "type": "string",
      "enum": [
        "21:9",
        "16:9",
        "4:3",
        "1:1",
        "3:4",
        "9:16",
        "9:21"
      ],
      "default": "21:9"
    },
    "resolution": {
      "type": "string",
      "enum": [
        "480p",
        "720p",
        "1080p"
      ],
      "default": "720p"
    },
    "duration": {
      "type": "number",
      "enum": [
        1,
        2,
        3,
        4,
        5,
        6,
        7,
        8,
        9,
        10,
        11,
        12,
        13,
        14,
        15,
        16,
        17,
        18,
        19,
        20
      ],
      "default": 6
    },
    "fps": {
      "type": "number",
      "minimum": 1,
      "maximum": 60,
      "multipleOf": 1,
      "default": 24,
      "description": "FPS"
    },
    "sourceScale": {
      "type": "number",
      "minimum": 0.25,
      "maximum": 1,
      "multipleOf": 0.05,
      "default": 1,
      "description": "Source Scale"
    },
    "videoStrength": {
      "type": "number",
      "minimum": 0,
      "maximum": 1,
      "multipleOf": 0.05,
      "default": 1,
      "description": "Source Strength"
    },
    "cfgScale": {
      "type": "number",
      "minimum": 1,
      "maximum": 20,
      "default": 1,
      "description": "CFG Scale"
    },
    "numInferenceSteps": {
      "type": "number",
      "minimum": 8,
      "maximum": 30,
      "default": 15,
      "description": "Inference Steps"
    },
    "videoQuality": {
      "type": "string",
      "enum": [
        "low",
        "medium",
        "high",
        "maximum"
      ],
      "default": "high",
      "description": "Video Quality"
    },
    "videoWriteMode": {
      "type": "string",
      "enum": [
        "fast",
        "balanced",
        "small"
      ],
      "default": "balanced",
      "description": "Write Mode"
    },
    "enhancePrompt": {
      "type": "boolean",
      "default": true
    },
    "generateAudio": {
      "type": "boolean",
      "default": true
    },
    "enableSafetyChecker": {
      "type": "boolean",
      "default": true,
      "description": "Safety Checker"
    },
    "seed": {
      "type": "number",
      "minimum": 0,
      "maximum": 2147483647,
      "multipleOf": 1,
      "description": "Seed"
    }
  },
  "additionalProperties": false
}
```

### Required parameters example

The required parameters plus the defaults that shape the output, as a REST body:

```json
{
  "params": {
    "model": "ltx-v2.3-outpaint",
    "params": {
      "prompt": "A serene mountain lake at golden hour, ultra detailed",
      "videoUrl": "https://cdn.example.com/input.mp4",
      "aspectRatio": "21:9",
      "resolution": "720p",
      "duration": 6
    }
  }
}
```

### Response

The body is the gateway's status envelope: the output is at `response.result`, next to the task id, its status and the credits charged. Asset models return `url` plus an `items` array of results.

```json
{
  "status": "success",
  "response": {
    "id": "task_abc123",
    "status": "COMPLETED",
    "result": {
      "url": "https://cdn.picsart.com/…/result",
      "items": [
        {
          "url": "https://cdn.picsart.com/…/result"
        }
      ],
      "model": "ltx-v2.3-outpaint"
    }
  }
}
```

What `ai.generate()` / `ai.generateText()` resolve to (the envelope already unwrapped):

```json
{
  "items": [
    {
      "url": "https://cdn.picsart.com/…/result"
    }
  ],
  "model": "ltx-v2.3-outpaint"
}
```

### Usage examples

#### TypeScript (SDK)

```typescript
import { createClient } from '@picsart/ai-sdk';

const ai = createClient({
  apiKey: process.env.PICSART_API_KEY,
  apiUrl: 'https://api.picsart.com',
});

const result = await ai.generate('ltx-v2.3-outpaint', {
  prompt: "A serene mountain lake at golden hour, ultra detailed",
  videoUrl: "https://cdn.example.com/input.mp4",
  aspectRatio: "21:9",
  resolution: "720p",
  duration: 6
});

console.log(result.url); // video URL
```

#### cURL (sync)

```bash
curl -X POST 'https://api.picsart.com/workflows/v1/models/execute' \
  -H 'Authorization: Bearer $PICSART_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{
  "params": {
    "model": "ltx-v2.3-outpaint",
    "params": {
      "prompt": "A serene mountain lake at golden hour, ultra detailed",
      "videoUrl": "https://cdn.example.com/input.mp4",
      "aspectRatio": "21:9",
      "resolution": "720p",
      "duration": 6
    }
  }
}'
```

#### cURL (async: submit, then poll)

```bash
# 1. Submit the job
curl -X POST 'https://api.picsart.com/workflows/v1/models/submit' \
  -H 'Authorization: Bearer $PICSART_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{
  "params": {
    "model": "ltx-v2.3-outpaint",
    "params": {
      "prompt": "A serene mountain lake at golden hour, ultra detailed",
      "videoUrl": "https://cdn.example.com/input.mp4",
      "aspectRatio": "21:9",
      "resolution": "720p",
      "duration": 6
    }
  }
}'
# → { "status": "success", "response": { "id": "task_abc123" } }

# 2. Poll until response.status is COMPLETED
curl 'https://api.picsart.com/workflows/v1/models/task_abc123/result' \
  -H 'Authorization: Bearer $PICSART_API_KEY'
```

#### CLI

```bash
gen-ai login  # once per machine
gen-ai models info ltx-v2.3-outpaint  # this model's parameters
gen-ai pricing ltx-v2.3-outpaint  # quote before spending credits
gen-ai generate -m ltx-v2.3-outpaint \
  -p "A serene mountain lake at golden hour" \
  -d 6 \
  --ar 21:9
```

## Compatibility API (vendor parameters)

Alongside the unified API, the `ltx-2.3-quality/outpaint` workflow takes LTX's own parameters exactly as the vendor defines them — nothing renamed or reshaped. It is the shortest path onto Picsart for request bodies already written against the vendor; the trade is that a request is written for one vendor, and the result comes back in the vendor's own shape. Same authentication.

- **Endpoint**: `POST https://api.picsart.com/workflows/ltx-2.3-quality/outpaint/execute` (sync) · `POST …/submit` + `GET …/{taskId}/result` (async)
- **SDK**: `ai.apis.run('ltx-2.3-quality/outpaint', params, { mode })` — params forwarded verbatim

### Vendor parameters

| Parameter | Type | Required | Default | Details |
| --- | --- | --- | --- | --- |
| `video_url` | `string` | yes | — | The source video to spatially outpaint. |
| `enable_safety_checker` | `boolean` | no | `true` | Whether to enable the safety checker. |
| `video_quality` | `string` | no | `high` | The quality preset of the generated video. · Options: `low`, `medium`, `high`, `maximum` |
| `video_strength` | `number` | no | `1` | Strength of the IC-LoRA video guide for the original content. Higher values preserve the source video more strongly inside the outpainted canvas. · 0–1 |
| `num_inference_steps` | `integer` | no | `15` | Number of inference steps. Defaults to 15 and can be increased up to 30. · 8–30 |
| `video_write_mode` | `string` | no | `balanced` | The write mode of the generated video. · Options: `fast`, `balanced`, `small` |
| `prompt` | `string` | yes | — | The prompt to guide the outpainted video generation. · e.g. `A cinematic wide shot of the same scene, extending the environment naturally beyond the original frame.` |
| `num_frames` | `integer` | no | `121` | The number of frames to generate. · 9–481 |
| `sync_mode` | `boolean` | no | `false` | If True, the media is returned as a data URI inline in the response. Useful for short-lived requests and tests. |
| `guidance_scale` | `number` | no | `1` | Classifier-free guidance scale. The default is tuned for fast, high-quality generation. · 1–20 |
| `negative_prompt` | `string` | no | `color distortion, overexposure, static, blurry details, subtitles, style, artwork, painting, frame, still, dim overall tone, worst quality, low quality, JPEG compression artifacts, ugly, mutilated, extra fingers, poorly drawn hands, poorly drawn face, deformed, disfigured, malformed limbs, fused fingers, motionless frame, cluttered background, three legs, crowded background, walking backwards` | The negative prompt to steer generation away from. |
| `aspect_ratio` | `string` | no | `16:9` | Target aspect ratio for the outpainted video. Choose a different ratio than the input video to extend the frame cleanly, e.g. use 16:9 for a 4:3 source. · Options: `21:9`, `16:9`, `4:3`, `1:1`, `3:4`, `9:16`, `9:21` |
| `generate_audio` | `boolean` | no | `true` | Whether to include audio in the returned video. When disabled, the final MP4 is returned without an audio track. |
| `seed` | `integer` | no | — | Random seed for reproducibility. If None, a random seed is chosen. |
| `output_resolution` | `string` | no | `720p` | Output resolution tier. 480p is faster, 720p is the default balance, and 1080p gives a larger canvas when it fits LTX limits. · Options: `480p`, `720p`, `1080p` |
| `enable_prompt_expansion` | `boolean` | no | `true` | Whether to enable prompt expansion. |
| `frames_per_second` | `number` | no | `24` | Frames per second of the generated video. · 1–60 |
| `resolution` | `ImageSize \| string` | no | `landscape_16_9` | Legacy exact target canvas size. For new requests, prefer aspect_ratio with output_resolution; this field remains supported for backwards compatibility. |
| `source_scale` | `number` | no | `1` | Scale of the source video inside the target canvas before outpainting. 1.0 uses the largest source size that fits the target canvas, which is recommended for true aspect-ratio outpainting such as 4:3 to 16:9. Lower values create a zoom-out border around the source and are less stable. · 0.25–1 |
| `options` | `object` | no | — | Platform-specific options for safety checks and Picsart Drive integration. |
| └ `safety_checks` | `object` | no | — | Safety check configuration. |
| └   `enabled` | `boolean` | no | `true` | Enable or disable text safety checks. Defaults to true. |
| └ `drive` | `object` | no | — | Picsart Drive storage options. When provided, the result will be saved to the user's Drive. |
| └   `name` | `string` | yes | — | Filename to save the result as in Picsart Drive. |
| └   `attributes` | `object` | no | — | Additional file metadata attributes. |
| └   `folder` | `object` | no | — | Destination folder in Picsart Drive. |

### Example request body

```json
{
  "params": {
    "video_url": "https://cdn.example.com/input.mp4",
    "prompt": "A cinematic wide shot of the same scene, extending the environment naturally beyond the original frame."
  }
}
```

### Usage examples

#### TypeScript (`ai.apis.run`)

```typescript
import { createClient, ApiRunMode } from '@picsart/ai-sdk';

const ai = createClient({
  apiKey: process.env.PICSART_API_KEY,
  apiUrl: 'https://api.picsart.com',
});

// Calls the 'ltx-2.3-quality/outpaint' workflow directly — params are sent as-is.
const { result, usage } = await ai.apis.run('ltx-2.3-quality/outpaint', {
  video_url: "https://cdn.example.com/input.mp4",
  prompt: "A cinematic wide shot of the same scene, extending the environment naturally beyond the original frame."
}, {
  mode: ApiRunMode.SYNC,
});

console.log(result); // workflow-specific output
console.log(usage?.credits); // amount charged, in $
```

#### cURL (sync)

```bash
curl -X POST 'https://api.picsart.com/workflows/ltx-2.3-quality/outpaint/execute' \
  -H 'Authorization: Bearer $PICSART_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{
  "params": {
    "video_url": "https://cdn.example.com/input.mp4",
    "prompt": "A cinematic wide shot of the same scene, extending the environment naturally beyond the original frame."
  }
}'
```

#### cURL (async: submit, then poll)

```bash
# 1. Submit the job
curl -X POST 'https://api.picsart.com/workflows/ltx-2.3-quality/outpaint/submit' \
  -H 'Authorization: Bearer $PICSART_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{
  "params": {
    "video_url": "https://cdn.example.com/input.mp4",
    "prompt": "A cinematic wide shot of the same scene, extending the environment naturally beyond the original frame."
  }
}'
# → { "status": "success", "response": { "id": "wf_abc123" } }

# 2. Poll until response.status is COMPLETED
curl 'https://api.picsart.com/workflows/ltx-2.3-quality/outpaint/wf_abc123/result' \
  -H 'Authorization: Bearer $PICSART_API_KEY'
```

### Response

Over HTTP the vendor-shaped result arrives inside the gateway envelope at `response.result`:

```json
{
  "status": "success",
  "response": {
    "id": "wf_abc123",
    "status": "COMPLETED",
    "result": {
      "seed": 0,
      "prompt": "…",
      "video": {
        "content_type": "image/png",
        "file_size": 4404019,
        "url": "https://cdn.picsart.com/…/result.jpg",
        "file_name": "z9RV14K95DvU.png"
      }
    }
  }
}
```

`ai.apis.run()` unwraps that envelope and resolves to `{ result, usage }`:

```json
{
  "result": {
    "seed": 0,
    "prompt": "…",
    "video": {
      "content_type": "image/png",
      "file_size": 4404019,
      "url": "https://cdn.picsart.com/…/result.jpg",
      "file_name": "z9RV14K95DvU.png"
    }
  }
}
```

## Additional resources

- Model page: https://picsart.com/api-platform/models/ltx-v2.3-outpaint
- Try it: https://picsart.com/api-platform/models/ltx-v2.3-outpaint/playground
- SDK: https://picsart.com/api-platform/models/ltx-v2.3-outpaint/sdk
- REST API (unified): https://picsart.com/api-platform/models/ltx-v2.3-outpaint/api
- Compatibility API (vendor parameters): https://picsart.com/api-platform/models/ltx-v2.3-outpaint/advanced
- Pricing: https://picsart.com/api-platform/models/ltx-v2.3-outpaint/pricing
- This document: https://picsart.com/api-platform/models/ltx-v2.3-outpaint/llms.txt
- All models: https://picsart.com/api-platform/models
- Docs — quickstart https://picsart.com/api-platform/docs/quickstart, authentication https://picsart.com/api-platform/docs/authentication, SDK https://picsart.com/api-platform/docs/sdk, REST https://picsart.com/api-platform/docs/api-reference, CLI https://picsart.com/api-platform/docs/cli, MCP https://picsart.com/api-platform/docs/mcp
- CLI reference: https://picsart.github.io/picsart-mcp-cli-docs/guide/introduction
