Short answer: you can generate images and video from the same API, key and SDK you use for chat. On the LazySusan API, images.generate covers Nano Banana 2.1 and Pro, GPT Image 2.5, FLUX 3 and FLUX 2 Pro, FLUX Kontext, Midjourney V7, Stable Diffusion 3.5, Ideogram 3.0, Recraft V3, Grok Imagine and Luma Photon. videos.create covers Veo 3.1 (with native audio), Runway Gen-4.5, Luma Ray 2, Hailuo 2.3, Pika and Vidu. Images come back in one call; video runs in the background and you wait for it. You pay per image or per clip from prepaid credits, only for what's delivered, and failed videos are refunded in full.
Here's how each part works, which model to pick for which job, and a small pipeline that turns a still into a clip.
Your first image
Install the SDK (npm install lazysusan or pip install lazysusan), set LAZYSUSAN_API_KEY, and:
import LazySusan from "lazysusan";
const ls = new LazySusan();
const img = await ls.images.generate({
model: "google/nano-banana-2.1",
prompt: "A red ceramic cube on a white table, studio light",
size: "1344x768",
});
console.log(img.images[0].url); // a permanent hosted URL
console.log(img.usage.costCredits); // what this image costIn Python:
from lazysusan import LazySusan
ls = LazySusan()
img = ls.images.generate(
model="bfl/flux-3",
prompt="A red ceramic cube on a white table, studio light",
size="1344x768",
)
print(img.images[0].url, img.cost_credits)Every image model takes the same parameters, so switching from Nano Banana to FLUX or Midjourney is a change to model, nothing else. The parameters worth knowing:
- size: one of the model's sizes, such as
1024x1024(the default),1344x768or768x1344. Nano Banana and FLUX map sizes to aspect ratios. - n: how many images. Up to 4 on Nano Banana, GPT Image and Grok Imagine; 1 on the others.
- quality: GPT Image only,
low,medium(default) orhigh. - format:
url(the default, a hosted link) orb64_jsonfor the image inline. - metadata: up to 16 tags, such as
{ campaign: "spring-launch" }, for filtering usage later.
Prompts can be up to 4,000 characters.
Which image model for which job
Image models disagree with each other far more than chat models do. A rough guide, with the per-image price in credits (1 credit = $0.001) at a standard size, from the rate card at the time of writing:
| Job | Try first | Model id | Credits per image |
|---|---|---|---|
| Edit a photo you already have | Nano Banana 2.1 | google/nano-banana-2.1 | about 39 |
| Final, detailed assets | Nano Banana Pro | google/nano-banana-pro | about 154 |
| Following long, precise instructions, text in images | GPT Image 2.5 | openai/gpt-image-2.5 | about 6 to 48, by quality |
| Photorealism | FLUX 3 | bfl/flux-3 | about 55 |
| Context-aware generation | FLUX Kontext Pro | bfl/flux-kontext-pro | 46 |
| Art-directed, stylised imagery | Midjourney V7 | midjourney/v7 | 92 |
| Anime and illustration | Niji 6 | midjourney/niji-6 | about 58 |
| Posters, logos, typography | Ideogram 3.0 | ideogram/ideogram-3 | see rate card |
| Vector icons and illustrations (SVG) | Recraft V3 Vector | recraft/recraft-v3-vector | 92 |
| Cheap drafts at volume | Luma Photon Flash | luma/photon-flash-1 | about 5 |
| Fast, cheap variations | Grok Imagine | xai/grok-imagine-image | 23 |
GPT Image models are billed by the tokens each image actually uses, so their figures are typical rather than fixed: larger sizes and higher quality use more.
The practical move is the same as with chat: draft cheap, finish expensive. Generate twenty concepts on Photon Flash or Grok Imagine, pick three, and render those on FLUX 3 or Nano Banana Pro.
Editing with reference images
Nano Banana models accept input images, which is what makes them good editors. Send one image as image, or up to three as images, as an https:// URL or a data: URL (PNG, JPEG or WebP, up to 20 MB each):
const edited = await ls.images.generate({
model: "google/nano-banana-2.1",
prompt: "Same photo, but make it golden hour and remove the cable on the left",
image: "https://example.com/product-shot.jpg",
});const combined = await ls.images.generate({
model: "google/nano-banana-pro",
prompt: "Put the mug from the first image on the desk from the second, matching the lighting",
images: ["https://example.com/mug.png", "https://example.com/desk.jpg"],
});Image URLs you send are fetched only from the public internet; private and internal addresses are refused. If you want the background on how people use Nano Banana for edits, see 9 practical ways to use Nano Banana.
What you pay for images
- Only delivered images. Ask for 4 and get 3 back, and you pay for 3.
- Declined prompts are free. If no image comes back, for example because a safety filter declined the prompt, the request returns a 400 and costs nothing.
- Hosted URLs are permanent and unguessable. Anyone with the link can open it, so treat it like a share link. If you need access control, download the file and re-host it.
Video: start it, then wait for it
Video takes from about a minute to a few minutes, so it doesn't fit in one HTTP request. videos.create starts the job and returns straight away; videos.wait polls until it's done and returns the finished video, or raises an error if it failed.
const v = await ls.videos.create({
model: "google/veo-3.1-fast",
prompt: "A slow pan across a calm lake at sunrise. Sound: birds, light wind.",
seconds: 8,
resolution: "1080p",
aspectRatio: "16:9",
metadata: { campaign: "spring-launch" },
});
const done = await ls.videos.wait(v.id);
console.log(done.videoUrl, done.costCredits);In a web app, you usually don't want a request handler sitting in wait. Store v.id, return to the user, and check later with ls.videos.get(id), or let a background worker do the waiting. Videos finish even if nobody is waiting, and ls.videos.list() returns your 50 most recent.
The video parameters:
- seconds: one of the model's durations (default: the shortest).
- resolution: one of the model's resolutions. Veo renders 1080p only at 8 seconds.
- aspectRatio:
16:9(default) or9:16; some models offer more. - image: a starting frame. Required for
runway/gen-4-turboandvidu/viduq2-turbo. - negativePrompt: Google Veo models only, up to 1,000 characters.
Which video model for which job
Clip prices in credits at the time of writing; the rate card has every length and resolution.
| Job | Model id | Audio | Example clip price |
|---|---|---|---|
| Final clip with synced sound | google/veo-3.1 | yes | 3,680 for 8 s |
| Most social clips, with sound | google/veo-3.1-fast | yes | 920 for 8 s at 720p |
| Cheap drafts with sound | google/veo-3.1-lite | yes | 460 for 8 s at 720p |
| Cinematic motion and camera moves | runway/gen-4.5 | no | 690 for 5 s |
| Animate a still, cheaply | runway/gen-4-turbo | no | 287.5 for 5 s |
| People and expressions | minimax/hailuo-2.3 | no | 322 for 6 s at 768p |
| Smooth camera motion, many aspect ratios | luma/ray-2 | no | 460 for 5 s at 540p |
| Stylised social clips | pika/pika-2.5 | no | 460 for 5 s at 540p |
| Fast, low-cost image to video | vidu/viduq2-turbo | no | 80.5 for 5 s at 540p |
If you're coming from the Sora API, which OpenAI switched off on September 24, Veo 3.1 is the closest match: one prompt in, a clip with sound out. There's a longer comparison in Sora is shut down: what to use instead.
How video billing works
- Starting a video holds its exact price from your balance while it renders (
costCreditsHeld). - On success, you're charged that amount.
- On failure, the status is
failed,error.messagesays why, and the hold is returned in full. - A video that hasn't finished after 2 hours is marked failed and refunded.
Because the price is fixed per clip, you can show users the cost before they press generate.
A small pipeline: still image to animated clip
Generating a strong first frame with an image model, then animating it, gives you far more control over composition than text-to-video alone:
import LazySusan from "lazysusan";
const ls = new LazySusan();
const tags = { campaign: "spring-launch" };
// 1. Draft four cheap concepts
const drafts = await ls.images.generate({
model: "xai/grok-imagine-image",
prompt: "Ceramic coffee mug on a sunlit kitchen counter, steam rising, editorial photo",
n: 4,
metadata: tags,
});
// 2. Re-render the chosen concept at full quality
const hero = await ls.images.generate({
model: "bfl/flux-3",
prompt: "Ceramic coffee mug on a sunlit kitchen counter, steam rising, editorial photo, 35mm",
size: "1344x768",
metadata: tags,
});
// 3. Animate it
const clip = await ls.videos.create({
model: "runway/gen-4-turbo",
prompt: "Steam curls upward, slow push in",
image: hero.images[0].url,
seconds: 5,
metadata: tags,
});
const done = await ls.videos.wait(clip.id);
console.log(done.videoUrl);Because every step carries the same campaign tag, the console can show you exactly what that campaign cost across both endpoints.
Keep keys on the server
One rule that matters more for media than for chat: generation is usually triggered from a front end, and it's tempting to call the API straight from the browser. Don't. Keep the key on your server, expose your own endpoint, and enforce your own per-user limits there. On the LazySusan side, give the service its own key with a monthly budget and an allowlist of the models you actually use, as described in setting AI API budgets per project and environment.
Not building anything?
If you want to make images and video by hand rather than in code, the same models (plus a few that are app-only, such as ElevenLabs voice) are in the LazySusan app. The models page lists them and pricing has the app plans, which are separate from API credits.
FAQ
Is there one API for both image and video generation? Yes. The LazySusan API uses one key and one SDK for chat, image and video models: images.generate for images and videos.create plus videos.wait for video.
Can I use Veo 3.1 through an API? Yes. Use the model id google/veo-3.1, google/veo-3.1-fast or google/veo-3.1-lite with videos.create. Veo clips include generated audio.
Can I use FLUX and Midjourney models through the same API? Yes. FLUX 3, FLUX 2 Pro, FLUX Kontext and FLUX 1.1 models, and Midjourney V7, V6.1, V6 and Niji 6, all use the same images.generate call. Change the model id to switch.
Am I charged if a video fails? No. The clip price is held while it renders and returned in full if it fails, including videos that haven't finished after 2 hours.
How long do generated images and videos stay available? The hosted URLs are permanent and unguessable. Anyone with a link can open it, so download and re-host files if you need to control access.