Node.js AI Image Generation API — GenRelay Integration Guide (2026)
Your Node.js backend needs to generate images on demand — product mockups, marketing visuals, user avatars — and you want to call the right AI image model without managing multiple vendor SDKs or accounts. This guide shows you how to integrate GenRelay's image generation API into a Node.js application from a blank file to working batch generation, covering authentication, model selection, error handling, and per-model pricing.
How Does the GenRelay Image API Work?
The GenRelay image API exposes a single POST endpoint — https://genrelay.ai/v1/images/generations — for all three image models available as of August 2026. You select the model in the request body; the response returns a hosted URL or base64-encoded image synchronously. Unlike video generation, image responses do not require polling — the HTTP response arrives when the image is ready, typically within 5–15 seconds depending on resolution.
Available image models:
| Model | Strengths | Resolution options | Price per image |
|---|---|---|---|
| Nano Banana Pro | Photorealistic, fine texture, high-detail output | 1K · 2K · 4K | $0.030 (1K/2K) · $0.042 (4K) |
| Nano Banana 2 | Balanced quality and cost, general-purpose | 1K · 4K | $0.020 (1K) · $0.036 (4K) |
| GPT-image-2 | Fast, instruction-following, supports editing/inpainting | Standard | $0.014 |
How Do I Authenticate with the GenRelay API?
Every request requires an Authorization: Bearer <key> header. Retrieve your API key from the GenRelay dashboard after signing up at genrelay.ai. Create one key per environment (development, staging, production) so you can rotate them independently.
// config/genrelay.js
const API_KEY = process.env.GENRELAY_API_KEY;
if (!API_KEY) throw new Error("GENRELAY_API_KEY environment variable is not set");
export const BASE_URL = "https://genrelay.ai";
export const authHeaders = {
Authorization: `Bearer ${API_KEY}`,
"Content-Type": "application/json",
};
Store the key in .env locally (add .env to .gitignore), and use your platform's secrets manager in production — AWS Secrets Manager, Railway environment variables, or Vercel project settings.
How Do I Make My First Image Generation Request?
Node.js 18+ includes fetch natively. The following function sends a request to Nano Banana Pro at 1K resolution and returns the image URL:
import { authHeaders, BASE_URL } from "./config/genrelay.js";
async function generateImage({ model, prompt, resolution }) {
const response = await fetch(`${BASE_URL}/v1/images/generations`, {
method: "POST",
headers: authHeaders,
body: JSON.stringify({ model, prompt, resolution }),
});
if (!response.ok) {
const error = await response.json().catch(() => ({ message: response.statusText }));
throw new Error(`GenRelay ${response.status}: ${error.message}`);
}
const data = await response.json();
// data.data[0].url — hosted CDN URL, expires after ~1 hour
return data.data[0].url;
}
// Generate a product image
const url = await generateImage({
model: "nano-banana-pro",
prompt: "studio product shot of wireless headphones on a white surface, soft shadow, professional photography",
resolution: "1k",
});
console.log("Image URL:", url);
The response structure follows the same shape as OpenAI's images API: { data: [{ url: "https://..." }] }. If you need raw bytes instead of a URL, add "response_format": "b64_json" to the request body — the response will include data[0].b64_json.
Which Image Model Should I Use?
Nano Banana Pro is the right choice when image quality is the primary constraint: product hero shots, portfolio images, marketing visuals, or any context where texture detail and photorealism matter. At $0.030 for 1K and $0.042 for 4K, it's the highest-cost option but produces noticeably richer output. See the Nano Banana model page for supported styles and sample outputs.
Nano Banana 2 at $0.020 per image (1K) is 33% cheaper than Nano Banana Pro at the same resolution, with slightly less texture detail. It's the right default for thumbnails, app-generated content, previews, or any high-volume workflow where cost efficiency matters more than maximum fidelity.
GPT-image-2 at $0.014 is the most cost-effective option and excels at instruction-following prompts — accurate text rendering within images, structured compositions with specific element placement, and image editing via inpainting. See the GPT-image-2 guide for the full inpainting parameter reference. For a detailed cost comparison across all three models, see the AI image API pricing comparison.
How Do I Switch Models or Run A/B Tests in Node.js?
Because all models share the same endpoint, model switching is a configuration change, not an architectural one. A simple factory pattern handles model-specific defaults:
const IMAGE_MODELS = {
"nano-banana-pro": { model: "nano-banana-pro", resolution: "1k" },
"nano-banana-pro-4k": { model: "nano-banana-pro", resolution: "4k" },
"nano-banana-2": { model: "nano-banana-2", resolution: "1k" },
"gpt-image-2": { model: "gpt-image-2" },
};
async function generateWithModel(modelKey, prompt, overrides = {}) {
const config = IMAGE_MODELS[modelKey];
if (!config) throw new Error(`Unknown model key: ${modelKey}`);
const response = await fetch(`${BASE_URL}/v1/images/generations`, {
method: "POST",
headers: authHeaders,
body: JSON.stringify({ ...config, ...overrides, prompt }),
});
if (!response.ok) {
const err = await response.json().catch(() => ({}));
throw new Error(`GenRelay ${response.status}: ${err.message}`);
}
const data = await response.json();
return data.data[0].url;
}
// Route premium users to Nano Banana Pro, free users to GPT-image-2
const modelKey = user.isPremium ? "nano-banana-pro" : "gpt-image-2";
const imageUrl = await generateWithModel(modelKey, prompt);
This pattern supports user-tier routing, per-feature model selection, and A/B testing without changes to your HTTP layer.
How Do I Generate Multiple Images in Parallel?
For bulk generation — product color variants, social media assets, prompt comparisons — run requests concurrently with Promise.allSettled. This handles individual failures without canceling the entire batch:
async function batchGenerate(prompts, modelKey = "nano-banana-2") {
const tasks = prompts.map((prompt) => generateWithModel(modelKey, prompt));
const results = await Promise.allSettled(tasks);
return results.map((result, i) => ({
prompt: prompts[i],
success: result.status === "fulfilled",
url: result.status === "fulfilled" ? result.value : null,
error: result.status === "rejected" ? result.reason.message : null,
}));
}
const colorVariants = [
"product photo of a matte black water bottle on white background",
"product photo of a matte white water bottle on white background",
"product photo of a forest green water bottle on white background",
"product photo of a navy blue water bottle on white background",
];
const images = await batchGenerate(colorVariants);
images.forEach(({ prompt, success, url, error }) => {
if (success) console.log(`✅ ${url}`);
else console.error(`❌ Failed: ${error}`);
});
Generating 4 images with nano-banana-2 at 1K costs $0.08 total. Use Promise.all if any single failure should abort the batch; Promise.allSettled is the better default for batch jobs where partial success is acceptable.
FAQ
Does GenRelay have a Node.js npm package?
There is no dedicated npm package — the API is standard REST and Node.js 18+ native fetch is sufficient. The API request/response shape is compatible with the openai npm package if you configure a custom baseURL, since GenRelay follows the same conventions for image generation endpoints.
What does the image URL expiry mean for my application?
The hosted CDN URL in data[0].url expires after approximately one hour. For user-facing applications, either present the URL immediately after generation, or download the image to your own object storage (S3, R2, Cloudinary) within that window. Use response_format: "b64_json" if you need to process the image server-side before deciding whether to persist it.
What HTTP status codes should I handle?
200— Success, image generated.400— Invalid parameters or content policy violation. Not charged.401— Invalid or missing API key.429— Rate limit exceeded — implement exponential backoff and retry after theRetry-Afterheader value.5xx— Server error — retry with backoff; failed generations are not charged.
Can I use this with TypeScript?
Yes. Define types inline:
interface GenerateOptions {
model: "nano-banana-pro" | "nano-banana-2" | "gpt-image-2";
prompt: string;
resolution?: "1k" | "2k" | "4k";
response_format?: "url" | "b64_json";
}
The API response type is { data: Array<{ url?: string; b64_json?: string }> }.
How do I save the generated image to disk from Node.js?
Once you have the image URL, download it with fetch and write it using fs/promises:
import { writeFile } from "fs/promises";
async function saveImage(url, filename) {
const resp = await fetch(url);
const buffer = await resp.arrayBuffer();
await writeFile(filename, Buffer.from(buffer));
console.log(`Saved: ${filename}`);
}
await saveImage(imageUrl, "output.png");
Is the 1K resolution label the same pixel dimensions across all models?
The 1K label refers to approximately 1024px on the longest side, but exact output dimensions vary by model. GPT-image-2 does not accept a resolution parameter and uses its own fixed output sizes. Check the model's page on genrelay.ai for precise pixel dimensions before building downstream image processing logic that assumes specific dimensions.