Images API
Endpoints for managing generated images.
List Images
Retrieve paginated list of images.
GET /api/imagesQuery Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
limit | integer | 20 | Items per page (max 100) |
offset | integer | 0 | Pagination offset |
search | string | - | Search prompt text |
searchMode | string | exact | exact, all, or any matching |
dateFrom | string | - | ISO start date filter |
dateTo | string | - | ISO end date filter |
aspectRatio | string | - | Filter by aspect ratio |
operationType | string | - | Filter by operation: generate, edit, upload, character, characters, product or product-ref. Any other value is a 400 |
minSize | number | - | Minimum size in bytes |
maxSize | number | - | Maximum size in bytes |
sessionId | string | - | Filter by session |
hasNegativePrompt | boolean | - | Only images with negative prompts |
modelId | string | - | Model filter — any of the eight model IDs, or the retired gemini-flash-image to find images it made: gemini-flash-lite-image, gemini-nano-banana-2.1, gemini-pro-image, openai-gpt-image-2, openai-gpt-image-2.6-flare, openai-gpt-image-2.6-sunburst, openai-gpt-image-2.5-flare, openai-gpt-image-2.5-sunburst |
resolutionTier | string | - | 1k, 2k, 4k (comma‑separated) |
stylePresetId | integer | - | Filter by style preset |
productReferenceId | integer | - | Filter by product reference |
isReference | boolean | - | true for reference images only |
project | string | - | A project's key (or name), or none for images without a project |
tags | string | - | Tag keys, comma-separated or as repeated tags parameters; an image must have every one (up to 10) |
Results are newest‑first; sorting is not currently configurable.
Each image carries project ({ "id", "name", "key" }, or null) and tags ([{ "name", "key" }]). See Projects and Tags.
Request
curl -X GET "https://gobananasai.com/api/images?limit=20&search=sunset" \
-H "X-API-Key: sk_live_xxx"Response
{
"data": [
{
"id": 42,
"sessionId": "sess_abc123",
"fullUrl": "https://pub-xxx.r2.dev/acme-corp/2024-01-15/generate-a1b2c3d4.png",
"thumbnailUrl": "https://pub-xxx.r2.dev/acme-corp/2024-01-15/generate-a1b2c3d4-thumb.jpg",
"width": 1024,
"height": 1024,
"sizeBytes": 1048576,
"prompt": "A beautiful sunset over the ocean",
"negativePrompt": "blurry, low quality",
"operation": "generate",
"aspectRatio": "square",
"createdAt": "2024-01-15T10:30:00.000Z",
"project": { "id": 7, "name": "Brand Refresh", "key": "brand-refresh" },
"tags": [{ "name": "hero", "key": "hero" }]
}
],
"pagination": {
"total": 150,
"limit": 20,
"offset": 0
}
}Generate Image
Create a new image from a text prompt.
POST /api/imagesRequest Body
| Field | Type | Required | Description |
|---|---|---|---|
prompt | string | Yes | Text description (Gemini max: 16384, OpenAI models max: 32000) |
negative_prompt | string | No | What to avoid (max: 1024) |
aspect_ratio | string | No | Named aliases (square, portrait, landscape) or ratios (1:1, 2:3, 3:2, 3:4, 4:3, 4:5, 5:4, 9:16, 16:9, 21:9). Default: square (see Aspect ratio default) |
n | integer | No | Number of images (1-4) |
model_id | string | No | gemini-flash-lite-image (default), gemini-nano-banana-2.1, gemini-pro-image, openai-gpt-image-2, openai-gpt-image-2.6-flare, openai-gpt-image-2.6-sunburst, openai-gpt-image-2.5-flare, or openai-gpt-image-2.5-sunburst. Validated against tenant allowedModels. gemini-flash-image is a deprecated alias of gemini-nano-banana-2.1 |
resolution_tier | string | No | Gemini output tier: 1k, 2k, or 4k. Lite is fixed at 1K; higher tiers require Nano Banana 2.1 or Pro. No current model offers 0.5k |
use_google_search | boolean | No | Enable Google Search grounding for Nano Banana 2.1 or Pro |
enable_thinking | boolean | No | Enable Gemini thinking mode for Lite, Nano Banana 2.1 or Pro |
size | string | No | OpenAI models only: auto or WIDTHxHEIGHT meeting OpenAI size constraints |
output_format | string | No | OpenAI models only: png (default), jpeg, webp |
quality | string | No | OpenAI models only: low, medium, high, auto; xhigh and max require GPT Image 2.5 or 2.6 |
output_compression | integer | No | OpenAI models only (jpeg/webp): 0–100 |
background | string | No | OpenAI models only: auto (default) or opaque; GPT Image 2.5 and 2.6 also support transparent with png or webp |
moderation | string | No | OpenAI models only: auto (default) or low |
complexity | string | No | GPT Image 2.6 only: low, medium or high planning effort, separate from quality. Omitted, 2.6 uses high. Other OpenAI models answer 400 invalid_request; Gemini models ignore it |
system_instruction | string | No | Style guidance |
style_preset_id | integer | No | Apply saved preset by ID |
style_preset_name | string | No | Apply saved preset by name |
reference_images | string[] | No | Additional reference R2 keys (advanced). Each must be an image stored in this workspace (its key starts with your workspace id); any other key is rejected with 400 |
reference_group_id | integer | No | Use a saved reference group by ID |
reference_group_ids | integer[] | No | Use multiple groups (1–5) |
reference_group_name | string | No | Use a group by name |
reference_mode | string | No | 'style' for style transfer or 'add' to place the referenced elements (logos, products) in the image and keep their exact design, colours and proportions |
session_id | string | No | Custom session ID |
character_id | integer | No | Single character ID for consistent generation |
character_ids | integer[] | No | Array of character IDs (1-5) for multi-character scenes |
product_id | integer | No | Single product reference ID |
product_ids | integer[] | No | Array of product IDs (1-6) for product placement |
image_to_edit_id | integer | No | If set, edits that image instead of generating new |
camera_look | string | No | A built-in real-camera look: disposable-flash, skate-fisheye, old-phone-selfie, camcorder-still, point-and-shoot-night, street-candid-35mm, security-camera or instant-film. Its camera sentence goes before the prompt and its lighting and texture sentences after it; its negative and ratio hint apply only when nothing else sets them. Not with enhance_prompt or image_to_edit_id (400 invalid_request, sync or ?async=true). A synchronous response's metadata.camera_look names it. See Camera looks |
reference_sheet | string | No | A built-in identity plate: face-plate, outfit-plate or three-panel. Its layout sentence goes before the prompt and its lighting and backdrop sentences after it; its negative and ratio hint apply only when nothing else sets them. Not with camera_look, enhance_prompt or image_to_edit_id (400 invalid_request, sync or ?async=true). A synchronous response's metadata.reference_sheet names it. See Reference sheets |
project | string | No | Project to file the new images in (created if new; none for no project; blank counts as not given). See Projects and Tags |
tags | string[] | No | Up to 10 tags for the new images |
Default Model
gemini-flash-lite-image (Nano Banana 2 Lite) is the current default. Pass model_id to opt into gemini-nano-banana-2.1 (Nano Banana 2.1: 2K/4K, broader ratios, stronger multi-reference workflows), Pro features (grounding and premium production quality), openai-gpt-image-2 for best-in-class text rendering and quality tiers, or openai-gpt-image-2.6-flare / openai-gpt-image-2.6-sunburst (GPT Image 2.6) and openai-gpt-image-2.5-flare / openai-gpt-image-2.5-sunburst (GPT Image 2.5) for xhigh/max quality and transparent backgrounds. Requested models must be in the tenant allowlist.
Aspect ratio default
When you don't pass aspect_ratio, the shape is decided in this order:
aspect_ratioin the request, if given.- Otherwise a default saved on a scene, style preset or character you use (checked in that order).
- Otherwise the ratio hint of the
camera_lookorreference_sheet, if given. - Otherwise
square(1:1).
Edits (image_to_edit_id) keep the source image's shape unless you pass aspect_ratio or a scene, style preset or character supplies one.
Character & Product Integration
Generate images with saved characters and/or products directly via the main endpoint:
Limits:
- Maximum 5 characters per scene
- Maximum 6 products per scene
- Maximum total reference images: 14 for Gemini, 16 for OpenAI models
- Cannot mix singular and array form (e.g.,
character_id+character_ids)
Example: Character + Product Combined
curl -X POST "https://gobananasai.com/api/images" \
-H "X-API-Key: sk_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"prompt": "at a sports stadium, professional advertisement",
"character_ids": [19, 20],
"product_ids": [2],
"aspect_ratio": "16:9"
}'Prompt Construction: The system automatically builds optimized prompts based on what you provide:
- Characters only:
"The characters (Name1 and Name2) from the reference images {your prompt}" - Products only:
"Using the products shown in the reference images, {your prompt}. Maintain exact design..." - Both:
"The characters with the products shown in reference images, {your prompt}. Maintain exact product design..." reference_imageswithreference_mode: "add":"Include the elements shown in the reference images in the scene: {your prompt}. ...maintaining their exact design, colors, and proportions."reference_imageswithreference_mode: "style":"Using the visual style from the reference images, {your prompt}. Match the artistic style, color palette, lighting, mood, and visual aesthetic from the references."
Request
curl -X POST "https://gobananasai.com/api/images" \
-H "X-API-Key: sk_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"prompt": "A majestic mountain landscape at golden hour with dramatic clouds",
"negative_prompt": "blurry, watermark, text",
"aspect_ratio": "landscape",
"n": 2
}'Response
{
"data": {
"images": [
{
"id": 43,
"d1_record_id": 43,
"full_url": "https://pub-xxx.r2.dev/acme-corp/2024-01-15/generate-e5f6g7h8.png",
"thumbnail_url": "https://pub-xxx.r2.dev/acme-corp/2024-01-15/generate-e5f6g7h8-thumb.jpg",
"width": 1365,
"height": 1024,
"size_bytes": 2097152,
"format": "png",
"prompt": "A majestic mountain landscape at golden hour with dramatic clouds",
"negative_prompt": "blurry, watermark, text",
"has_synthid": true,
"created_at": "2024-01-15T10:35:00.000Z"
}
],
"metadata": {
"requested": 2,
"generated": 2,
"session_id": "sess_def456"
},
"executionId": "exec-abc123"
}
}Each image's id is its gallery id (the same value as d1_record_id). Use it with GET /api/images/:id or image_to_edit_id; when you run several generations in parallel, don't look up the newest image with GET /api/images?limit=1, because another call may have saved one after yours.
Get Image Details
Retrieve metadata and edit history for a specific image.
GET /api/images/:idRequest
curl -X GET "https://gobananasai.com/api/images/42" \
-H "X-API-Key: sk_live_xxx"Response
{
"data": {
"id": 42,
"sessionId": "sess_abc123",
"fullUrl": "https://pub-xxx.r2.dev/acme-corp/2024-01-15/generate-a1b2c3d4.png",
"thumbnailUrl": "https://pub-xxx.r2.dev/acme-corp/2024-01-15/generate-a1b2c3d4-thumb.jpg",
"width": 1024,
"height": 1024,
"sizeBytes": 1048576,
"prompt": "A beautiful sunset over the ocean",
"negativePrompt": "blurry, low quality",
"operation": "generate",
"aspectRatio": "square",
"createdAt": "2024-01-15T10:30:00.000Z",
"modelId": "gemini-pro-image",
"stylePresetId": null,
"productReferenceId": null,
"referenceGroupIds": null,
"project": { "id": 7, "name": "Brand Refresh", "key": "brand-refresh" },
"tags": [{ "name": "hero", "key": "hero" }]
}
}Edit Image
Edit an existing image by ID.
POST /api/edit-imageRequest Body
| Field | Type | Required | Description |
|---|---|---|---|
image_id | integer | Yes | Database ID of image to edit |
prompt | string | Yes | Edit instruction |
negative_prompt | string | No | What to avoid |
aspect_ratio | string | No | Change aspect ratio |
Request
curl -X POST "https://gobananasai.com/api/edit-image" \
-H "X-API-Key: sk_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"image_id": 42,
"prompt": "Add a silhouette of a sailboat in the distance"
}'Response
{
"thumbnailUrl": "https://pub-xxx.r2.dev/acme-corp/2024-01-15/edit-m3n4o5p6-thumb.jpg",
"fullUrl": "https://pub-xxx.r2.dev/acme-corp/2024-01-15/edit-m3n4o5p6.png",
"width": 1024,
"height": 1024,
"sizeBytes": 1124352,
"format": "png",
"prompt": "Add a silhouette of a sailboat in the distance",
"parentImageId": 42,
"d1RecordId": 49,
"createdAt": "2024-01-15T10:40:00.000Z"
}Delete Image
Delete an image and its associated files.
DELETE /api/images/:idRequest
curl -X DELETE "https://gobananasai.com/api/images/42" \
-H "X-API-Key: sk_live_xxx"Response
Returns 204 No Content on success (empty body).
Note
Deleting an image does not delete its edit children. Child images retain their parent_image_id reference for history tracking.
Bulk Operations
Bulk Delete
POST /api/images/delete-bulkRequest
curl -X POST "https://gobananasai.com/api/images/delete-bulk" \
-H "X-API-Key: sk_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"ids": [41, 42, 43, 44]
}'Response
{
"data": {
"deleted": [41, 42, 43, 44],
"failed": [],
"summary": {
"total": 4,
"succeeded": 4,
"failed": 0
}
}
}Bulk Download
POST /api/images/downloadRequest
curl -X POST "https://gobananasai.com/api/images/download" \
-H "X-API-Key: sk_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"imageIds": [41, 42, 43]
}' \
--output images.zipReturns a ZIP file containing the requested images.
Projects and Tags
An image can be in one project and carry up to 20 tags. Names match loosely by key: "Brand Refresh", "brand_refresh" and "BRAND-REFRESH" are one project, with the key brand-refresh. Project names are up to 100 characters and tags up to 50; none is not a project name. A renamed or merged project keeps answering to its old names.
Changes need a workspace owner or manager. OAuth clients can list projects and tags (images:read). They create them by organizing images (images:edit), or by filing new images with project or tags on generate (images:generate) and upload (images:edit). Renaming, merging and deleting are not available to them.
Organize Images
Move up to 100 images to a project, or out of theirs, and add or remove tags. Give at least one of project, addTags and removeTags.
POST /api/images/organize| Field | Type | Required | Description |
|---|---|---|---|
imageIds | integer[] | Yes | 1–100 image ids |
project | object or null | No | { "name": "..." } (found or created), { "id": 7 }, or null to take the images out of their project |
addTags | string[] | No | Up to 10 tags to add |
removeTags | string[] | No | Up to 10 tags to remove |
curl -X POST "https://gobananasai.com/api/images/organize" \
-H "X-API-Key: sk_live_xxx" \
-H "Content-Type: application/json" \
-d '{ "imageIds": [42, 43], "project": { "name": "Brand Refresh" }, "addTags": ["hero"] }'{
"data": {
"updated": [42, 43],
"notFound": [],
"project": { "id": 7, "name": "Brand Refresh", "key": "brand-refresh" },
"addedTags": [{ "name": "hero", "key": "hero" }]
}
}Ids that don't exist, and other workspaces' ids, come back in notFound. A project { "id" } your workspace doesn't have answers 404 project_not_found and changes nothing.
Select All Matching
The ids of every image GET /api/images would show for the same query parameters, in the same order, up to 1,000.
GET /api/images/ids{ "data": { "ids": [44, 43, 40], "total": 3, "truncated": false } }truncated is true when more than 1,000 images match.
List Projects
GET /api/projects{
"data": {
"projects": [
{ "id": 7, "name": "Brand Refresh", "key": "brand-refresh", "imageCount": 12, "lastImageAt": "2024-01-15 10:30:00" }
],
"unassignedCount": 30
}
}Most recently used first. unassignedCount is the number of images without a project.
Create a Project
POST /api/projects with { "name": "Brand Refresh" } finds the project that already has the name or creates it: 201 when created, 200 when found, with { "data": { "id", "name", "key", "created" } }.
Rename a Project
PATCH /api/projects/:id with { "name": "Brand Refresh 2026" } answers { "data": { "id", "name", "key" } }. When another project already has the name, it answers 409:
{
"error": "Another project already uses this name",
"code": "project_name_taken",
"conflictProjectId": 9
}Merge Projects
POST /api/projects/:id/merge with { "intoProjectId": 9 } moves the project's images and names into project 9 and deletes it: { "data": { "project": { "id", "name", "key" }, "movedImages": 12 } }.
Delete a Project
DELETE /api/projects/:id answers { "data": { "deleted": true, "unassignedImages": 12 } }. The images stay, without a project.
Tags
GET /api/tags answers { "data": { "tags": [{ "id": 3, "name": "hero", "key": "hero", "imageCount": 8 }] } }, the most used first. DELETE /api/tags/:id removes the tag from every image and answers { "data": { "deleted": true } }.
Upload an Image File
Upload a local image file (PNG, JPEG, WebP or GIF, up to 20 MB) directly, as multipart/form-data.
POST /api/images/uploadForm Fields
| Field | Type | Required | Description |
|---|---|---|---|
file | file | Yes | The image |
file_name | string | No | Filename to record instead of the file's own |
project | string | No | Project to file the image in (none for no project; blank counts as not given) |
tags | string | No | Up to 10 tags, as repeated fields or one comma-separated value |
Without a project field, the X-Go-Bananas-Project header names the project: encodeURIComponent of a name, sent by the local connector with its folder's name.
Request
curl -X POST "https://gobananasai.com/api/images/upload" \
-H "X-API-Key: sk_live_xxx" \
-F "file=@./hero.png" \
-F "project=Brand Refresh" \
-F "tags=hero,final"Response
{
"image_id": 51,
"r2_key": "acme-corp/2024-01-15/upload-u1v2w3x4.png",
"public_url": "https://pub-xxx.r2.dev/acme-corp/2024-01-15/upload-u1v2w3x4.png",
"thumbnail_url": "https://pub-xxx.r2.dev/acme-corp/2024-01-15/upload-u1v2w3x4-thumb.webp",
"size_bytes": 482133,
"mime_type": "image/png",
"file_name": "hero.png",
"project": { "id": 7, "name": "Brand Refresh", "key": "brand-refresh" },
"message": "File uploaded successfully. Image ID: 51. Ready for editing with edit_uploaded_image or edit_image MCP tools."
}If the image is saved but its project and tags cannot be applied, the response adds "warnings": ["Saved, but the project and tags could not be applied."].
Upload Image for Editing
Upload an external image for editing.
POST /api/upload-for-editingRequest Body
| Field | Type | Required | Description |
|---|---|---|---|
image_url | string | Yes | Public URL of image |
file_name | string | No | Original filename |
mime_type | string | No | Image MIME type |
Request
curl -X POST "https://gobananasai.com/api/upload-for-editing" \
-H "X-API-Key: sk_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"image_url": "https://example.com/my-image.jpg",
"file_name": "product-photo.jpg"
}'Response
{
"image_id": 50,
"r2_key": "acme-corp/2024-01-15/upload-q7r8s9t0.jpg",
"public_url": "https://pub-xxx.r2.dev/acme-corp/2024-01-15/upload-q7r8s9t0.jpg",
"size_bytes": 524288,
"mime_type": "image/jpeg",
"message": "Image uploaded successfully. ID: 50. Ready for editing."
}Generate with Character
Generate an image featuring a saved character.
POST /api/characters/:identifier/generateRequest Body
| Field | Type | Required | Description |
|---|---|---|---|
scene_prompt | string | Yes | Scene description |
additional_details | string | No | Extra details |
aspect_ratio | string | No | Aspect ratio |
override_negative_prompt | string | No | Override character negative prompt |
session_id | string | No | Custom session ID |
identifier is the character ID or name in the URL path.
Request
curl -X POST "https://gobananasai.com/api/characters/Luna/generate" \
-H "X-API-Key: sk_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"scene_prompt": "walking through a magical forest at night",
"aspect_ratio": "portrait"
}'Response
{
"data": {
"imageId": 51,
"sessionId": "sess_abc123",
"fullUrl": "https://pub-xxx.r2.dev/acme-corp/2024-01-15/generate-u1v2w3x4.png",
"thumbnailUrl": "https://pub-xxx.r2.dev/acme-corp/2024-01-15/generate-u1v2w3x4-thumb.jpg",
"width": 768,
"height": 1024,
"prompt": "The character from the reference images walking through a magical forest at night",
"message": "Image generated successfully with character \"Luna\""
}
}Generate with Product
Generate marketing image with saved product.
POST /api/products/:identifier/generateRequest Body
| Field | Type | Required | Description |
|---|---|---|---|
scene_prompt | string | Yes | Marketing scene |
additional_details | string | No | Extra styling |
aspect_ratio | string | No | Aspect ratio |
number_of_images | integer | No | 1-4 images |
negative_prompt | string | No | Optional negative prompt |
identifier is the product ID or name in the URL path.
Request
curl -X POST "https://gobananasai.com/api/products/Premium%20Headphones/generate" \
-H "X-API-Key: sk_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"scene_prompt": "on a minimalist desk with soft morning light",
"aspect_ratio": "16:9",
"number_of_images": 2
}'Response
{
"data": {
"productId": 3,
"productName": "Premium Headphones",
"scenePrompt": "on a minimalist desk with soft morning light",
"images": [
{
"id": 52,
"url": "https://pub-xxx.r2.dev/...",
"thumbnail_url": "https://pub-xxx.r2.dev/...-thumb.jpg"
}
],
"message": "Marketing images generated successfully"
}
}Error Responses
400 Bad Request
{
"error": "Invalid request payload",
"details": ["prompt is required"]
}404 Not Found
{
"error": "Image not found"
}429 Rate Limited
{
"error": "Rate limit exceeded",
"retryAfter": 30
}