After imagen-4.0-generate-001: read n from endpoints, use webhook mode
Do not assume your old image count carries over. Read supported_parameters.n from the Sume endpoints route, then submit in webhook mode and wait for.

Ask the model's endpoints route how many images one request may return, cap your n at that, and send the request with mode: "webhook" so the images arrive on job.completed. Google shut down imagen-4.0-generate-001 on August 17, 2026 and points to gemini-nano-banana-2.1, and nothing guarantees the replacement takes the same per-request count as your old code assumed.
Where the number lives
Sume's image docs show each endpoint record with supported_parameters. n appears there as a range with min and max; the docs' example uses 1 to 4 for one model, which is an example, not a promise for yours. Read it for the id you call.
| Question | Route | Field |
|---|---|---|
| Which models exist | GET /v1/images/models | data[].id |
| How many images per call | GET /v1/images/models/{id}/endpoints | supported_parameters.n.max |
| What it costs | same endpoints route | pricing lines |
| Which ratios and sizes | same endpoints route | supported_parameters |
The submit
mode: "webhook" with a webhook_url makes /v1/images answer 202 with the job envelope; the images come later as artifacts in the job.completed payload. The webhook_url must be public HTTPS; localhost and private addresses are rejected. The sample prints the status and the cap it used.
Webhook delivery makes up to 10 attempts at 30-second spacing and can repeat, so dedupe on job_id. Keep a poll of status_url as a fallback for a missed delivery.
const base = process.env.SUME_BASE ?? "https://api.sume.com";
const headers = { Authorization: `Bearer ${process.env.SUME_API_KEY}`, "Content-Type": "application/json" };
const model = "google/nano-banana-2.1";
const meta = await (await fetch(`${base}/v1/images/models/${model}/endpoints`, { headers })).json();
const nMax = meta.endpoints[0].supported_parameters.n?.max ?? 1; // read it; do not assume Imagen's old count
const res = await fetch(`${base}/v1/images`, {
method: "POST",
headers: { ...headers, "Idempotency-Key": "catalog-shoot-0042" },
body: JSON.stringify({ model, prompt: "ceramic mug on oak table", n: Math.min(4, nMax), mode: "webhook", webhook_url: "https://hooks.example.com/sume" }),
});
console.log(res.status, nMax); // 202 with the job envelope; the images arrive via job.completedWhat this skips
The sample does not verify a signature, because it only sends; your receiver must check x-sume-webhook-signature before it trusts the body. It also uses a placeholder hook host, so swap in your own. A big n at high quality can exceed the 30-second wait in sync mode, which is the reason to go async here rather than hold an HTTP request open.
Sources
Related posts
More in Developers
- Agno's DALL-E toolkit defaults to dall-e-3, removed May 12: fix
Agno issue 10817: tools/dalle.py:20 and tools/openai.py:53 default to dall-e-3, removed May 12, 2026. A fix and a Python call to Sume instead.
- AI music generator API key: a Python script that polls and downloads
Use your SUME_API_KEY to generate a track with the Music Router, poll the job and read the audio URL. A 28-line Python script with the $0.125 price.
- AI song generator API: section markers in, lyrics out, $0.125
Sume Music Router writes songs from a 5,000-character prompt: put [0:00-0:30] section markers and a BPM in, read result.lyrics out. $0.125 each.
- aiohttp web server: verify a Sume webhook with await request.read()
An aiohttp 3.14 web handler that verifies the Sume HMAC on await request.read(), then calls request.json(). Exits on an empty secret and handles webhook.test.
Written by Sume