API Cookbook
Product-image recipe
Use one stable requestId per intended output. Store the returned imageUrl
with your own product record and retry the same request id after a network
timeout instead of creating a new generation.
const request = {
prompt:
"A clean ecommerce product photo of a matte black water bottle on a stone pedestal, soft studio light, empty space for a headline",
model: "nano-banana-fast",
ratio: "1:1",
style: "studio",
requestId: `catalog-${productId}-hero-v1`,
};
const response = await fetch(
"https://nanobananafree.app/api/nano-banana/generate",
{
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${process.env.NANO_BANANA_API_KEY}`,
},
body: JSON.stringify(request),
}
);
if (!response.ok) throw new Error(await response.text());
const result = await response.json();
await saveProductHero(productId, result.imageUrl, result.requestId);Safe retry pattern
- Generate a deterministic request id from your business object and version.
- Persist the successful
imageUrlandrequestIdtogether. - On timeout, retry the same payload and request id.
- Treat HTTP
409as “already processing or failed”; inspect generation history before creating a new request. - Treat HTTP
402as a credit reservation failure; do not retry in a loop.
For up to four variations, use the synchronous batch endpoint. It returns
partial results with HTTP 207 when some items fail; each item has its own
request id and credit/refund history. For asynchronous terminal callbacks,
create a webhook subscription in the signed-in Webhooks console or through
POST /api/webhooks.
const batch = await fetch("https://nanobananafree.app/api/nano-banana/batch", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${process.env.NANO_BANANA_API_KEY}`,
},
body: JSON.stringify({
prompt: "a premium banana product poster in a clean studio",
model: "nano-banana-fast",
count: 3,
batchRequestId: "product-poster-v1",
}),
});
const payload = await batch.json();
const successfulImages = payload.results.filter(
(item) => item.status === "succeeded"
);Reusable production setup
When the same prompt and settings will be used repeatedly, save them as a named workflow in the signed-in studio. This preserves the generation context without copying image bytes into the workflow record. Generated image URLs still need to be stored in your own asset system if you require long-term retention.
Reference-image remix
Send a base64 data URL in image when the input is a product or subject you
own or have permission to edit. Keep the original asset in your own storage;
the API response is the generated result, not a promise of permanent hosting.