Generate AI images and videos via the LetzAI API. Images with Nano Banana Pro, Seedream 5, Flux 2, GPT Image 2; videos with Veo 3.1, Kling V3, Seedance 2.0. Includes context editing, upscaling, asset uploads, and custom @model training. Use for content creation apps and automation.
Install
npx skills add https://github.com/letz-ai/letzai-skill --skill letzai-apiLetzAI API Integration Skill
Overview
Helps you integrate the LetzAI public API for AI image and video generation, editing,
upscaling, asset uploads, and custom model (LoRA) training. Custom-trained models for
persons, objects and styles are referenced inside prompts with @modelname.
Authentication
- Base URL:
https://api.letz.ai - Auth:
Authorization: Bearer YOUR_API_KEY - Get an API key: letz.ai/subscription
- Swagger (source of truth): api.letz.ai/doc — machine-readable at
/doc-jsonand/doc-yaml
const headers = {
'Content-Type': 'application/json',
Authorization: `Bearer ${process.env.LETZAI_API_KEY}`,
};
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {os.environ['LETZAI_API_KEY']}",
}
Do not confuse the public API with the private one.
https://api.letz.aiis the public developer API described here.https://private-api.letz.aipowers the LetzAI web app and has different route names (/upscales,/image_completions,/video-edits). Those routes 404 on the public API.
Unknown-field rejection
The API validates request bodies strictly. Sending a field that is not in the schema
returns 400. In particular there is no negativePrompt, seed or aspectRatio on
POST /images — aspect ratio is expressed via width/height.
Core Workflows
1. Image Generation — POST /images
| Parameter | Type | Default | Notes |
|---|---|---|---|
prompt |
string | — | Required. May contain @modelname tags. |
baseModel |
string | account default | See model table below. |
mode |
string | model default | Resolution tier — allowed values differ per model. |
width |
int | 1600 |
480–2160 |
height |
int | 1600 |
480–2160 |
quality |
int | 2 |
1–6 |
creativity |
int | 2 |
1–6 |
hasWatermark |
bool | true |
|
systemVersion |
int | account default | 2 or 3 |
hideFromUserProfile |
bool | false |
|
webhookUrl |
string | — | POSTed when the job finishes. |
organizationId |
UUID | — | Bill credits to an org you belong to. |
Image models
mode is the resolution tier, and the accepted values are model-specific.
| Model | baseModel |
mode values |
Credits (generate) | Credits (edit) |
|---|---|---|---|---|
| Nano Banana Pro (Google) | gemini-3-pro-image |
default (1K) · 2k (HD) · 4k |
80 / 160 / 240 | 80 / 160 / 240 |
| Nano Banana 2 (Google) | nbf-inferencesh |
default (1K) · 2k (HD) · 4k |
40 / 80 / 160 | 50 / 100 / 150 |
| Nano Banana 2 Lite (Google) | nano-banana-2-lite |
default (1K) |
20 | 25 |
| Seedream 5 Pro (ByteDance) | seedream-5-0-pro |
2k (HD) · 4k |
80 / 160 | 80 / 160 |
| Seedream 4.5 (ByteDance) | seedream-4-5-251128 |
2k (HD) · 4k |
80 / 160 | 80 / 160 |
| Flux 2 (Black Forest Labs) | flux2 |
1k · hd |
60 / 120 | 60 / 120 |
| GPT Image 2 (OpenAI) | gpt-image-2 |
1k · hd · 4k |
160 / 240 / 480 | 160 / 240 / 480 |
| WAN 2.7 Image Pro (Alibaba) | wan-2-7-image-pro |
1k · 2k |
10 | 10 |
Aliases are accepted, e.g. gemini-3-pro-image-preview still resolves to Nano Banana Pro.
The live catalogue with pricing lives at letz.ai/docs/models.json.
Workflow
POST /images- Read
idfrom the response - Poll
GET /images/{id}every 3 s - On
status === "ready", readimageVersions.original
See examples/image_generation.js.
2. Video Generation — POST /videos
| Parameter | Type | Notes |
|---|---|---|
prompt |
string | Required. |
originalImageCompletionId |
UUID | Animate a previously generated LetzAI image. |
imageUrl |
string | Animate a public image URL. |
imageUrls |
string[] | Multi-frame: [0] = first frame, [1] = last frame. |
prompts |
object[] | Multi-shot storyboards (video-kling3): [{ prompt, duration }]. |
baseModel |
string | Optional; settings.mode is the usual selector. |
width / height / resolution |
number | Optional output sizing. |
settings |
object | Model + duration + audio (below). |
webhookUrl |
string | |
hidePrompt |
bool | |
organizationId |
UUID |
Image input is optional — omit all of originalImageCompletionId / imageUrl /
imageUrls for pure text-to-video.
settings
| Field | Notes |
|---|---|
mode |
Video model key — see table. |
duration |
Seconds, clamped to the model's allowed values. |
withSound |
Enable native audio where supported. |
highQuality |
Higher-resolution tier; usually doubles the price. |
resolution |
"720p", "1080p", "4k" for per-second-priced models. |
Video models
Use the video- prefixed key as settings.mode.
| Model | settings.mode |
Duration | Credits |
|---|---|---|---|
| Google Veo 3.1 | video-veo31 |
8 s (fixed) | 1500 · ×2 with audio · ×2 at 1080p |
| Kling V3 | video-kling3 |
3–15 s | 150 · 300 with audio |
| Kling V2.6 | video-kling26 |
5 or 10 s | 150 · ×2 with audio · ×2 at 1080p |
| WAN 2.5 | video-wan25 |
5 or 10 s | 110 · ×2 at 1080p (image-to-video only) |
| Seedance 2.0 | video-seedance2 |
4–15 s | per second: 105 @480p · 210 @720p · 500 @1080p · 1000 @4K (audio always on) |
| Seedance 2.0 Enterprise | video-seedance2-enterprise |
4–15 s | same as Seedance 2.0; requires organizationId |
| Gemini Omni Flash | video-gemini-omni |
3–10 s | 100 per second (audio always on) |
Workflow
POST /videos- Poll
GET /videos/{id}every 2–3 s - On
status === "ready", readvideoVersions.original
See examples/video_generation.py.
3. Image Editing — POST /image-edits
| Parameter | Type | Notes |
|---|---|---|
mode |
string | Required. context (AI editing) or skin (skin fix). |
prompt |
string | Edit instruction. May contain @modelname tags. |
imageUrl |
string | Single source image URL. |
inputImageUrls |
string[] | Multi-reference source images (up to 9 in practice). |
originalImageCompletionId |
UUID | Edit a previously generated LetzAI image. |
originalImageCompletionIds |
UUID[] | Several LetzAI images as sources. |
baseModel |
string | Same identifiers as image generation. |
settings |
object | { resolution, aspect_ratio, model } |
imageCompletionsCount |
int | Variations to generate (1–5, default 1). Not used by skin. |
mask |
string | Base64 mask, legacy inpainting only. |
width / height |
number | Target dimensions. |
webhookUrl, organizationId, hidePrompt |
settings:
resolution:"2k"(HD) or"4k"(Ultra HD)aspect_ratio:"1:1","16:9","9:16","4:3","3:4","21:9","9:21"model: same identifiers asbaseModel
Provide at least one source: imageUrl, inputImageUrls, originalImageCompletionId
or originalImageCompletionIds.
Prefer the top-level baseModel. Server-side queue routing reads baseModel;
settings.model is forwarded to the worker. Setting both to the same value is safest.
Workflow
POST /image-edits- Poll
GET /image-edits/{id}every 3 s - On
status === "ready", readgeneratedImageCompletion.imageVersions.original
mode: "in" (inpainting) and mode: "out" (outpainting) are deprecated — use context.
4. Upscaling — POST /upscale
The public route is
/upscale(singular)./upscalesis the private web-app route and returns 404 here.
| Parameter | Type | Default | Notes |
|---|---|---|---|
imageId |
UUID | — | A LetzAI image completion ID. |
imageUrl |
string | — | Public image URL. Use instead of imageId. To upscale your own file, upload it via /user-assets and pass the returned imageUrl. |
mode |
string | default |
Upscaler model — see table. |
size |
number | — | 2–12; output tier — see table. |
strength |
number | 1 |
1–5. |
prompt |
string | — | Optional guidance for creative upscalers. |
webhookUrl, organizationId |
mode |
Upscaler | size → output |
Credits |
|---|---|---|---|
nano-banana-pro |
Google Gemini 3 Pro | 4 → 1K · 8 → 2K · 12 → 4K | 80 / 160 / 240 |
nano-banana-2 |
Google Gemini 3.1 Flash | 4 → 1K · 8 → 2K · 12 → 4K | 50 / 100 / 150 |
gpt-image-2 |
OpenAI GPT Image 2 | 4 → 1K · 8 → 2K · 12 → 4K | 160 / 240 / 480 |
pruna |
Pruna P-Image-Upscale | 4 → 1 MP · 8 → 4 MP · 12 → 16 MP | 20 / 40 / 80 |
default |
LetzAI in-house | — | 20 |
Workflow
POST /upscale- Poll
GET /upscale/{id}every 3 s - On
status === "ready", readimageVersions.original
5. Uploading Your Own Files — POST /user-assets
Two-step pre-signed S3 upload. Use this to get a public URL for a local file before
feeding it to /image-edits, /videos or /upscale.
POST /user-assetswith{ extension }(plus optionaloriginalFilename,mimeType,fileSize,caption,metadata,numberOfImages).PUTthe raw file bytes to the returneduploadUrlwith the matchingContent-Typeheader. NoAuthorizationheader — the URL is already signed.- The file is then reachable at
imageUrlfrom the step-1 response.
Allowed extension values: jpg, jpeg, png, gif, webp, mp4, webm, mov,
avi, mp3, wav, ogg, m4a, aac, flac.
POST /user-images is the older image/video-only variant of the same flow; prefer
/user-assets, which also accepts audio.
See examples/uploads_and_training.md.
6. Custom AI Models (@modelname)
Trained models for persons, objects and styles. Tag them inside any image or edit
prompt: @john_doe on the beach at sunset.
List: GET /models — query params page, limit, sortBy, sortOrder, search,
name, userId, username, class (person | object | style), type,
description, privacy (public | private | licensed), systemVersion,
isActive, status. Pagination is reported through the X-Total-Count,
X-Current-Page, X-Per-Page and X-Total-Pages response headers.
Get one: GET /models/{id}
Train a new model: POST /models — this is available over the API (Enterprise
plans).
| Parameter | Notes |
|---|---|
name |
Required. Alphanumeric, _ and ., max 50 chars. Becomes the @tag. |
class |
Required. person | style | object |
privacy |
public | private | licensed |
type |
Optional; auto-generated when omitted. |
trainingDataUrls |
1–50 public image URLs. Upload via /user-assets first. |
trainingMode |
e.g. default, slow |
settings |
e.g. ["NO_ADULT_CONTENT", "NO_VIOLENCE"] |
description, website, webhookUrl, organizationId |
Optional. |
Training starts automatically. Poll GET /models/{id} until status is available.
Manage: PATCH /models/{id}, DELETE /models/{id},
PUT /models/{id}/thumbnail.
Workflow Decision Tree
Create an image → pick baseModel + mode from the model table → POST /images →
poll GET /images/{id} → imageVersions.original.
Use a trained model → GET /models?class=person to find the name → put
@name in the prompt → generate normally.
Edit an image → get a source (URL, /user-assets upload, or a LetzAI completion id)
→ POST /image-edits with mode: "context" → poll → generatedImageCompletion.imageVersions.original.
Create a video → optional source image → POST /videos with
settings.mode = a video-* key → poll → videoVersions.original.
Upscale → POST /upscale with imageId or imageUrl → poll → imageVersions.original.
Train a model → upload images via /user-assets → POST /models with
trainingDataUrls → poll GET /models/{id} until available.
Status Polling
Every generation endpoint is asynchronous: the POST returns an id, and you poll the
matching GET until a terminal status.
| Resource | Statuses |
|---|---|
| Images | new · generating · ready · failed · interrupted · not_allowed · hidden |
| Videos | new · generating · ready · saved · failed · interrupted |
| Image edits | new · generating · ready · saved · failed · interrupted |
| Upscales | new · generating · ready · failed |
| Models | new · pending · training · finished · available · failed |
There is no "in progress" status — in-flight jobs report generating. Treat
ready and saved as success; failed, interrupted and not_allowed as terminal
failures. Responses also carry progress (0–100) and, during generation, a base64
previewImage.
Recommended intervals: 3 s for images / edits / upscales, 2–3 s for videos. Pass a
webhookUrl instead of polling for production workloads.
For a full implementation, see examples/polling_pattern.md.
Error Handling
| Status | Meaning | Fix |
|---|---|---|
| 400 | Invalid parameters, or an unknown field in the body | Check ranges and remove fields that are not in the schema |
| 401 | Missing/invalid key, or not a member of organizationId |
Check the Authorization header |
| 402 | Insufficient credits | Top up at letz.ai/subscription |
| 404 | Resource not found — or you used a private-API route | Check the id, and that the path exists on api.letz.ai |
| 429 | Rate limited | Back off exponentially |
| 500 | Server error | Retry with backoff |
Limitations
- All generation is asynchronous — poll or use webhooks.
- Videos are billed per model; per-second models can be expensive at 1080p/4K.
modevalues are model-specific; an unsupported tier falls back to the model default.- Seedance 2.0 Enterprise requires an
organizationIdyou are a member of. - A paid subscription is required for API access.
Quick Reference: API Endpoints
| Endpoint | Method | Purpose |
|---|---|---|
/images |
POST | Create image |
/images |
GET | List / filter images |
/images/{id} |
GET | Image status + URLs |
/images/{id}/interruption |
PUT | Stop generation |
/images/{id}/privacy |
PUT | { privacy: "public" | "private" | "licensed" } |
/images/{id}/prompt-privacy |
PUT | Hide/show the prompt publicly |
/image-edits |
POST | Create edit |
/image-edits |
GET | List edits |
/image-edits/{id} |
GET | Edit status + URLs |
/image-edits/{imageCompletionId}/mask |
GET | Mask used for a legacy inpaint |
/videos |
POST | Create video |
/videos |
GET | List videos |
/videos/{id} |
GET | Video status + URLs |
/videos/{id}/privacy |
PUT | Change video privacy |
/videos/{id}/prompt-privacy |
PUT | Hide/show the prompt publicly |
/upscale |
POST | Create upscale |
/upscale |
GET | List upscales |
/upscale/{id} |
GET | Upscale status + URLs |
/upscale/{id} |
DELETE | Delete an upscale |
/models |
GET | List models |
/models |
POST | Train a new model |
/models/{id} |
GET | Model details |
/models/{id} |
PATCH | Update model metadata |
/models/{id} |
DELETE | Delete model |
/models/{id}/thumbnail |
PUT | Set thumbnail |
/user-assets |
POST | Get a pre-signed upload URL (image/video/audio) |
/user-assets |
GET | List uploads |
/user-assets/{id} |
GET / PATCH / DELETE | Manage an upload |
/user-images |
POST / GET | Legacy image+video-only upload flow |
/user-images/{id} |
GET / DELETE | Manage a legacy upload |
/realtime/health |
GET | Realtime gateway health |
Not on the public API (private web-app routes — these 404): /upscales,
/video-edits, /image_completions, PUT /videos/{id}/interruption.
Key response fields
- Images / upscales:
imageVersions.original,imageVersions["1920x1920"],imageVersions["640x640"] - Edits:
generatedImageCompletion.imageVersions.original(source inoriginalImageCompletion) - Videos:
videoVersions.original - In flight:
progress(0–100),previewImage(base64),statusDetailon failure
Model Catalogue
To see the current list of AI Models that are supported on LetzAI, including their parameters and token costs, always read the models.json file:
Model catalogue (live): letz.ai/docs/models.json
Additional Resources
- Swagger / OpenAPI: api.letz.ai/doc ·
/doc-json - Developer docs: letz.ai/docs/api
- Model catalogue (live): letz.ai/docs/models.json
- Detailed reference: api_reference.md
- Code examples: examples/
- LetzAI Documentation with all features of the platform: letz.ai/docs
