Ready programs
GPU Forge packages, runs and updates a set of open AI models as ready programs. There is nothing to install and no model to download. You can use them in two ways:
- As jobs (
POST /v1/jobs): one request, one result, pay per render second. See Jobs. - On your own machine: add the program to your account, start a machine and call the program's own API, paying for the machine per second.
| Program | What it does | Job routes |
|---|---|---|
| FLUX 3 Klein | Makes images from a prompt, edits images, combines up to 4 reference images | /v1/generate, /v1/edit |
| Krea 2 | Makes images from a prompt (with an optional prompt writer), edits images | /v1/generate, /v1/edit |
| LTX-2.5 | Video with its own soundtrack, from a prompt or from a first frame; lips can follow speech you supply | /v1/jobs/text-to-video, /v1/jobs/image-to-video |
| MiniMax H3 | Video with sound from a prompt or frames; a talking person from one photo and your words; draft and full quality | /v1/jobs/text-to-video, /v1/jobs/image-to-video, /v1/jobs/talking-video |
The catalog is the source of truth for which routes are sold as jobs: always read job_routes from GET /v1/catalog.
Rules for every image program
- Every image carries an invisible GPU Forge mark, hidden in the pixels and signed in the file.
- Images of children are never made. A request that asks for one is refused (
422). - Results are generated by AI and may be inaccurate or unexpected; check them before you rely on them.
- Use is subject to the Terms of Service (acceptable use).
The catalog
GET /v1/catalogcurl -s "https://api.gpuforge.io/v1/catalog" -H "Authorization: Bearer $GF_KEY"Returns {"programs": [...]}. Each program:
| Field | Description |
|---|---|
capability_id | The program id. Use it as program in a job, and in POST /v1/catalog/{program_id}/add |
name | Short name |
title | Display title |
summary | What it does |
version | The current version. New versions reach your copy by themselves |
min_vram_gb | GPU memory the program needs per card |
max_price_per_hour | The price limit a new copy of the program starts with (you can change it on your copy) |
avg_price_per_hour | What one hour of a machine for this program usually costs you now: the middle of the cheapest machines that fit. Jobs are priced from this. null when nothing fits right now |
job_routes | The routes you can run as jobs. Empty = machine use only |
parked_machines | Parked machines kept for you on a new copy (always 0; parking is your choice) |
added | The id of your copy of this program, or null if you have not added it |
how_to_use | A one-line reminder of the machine flow |
Using a program on your own machine
Add it to your account (once):
curl -s -X POST "https://api.gpuforge.io/v1/catalog/<program id>/add" \ -H "Authorization: Bearer $GF_KEY" -H "Content-Type: application/json" -d '{}'201returns your copy'scapability_idand a program key (gf_api_key, shown once). Adding the same program twice answers409with the id of the copy you already have.- Start a machine:
POST /v1/capabilities/{your copy id}/deploy(or/scalewith{"desired_pods": 1}). A parked machine of the program is woken first if one is free. See Machines. - Wait for
capability_state: readyonGET /v1/fleet/{pod_id}.capability_urlis the machine's address. - Read the program's guide:
GET <capability_url>/v1withAuthorization: Bearer <program key>. Every request to the program needs that header (401without it). - Stop it:
POST /v1/fleet/{pod_id}/releaseor/park.
What you can change on your copy: its settings (idle_ttl_seconds, max_price_per_hour, surge_price_per_hour, daily_budget_usd, interruptible, only_gpus, excluded_gpus, min_gpu_family, idle_by, price_reduction), active, dormant_pods, and the program key (secrets.env.GF_API_KEY). The program itself (its files, commands and settings inside) stays ours and is updated by us: reading your copy shows those parts empty, and a machine of a copy cannot be started with your own start command, image, ports or environment. There is no SSH into machines of ready programs.
Good to know:
- Nothing is kept between starts. Each start or wake begins with an empty working folder. Upload your inputs again after every start or wake, and download each result as soon as it is made.
- For a minute or so after
ready, a video program may report"machine": "warming"onGET /v1/status; the first request waits a little. - For machines running our ready programs, the program's output is kept for 30 days:
GET /v1/fleet/{pod_id}/output?since=&limit=(1–2000, default 200).
FLUX 3 Klein (images)
Makes images from a prompt, edits images, and combines up to 4 reference images. The prompt goes to the image model exactly as written; it works best in English, as one full description: the medium ("Full-color photograph, ..."), the scene, light and camera, then each subject with concrete colors and materials.
POST /v1/generate: an image from a prompt
| Field | Required | Description |
|---|---|---|
prompt | yes | What the image shows, up to 6000 characters. Words that must appear in the image go in double quotes. With references, say what comes from each by order ("the jacket from the second image") |
reference_images | no | 0–4 images to combine, each base64 (JPEG, PNG or WebP, up to 20 MB) |
width, height | no | Both or neither. 256–2048, rounded to multiples of 16, at most 4.2 megapixels. Default 832 × 1216 |
seed | no | Integer |
POST /v1/edit: change an image
| Field | Required | Description |
|---|---|---|
image | yes | The image to edit, base64 |
prompt | yes | One instruction that states the end result and ends with what stays the same, e.g. "Change the sky to a sunset with warm orange light. Keep the buildings and the street unchanged." |
reference_images | no | 0–3 more images to take a person, look or object from (the image to edit counts as the first image) |
width, height | no | Default: the input image's shape at about 1 megapixel |
seed | no | Integer |
Response (both routes, 200)
{"image": "<base64 JPEG>", "mime_type": "image/jpeg", "width": 832, "height": 1216, "seed": 7, "seconds": {"total": 3.1}}seconds.total is the render time; jobs are billed on it. Other fields may be present; ignore fields you do not use.
Errors
400 invalid input (the message names the field) · 401 missing or wrong program key · 422 refused (the message says why) · 503 busy (see Retry-After) · 500 the render failed.
On your own machine, one image renders at a time and up to 8 wait in line. A warm machine makes an image in a few seconds.
Krea 2 (images)
Makes images from a prompt, and edits images. By default a prompt writer first turns your prompt into a full description; turn it off to send your prompt to the image model exactly as written.
POST /v1/generate: an image from a prompt
| Field | Required | Description |
|---|---|---|
prompt | yes | What the image shows, in any language, up to 6000 characters. Words that must appear in the image go in double quotes |
reference_images | no | 0–2 base64 images (JPEG, PNG or WebP, up to 20 MB). One image: the person or style to keep (an image with a face is cropped to the head first, so only the face and hair carry over). Two images: two references. None: plain text-to-image |
width, height | no | Both or neither. 512–2048, rounded to multiples of 16, at most 2.4 megapixels. Default 832 × 1216 |
seed | no | Integer |
characters | no | Up to 4 people by name: {"name", "gender" (female, male or transgender), "looks", "clothes", "reference" (1 or 2: which reference image shows them)}. Then use their names in the prompt |
camera | no | auto (default), fixed, selfie or mirror |
style | no | photo (default), anime or stylized_3d |
place, time_of_day | no | Short text |
enhance_prompt | no | true (default): the prompt writer expands your prompt first. false: the prompt goes to the image model as written (best in English, as a full description; for an edit, describe the result). With false, characters, camera, style, place, time_of_day, image_description and image_camera are refused (400): write them into the prompt |
POST /v1/edit: change an image
| Field | Required | Description |
|---|---|---|
image | yes | The image to edit, base64 |
prompt | yes | The change, e.g. "make it sunset" or "she stands up and stretches" |
reference_image | no | A second image to take a person, look or object from |
width, height | no | Default: the input image's shape at about 1 megapixel |
image_description | no | What the image to edit shows; helps keep the rest of it the same |
image_camera | no | How the image to edit was taken: fixed, selfie or mirror |
seed, enhance_prompt, characters, camera, style | no | As above |
Response (both routes, 200)
{"image": "<base64 JPEG>", "mime_type": "image/jpeg", "width": 832, "height": 1216, "seed": 7, "seconds": {"total": 16.1}}Other fields may be present; ignore fields you do not use.
Errors
400 invalid input (names the field) · 401 program key · 422 refused (the message says why, for example a prompt that cannot be drawn) · 503 busy (Retry-After) · 500 the render failed. One image renders at a time; up to 8 wait in line.
Example (on your own machine)
curl -s "<capability_url>/v1/generate" \
-H "Authorization: Bearer $PROGRAM_KEY" -H "Content-Type: application/json" \
-d '{"prompt": "A cyclist rides along a coastal road at golden hour, the sea on the left.", "seed": 7}' \
| python3 -c "import sys,json,base64; open('out.jpg','wb').write(base64.b64decode(json.load(sys.stdin)['image']))"LTX-2.5 (video with sound)
Makes 24 fps video with its own soundtrack, from a prompt alone or opening on a picture you give. If you send finished speech (audio), the lips follow it. Your prompt goes to the model exactly as written.
Job routes
| Route | What it makes |
|---|---|
/v1/jobs/text-to-video | A clip from the prompt alone |
/v1/jobs/image-to-video | A clip that opens on first_frame |
Both wait for the clip and answer with the finished video (within 580 seconds). In a job, send pictures and sounds inline, as a data: URI or plain base64.
Request fields
| Field | Default | Description |
|---|---|---|
prompt | required | What happens, as the model reads it (up to 8000 characters) |
first_frame | required for image-to-video | The picture the video opens on, cut to format at crop |
audio | none | Finished speech (from any text-to-speech or a recording), 0.3–11.2 s. The clip gets 0.5 s of quiet, then this speech; the lips follow it, and the clip is exactly that long (at least 3 s) |
seconds | 5 | 3–12. Only without audio; the model then makes the whole soundtrack from the prompt |
format | the picture's shape, else 9:16 | 9:16, 16:9, 1:1, 3:4, 4:3, 2:3, 3:2, 21:9 (about 0.5 megapixels, e.g. 544 × 960) |
crop | {"x": 0.5, "y": 0.3} | Where the frame sits on a picture of another shape (0–1 each way; 0.3 keeps faces in) |
seed | random | The same seed and request give the same video |
upload_url | none | Your own presigned PUT URL (S3, R2 or any S3-compatible store). The finished MP4 is also uploaded there |
Response (200)
{"video": "<base64 MP4>", "mime_type": "video/mp4", "seed": 81213, "format": "9:16", "clip_seconds": 5.0, "render_seconds": 14.2}With upload_url, the answer also has upload: {"status": "done", "http_status": 200, "bytes": ...} or {"status": "failed", "http_status": ..., "error": "..."}. Any error is a non-2xx answer {"error": "..."}.
Writing the prompt
- Describe the change, not the picture. With
first_frame, the first frame already shows who and where; write what happens next: the motion, the expression, the camera. - Speech: say the person talks in the first words ("She looks into the camera and talks warmly, ..."). The lips follow your
audio. - Short and concrete: one or two actions per clip, in the order they happen; the camera in its own sentence ("The camera holds still." / "The camera slowly pushes in.").
- Sound without
audio: write it into the prompt ("Rain on the window, a quiet café in the background."). - Head-and-shoulders framing gives faces the most detail.
On your own machine
The machine also offers a queue-based API: POST /v1/text-to-video and /v1/image-to-video answer 201 with a clip id; GET /v1/clips/{id}?wait=N (up to 600 s) returns the clip with a download url; POST /v1/clips/{id}/cancel; GET /v1/clips; POST /v1/uploads/photo and /v1/uploads/audio (multipart) return a name you can use in first_frame and audio; GET /v1/status. On your own machine, pictures and sounds may also be an http(s):// URL the machine can fetch. Full details: GET <capability_url>/v1.
MiniMax H3 (video with sound)
Makes 24 fps video with its own soundtrack. It can open on a picture, end on a picture, follow reference pictures and voice samples, and make a person in a photo say your words in a chosen voice. Every clip has two qualities: a fast draft for checking, and hq for delivery.
Job routes
| Route | What it makes |
|---|---|
/v1/jobs/talking-video | The person in a photo says your words to the camera |
/v1/jobs/text-to-video | A clip from the prompt alone |
/v1/jobs/image-to-video | A clip that opens on first_frame and/or ends on last_frame |
Each job stands alone and answers with the finished clip (within 580 seconds). In a job, send pictures and sounds inline (data: URI or plain base64) and voices by their ready id. For full quality send "quality": "hq": one call makes the draft pass and its upscale.
Quality
draft (default) | hq | |
|---|---|---|
| What | One fast pass at half size (352 × 608 for 9:16) | The same pass, upscaled with a detail pass to full size (704 × 1216) |
| For | Checking motion, framing, timing, speech and sound | The video you deliver |
| Looks | Soft; faces and eyes are smeared at this size | Sharp faces and eyes |
The same seed and request give the same motion, so a draft you like can be made again as hq with its seed.
/v1/jobs/talking-video fields
| Field | Default | Description |
|---|---|---|
photo | required | The person who talks; the video opens on it |
words | required (or audio) | What they say: up to about 13 s of speech (some 30 words). The clip's length follows the words (5–15 s) |
voice | chosen by the model | A ready voice id, for example emma, anna or mike |
language | en | The language of words: en es fr de it pt ru ja ko zh he ar nl pl tr (or the English name) |
audio | none | Instead of words and voice: a finished recording; the lips follow it |
seconds, format, quality, detail_steps, seed, crop, upload_url | As below |
The answer also has prompt: the prompt the program wrote for you. Send an edited version to /v1/jobs/image-to-video for full control.
/v1/jobs/text-to-video and /v1/jobs/image-to-video fields
| Field | Default | Description |
|---|---|---|
prompt | required | The H3 prompt, sent to the model as is (see "Writing the prompt") |
seconds | 5 (with audio: its length) | Whole seconds, 1–15. With audio, at least the audio's length |
format | the frame's shape, else 9:16 | 9:16, 16:9, 1:1, 3:4, 4:3, 2:3, 3:2, 21:9 |
quality | draft | draft or hq |
detail_steps | 1 | hq detail-pass steps, 1–3 |
seed | random | The same seed and request give the same motion |
first_frame | none | The video opens on exactly this picture (cut to format at crop). It is also <Picture 1>, the look reference, unless first_frame_is_reference: false |
crop | {"x": 0.5, "y": 0.3} | Where the frame sits on a picture of another shape |
last_frame | none | The video ends on this picture |
audio | none | Finished speech or sound, up to 15 s. The clip's soundtrack is this recording and the picture lip-syncs to it. Write the speaking in plain words ("she talks to the camera") |
voice | none | A ready voice id: <Audio 1>, the voice for speech your prompt writes in <d> lines |
references | none | {"images": [up to 9], "audios": [up to 3]}. Images are <Picture 2>… after a first frame (else from <Picture 1>). Audios are voice samples (about 10 s of one clean voice) |
upload_url | none | Your own presigned PUT URL; the finished MP4 is also uploaded there |
Response (200)
{"video": "<base64 MP4>", "mime_type": "video/mp4", "seed": 8121, "quality": "draft", "format": "9:16", "seconds": 5, "render_seconds": 18.4}Plus upload when you sent upload_url, and prompt on talking-video. Any error is a non-2xx answer {"error": "..."}.
Writing the prompt
An H3 prompt has six sections: subject_definitions, summary, retention_analysis, detailed_description, overall_soundscape, non_diegetic_music. Refer to inputs with exactly the labels you sent: <Picture n>, <Audio n>, and one <Subject n> per person. Name the task type in the summary: first or last frame = [keyframe completion], references = reference generation, a voice sample = audio reference; combine them with + . Speech written by the model goes in <d> lines at its moment, for example At 00:01.600, she says: <d>[English] Welcome back.</d>.
MiniMax's own prompt guide is served by the program on your machine: GET <capability_url>/v1/prompt-guide.
On your own machine
Beyond the job routes, a machine of your own offers: a clip queue (POST /v1/text-to-video, /v1/image-to-video, /v1/talking-video answer 201 with a clip id; GET /v1/clips/{id}?wait=N); POST /v1/clips/{id}/hq (the full-quality take of a finished draft, same seed, prompt and motion); POST /v1/clips/{id}/cancel; GET /v1/clips; chains of clips (continue_from, end_on) and POST /v1/join to join clips into one video; GET /v1/voices and POST /v1/voices (save your own voice sample, 3–30 s, under a name; it is gone at the next start); uploads (POST /v1/uploads/photo, /v1/uploads/voice); GET /v1/status. Full details: GET <capability_url>/v1.
Sending a video to your own bucket
Both video programs accept upload_url: a presigned PUT URL for the object you want, in Amazon S3, Cloudflare R2 or any S3-compatible store, valid for at least the render time plus a few minutes. When the clip is made, the machine uploads the MP4 there (Content-Type: video/mp4); sign the URL either without a content type or with video/mp4. Your bucket keys never reach GPU Forge, only the one URL.
import boto3
url = boto3.client("s3").generate_presigned_url(
"put_object",
Params={"Bucket": "my-videos", "Key": "clips/coast.mp4", "ContentType": "video/mp4"},
ExpiresIn=3600,
)
# then send {"prompt": "...", "upload_url": url}This page as Markdown, for tools and agents: /docs/programs.md