# Run H3 with a server and playground
Start FastH3 on CUDA, one DGX Spark, or Apple Silicon MLX, then send requests from a
browser, cURL, or your app. Several clients can share one server process.
CUDA requests reuse a loaded `VideoGenerator`. MLX keeps one pipeline object and
a prompt-embedding cache, but loads and releases heavyweight components between
phases to fit unified memory. MLX serving still pays that component-loading cost
on subsequent requests.
The server implements the OpenAI-compatible video-job API. The Python and
JavaScript clients use that API, but requests go to FastVideo. You do not need an
OpenAI account or cloud key.
This guide covers FastH3 V1 (four forwards) and FastH3 V2 (eight forwards). For
direct Python generation, see the [H3 cookbook](minimax-h3.md).
## Install and start the server
All runtimes need a FastVideo clone and an activated Python environment.
### CUDA
Complete the [CUDA installation requirements](../getting_started/installation/gpu.md)
before running these commands:
```bash
UV_TORCH_BACKEND=cu130 uv pip install -e ".[fasth3]"
fastvideo serve --config examples/serving/openai_fasth3.yaml --server.host 127.0.0.1
```
The configuration loads `FastVideo/FastVideo-Minimax-FastH3-Preview-v0.2` and
advertises it as `fasth3`. It configures four CUDA GPUs and does not record a GPU
model or VRAM requirement, so treat it as a starting point, not a measured
profile. Compilation is disabled.
For FastH3 V2, use the same install and the 8-step config (nine sigma
points, eight DiT forwards, VSA sparsity 0.8):
```bash
UV_TORCH_BACKEND=cu130 uv pip install -e ".[fasth3]"
fastvideo serve --config examples/serving/openai_fasth3_8step.yaml --server.host 127.0.0.1
```
Keep the server running. In another terminal, check readiness:
```bash
curl --fail-with-body http://127.0.0.1:8000/health
```
After model loading completes, the response is `{"status":"ok"}`.
### NVIDIA DGX Spark
Complete the [DGX Spark installation](../getting_started/installation/spark.md)
before running these commands. GB10 has no FA4 / ptx_blackwell VSA kernel:
```bash
UV_TORCH_BACKEND=cu130 uv pip install -e .
FASTVIDEO_VSA_PTX_BLACKWELL=0 FASTVIDEO_FA4=0 FASTVIDEO_ATTENTION_BACKEND=VIDEO_SPARSE_ATTN_H3 \
fastvideo serve --config examples/serving/openai_fasth3_spark.yaml --server.host 127.0.0.1
```
The configuration loads `FastVideo/FastVideo-FastH3-4-step-Preview-v1-VSA-DataFree`
on one GB10 and advertises it as `fasth3`. Lazy module load still reloads
Qwen3-VL and the DiT between phases of each request. Legal `num_frames` values
are `17n+5`, capped at 362 (15.08 s); a 345-frame request on one Spark can OOM.
There is no cookbook server for two Sparks; use the generate YAML after
[pairing two Sparks](../getting_started/installation/spark_pair.md).
Keep the server running. In another terminal, check readiness:
```bash
curl --fail-with-body http://127.0.0.1:8000/health
```
After model loading completes, the response is `{"status":"ok"}`.
### Apple Silicon MLX
Complete the [MLX install](../getting_started/installation/mlx.md),
including `ffmpeg`. From your FastVideo clone, install the MLX extra:
```bash
uv pip install -e ".[mlx]"
```
Download and convert the weights once. Skip this step if you already have the
snapshot and converted DiT:
```bash
hf download FastVideo/FastVideo-Minimax-FastH3-Preview-v0.2 --local-dir ./FastH3-Preview-v0.2
python scripts/checkpoint_conversion/convert_minimax_h3_mlx.py --model-root ./FastH3-Preview-v0.2/transformer --out ./FastH3-MLX --formats "int6"
```
Edit `generator.model_root` and `generator.mlx_checkpoint` in
`examples/serving/mlx_fasth3.yaml` if your weights are elsewhere. Paths are
relative to the directory where you launch the server. Start it with:
```bash
python -m fastvideo.entrypoints.openai.mlx_server --config examples/serving/mlx_fasth3.yaml
```
This uses the native MLX pipeline, not PyTorch MPS. The default output is
832 × 480, 124 frames at 24 fps, with four DiT forwards and the full H3 VAE.
The HTTP field `num_inference_steps=5` describes five sigma points; the adapter
passes `num_steps=4` to MLX. Temporal/spatial fast modes, VSA, reference inputs,
LoRA selection, and alternate decoders are not exposed by this server adapter.
Unsupported request options return HTTP 400 before a job starts.
The server binds to `127.0.0.1:8000` and advertises `fasth3`, so the playground
and clients below work unchanged. Do not run CUDA, Spark, and MLX servers on the
same port. MLX readiness means the pipeline is initialized; components load during
generation. The first request can take longer than a repeated cached prompt.
The MLX server has no recorded device or unified-memory requirement. The
direct Python recipe's M4 Max measurements are not a server benchmark or a
minimum-memory claim.
For FastH3 V2, convert that checkpoint's transformer with `--include-vsa`
and start the 8-step config. Do not overwrite a V1 export. The
[MiniMax H3 cookbook](minimax-h3.md) has the same download and convert
commands as the Python recipe.
```bash
hf download FastVideo/FastVideo-FastH3-8-Step-V2 --local-dir ./FastH3-8-Step-V2
python scripts/checkpoint_conversion/convert_minimax_h3_mlx.py --model-root ./FastH3-8-Step-V2/transformer --out ./FastH3-8-Step-V2-MLX --formats "int8" --include-vsa
python -m fastvideo.entrypoints.openai.mlx_server --config examples/serving/mlx_fasth3_8step.yaml
```
That adapter passes `num_steps=8` when the HTTP field is `num_inference_steps=9`,
and it enables the trained VSA recipe (sparsity 0.8, 64-token tiles). Reuse the
preview VAE, audio VAE, text encoder, and tokenizer if those directories already
exist; edit the YAML paths if your files live elsewhere.
## Open the playground
Open [the local H3 playground](http://127.0.0.1:8000/playground/) after startup.
Write a prompt, optionally set a seed, then select **Generate video**. The page
checks the job status and shows the completed video with a download link. Edit
the prompt and generate again without restarting the server.
The playground sends requests to `/v1/videos` on the same server that serves
the page. **Use this prompt with cURL** shows the equivalent submission. Recent
jobs include requests from other clients, so a script and the playground can
use the same model process. Opening the page or copying a command does not
start generation.
The page URL includes the active job ID. Reloading that URL resumes status
checks without resubmitting the prompt. A failed connection or a 30-minute
polling timeout does not cancel execution. Select **Check status** to reconnect.
If submission itself is interrupted, check Recent jobs before submitting again.
This first playground supports H3 text-to-video/audio. Reference-media inputs
remain available through the API, not through the playground. It does not start
or manage a GPU server for you.
## Generate with cURL or an SDK
These examples use the server's resolution, frame count, and sampling defaults.
Do not copy Sora-specific durations or resolutions onto H3. V1 configs use
124 frames, 24 fps, and the five-point distilled sigma schedule with four DiT
forwards. V2 configs use nine sigma points and eight DiT forwards. CUDA
and one Spark use 1344 × 768; MLX uses 832 × 480. The OpenAI Python client is
the same for every FastH3 server that advertises `fasth3`.
Each client submits a job, checks for completion or failure, and downloads an
MP4 named after the job ID. Polling stops after 30 minutes; a timeout does not
cancel GPU execution. Keep the printed job ID to retrieve its status later.
Transport retries are disabled to avoid accidental duplicate submissions.
### OpenAI Python
Install the tested client, then run the checked-in example:
```bash
python -m pip install openai==3.6.0
python examples/serving/clients/video.py
```
/_snippets/clients/video.py.md
### OpenAI JavaScript
Use Node.js 22 or later on your computer or in your webapp's backend. Do not put a
private server key in browser code.
```bash
npm ci --prefix examples/serving/clients
node examples/serving/clients/video.mjs
```
/_snippets/clients/video.mjs.md
### cURL
Install `curl` and `jq`, then run:
```bash
bash examples/serving/clients/video.sh
```
/_snippets/clients/video.sh.md
## Connect your app
Set `FASTVIDEO_BASE_URL` to the FastVideo endpoint, including `/v1`, and
`FASTVIDEO_MODEL` to its advertised model alias. The examples default to
`http://127.0.0.1:8000/v1` and `fasth3`.
For a remote GPU machine, keep the server bound to loopback and forward the
port. Replace `user@gpu-host` with your SSH destination:
```bash
ssh -N -L 8000:127.0.0.1:8000 user@gpu-host
```
Then open `http://127.0.0.1:8000/playground/` on your computer. The same forwarded
address works for the cURL and SDK clients. If local port 8000 is occupied, use
`-L 8001:127.0.0.1:8000`, open port 8001, and set `FASTVIDEO_BASE_URL` to
`http://127.0.0.1:8001/v1` for the example clients.
Your webapp backend can submit a job and return its ID to the browser. Poll
from the backend, then proxy the completed download or store it in your own
artifact store. Do not hold a browser request open for the entire generation.
The client key `local` is a placeholder required by the SDK, not server
authentication. FastVideo's HTTP server has no built-in API-key check. Before
public deployment, put it behind an authenticated TLS proxy with restricted
origins, request limits, and access controls. If your proxy uses bearer tokens,
set `FASTVIDEO_API_KEY` on your backend. Never reuse an OpenAI cloud key here.
## Compatibility and limits
The client examples target the OpenAI video-job API, not Chat Completions.
The compatibility tests cover real HTTP requests with the pinned SDKs and a
fake generator. They establish client and protocol behavior, not GPU generation
quality, latency, or memory use. The server configuration still needs a recorded
H3 hardware run before it can be marked Verified in the cookbook.
| Operation | Endpoint |
| --- | --- |
| List served models | `GET /v1/models` |
| Create a video job | `POST /v1/videos` |
| Retrieve status, including a failed job | `GET /v1/videos/{id}` |
| List jobs | `GET /v1/videos` |
| Download the MP4 | `GET /v1/videos/{id}/content` |
| Delete a job and its artifact | `DELETE /v1/videos/{id}` |
Failed jobs return HTTP 200 with `status: "failed"` and an `error` object so
SDK polling can stop. Invalid requests return HTTP 400; missing jobs return
HTTP 404. The download endpoint supports only the `video` variant, not
thumbnails or spritesheets. Remix, extensions, characters, and an OpenAI Files
store are not implemented. `/v1/videos/sync` is a FastVideo extension and is
not used by these client examples.
OpenAI marks its hosted Sora API as deprecated. FastVideo runs its own models;
the [OpenAI video API reference](https://developers.openai.com/api/reference/python/resources/videos/methods/create)
describes the client interface, not FastVideo model availability. The examples
pin tested SDK versions because future SDKs may change or remove video helpers.
The server serializes generation through one loaded pipeline. Job metadata is
in memory and is lost on restart. Async artifacts remain on disk until deleted
through the API; establish a retention policy for production use. Deleting an
in-progress job does not interrupt an already running CUDA call.
For model-specific request fields and reference media, see the
[HTTP contract](../design/server_contracts/openai.md).