Node.js AI Image Generation API — GenRelay Integration Guide (2026)

Aug 17, 2026·7 min read

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 the Retry-After header 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.

Related posts

Join our DiscordNode.js AI Image Generation API — GenRelay Integration Guide (2026) — GenRelay