{
  "openapi": "3.0.1",
  "info": {
    "title": "Bulk AI Image Generator & Editor: Nano Banana, GPT Image",
    "description": "Generate hundreds of AI images from prompts or an Excel/CSV file, or edit your own product photos in bulk: white or transparent background with no AI, or lifestyle scenes with the product kept pixel-exact. Nano Banana Pro, Nano Banana 2, GPT Image. No API key needed.",
    "version": "0.1",
    "x-build-id": "p0aim0QKkRnOeoCVj"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/fayoussef~bulk-ai-image-generator/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-fayoussef-bulk-ai-image-generator",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/acts/fayoussef~bulk-ai-image-generator/runs": {
      "post": {
        "operationId": "runs-sync-fayoussef-bulk-ai-image-generator",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor and returns information about the initiated run in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/runsResponseSchema"
                }
              }
            }
          }
        }
      }
    },
    "/acts/fayoussef~bulk-ai-image-generator/run-sync": {
      "post": {
        "operationId": "run-sync-fayoussef-bulk-ai-image-generator",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "inputSchema": {
        "type": "object",
        "properties": {
          "prompts": {
            "title": "Prompts",
            "type": "array",
            "description": "One text prompt per image you want to generate. Each prompt can be combined with the 'Images per prompt' setting to create multiple variations. With a spreadsheet attached, write a prompt with column names in double curly braces, for example: Studio product photo of a {{Color}} {{Product}} on a white background. It is filled in for every row. Prompts without placeholders are ignored in that case. When you edit photos (below), each prompt is an edit instruction applied to every photo, for example: Put the product on a marble kitchen counter. The two example prompts of the form are never used as edit instructions.",
            "items": {
              "type": "string"
            }
          },
          "imageUrls": {
            "title": "Photos to edit (optional)",
            "type": "array",
            "description": "Optional. Links to your own photos (JPG, PNG, WebP or GIF, public links or Google Drive share links). With photos here the Actor edits them instead of creating new images: every photo gets every prompt, or the ready-made edit chosen below. Leave empty to generate images from text as usual.",
            "items": {
              "type": "string"
            }
          },
          "editPreset": {
            "title": "Edit preset (photos only)",
            "enum": [
              "none",
              "white-background",
              "transparent-background",
              "scene-desk",
              "scene-kitchen",
              "scene-living-room",
              "scene-outdoor",
              "scene-studio",
              "scene-custom"
            ],
            "type": "string",
            "description": "Optional ready-made edit for product photos. 'No AI' presets cut the product out locally and never redraw it, so logos and text stay exact and no AI cost applies. 'Scene' presets paint a background around the product with the chosen model, then paste the original product back on top so it stays exact. Leave empty to apply your own prompts instead.",
            "default": "none"
          },
          "spreadsheetFile": {
            "title": "Spreadsheet (optional)",
            "type": "string",
            "description": "Optional. Upload an Excel (.xlsx), CSV or TSV file, or paste a public link to one (Google Sheets links work if the sheet is shared as 'Anyone with the link'). The first row must be the column names. Each row becomes one image (times 'Images per prompt'): either from a prompt above with {{Column}} placeholders, or from the prompt column below. You get your file back as results.xlsx with an image link on every row. Leave empty to use the Prompts list as usual."
          },
          "promptColumn": {
            "title": "Prompt column (spreadsheet only)",
            "type": "string",
            "description": "Which column holds the image prompt, when you do not write a {{Column}} template above. Leave empty to pick it automatically: a column named 'prompt' or 'description' if there is one, otherwise the column with the longest text."
          },
          "sheetName": {
            "title": "Sheet name (optional)",
            "type": "string",
            "description": "Only for Excel files with several sheets. Leave empty to read the first sheet."
          },
          "imageColumn": {
            "title": "Photo column (spreadsheet only)",
            "type": "string",
            "description": "Spreadsheet runs only: the column that holds a photo link on each row. Set it to edit those photos (one per row) instead of generating new images. Rows without a link are skipped. Leave empty to generate images as usual."
          },
          "model": {
            "title": "Image model",
            "enum": [
              "google/gemini-3-pro-image",
              "google/gemini-3-pro-image-preview",
              "google/gemini-3.1-flash-image",
              "google/gemini-3.1-flash-image-preview",
              "openai/gpt-5.4-image-2",
              "openai/gpt-5-image",
              "openai/gpt-5-image-mini",
              "google/gemini-2.5-flash-image",
              "google/gemini-nano-banana-2.1",
              "google/gemini-3.1-flash-lite-image"
            ],
            "type": "string",
            "description": "Which OpenRouter image model to use. Defaults to Gemini 2.5 Flash Image (reliable, handles terse prompts well). Every model in this list can also edit photos. Use 'Custom model ID' below to use any other OpenRouter model; a custom model that only accepts text cannot edit photos, and an edit run with one stops before any work.",
            "default": "google/gemini-2.5-flash-image"
          },
          "systemPrompt": {
            "title": "System prompt (optional)",
            "type": "string",
            "description": "Optional extra instructions applied to every image (e.g. a consistent style, brand, or quality directive). This is appended to the built-in instruction that forces the model to always render an image and never reply with text."
          },
          "customModelId": {
            "title": "Custom model ID (advanced)",
            "type": "string",
            "description": "Optional. Any OpenRouter model ID with image output, e.g. 'google/gemini-2.5-flash-image'. Overrides the 'Image model' selection above. See https://openrouter.ai/models?fmt=cards&output_modalities=image."
          },
          "aspectRatio": {
            "title": "Aspect ratio",
            "enum": [
              "1:1",
              "16:9",
              "9:16",
              "4:3",
              "3:4",
              "3:2",
              "2:3",
              "21:9"
            ],
            "type": "string",
            "description": "Aspect ratio of the generated images. Support varies by model; ignored by models that do not accept it. When editing photos, each photo keeps its own shape unless you untick 'Keep each photo's shape'.",
            "default": "1:1"
          },
          "imageSize": {
            "title": "Image resolution",
            "enum": [
              "0.5K",
              "1K",
              "2K",
              "4K"
            ],
            "type": "string",
            "description": "Output resolution. Higher resolutions cost more OpenRouter credit. Support varies by model. For the no-AI presets it sets the longer side: 0.5K = 512 px, 1K = 1024 px, 2K = 2048 px, 4K = 4096 px (Amazon recommends at least 1600 px for zoom, so pick 2K there).",
            "default": "1K"
          },
          "matchInputAspectRatio": {
            "title": "Keep each photo's shape (photos only)",
            "type": "boolean",
            "description": "Photos only: give each edited image the aspect ratio closest to its original photo, so a tall photo stays tall. Untick to use the 'Aspect ratio' above for every photo.",
            "default": true
          },
          "productFill": {
            "title": "Product size on white background (%)",
            "minimum": 30,
            "maximum": 100,
            "type": "integer",
            "description": "White background preset only: how much of the image the product fills, in percent of the longer side. 85 matches Amazon's main-image guideline.",
            "default": 85
          },
          "protectProduct": {
            "title": "Keep the product pixel-exact in scenes",
            "type": "boolean",
            "description": "Scene presets only: paste the original product back over the AI scene, so logos, text and colours stay exactly as in your photo. When the AI moved or resized the product, the AI version is kept and the row shows productProtected: false.",
            "default": true
          },
          "imagesPerPrompt": {
            "title": "Images per prompt",
            "minimum": 1,
            "maximum": 10,
            "type": "integer",
            "description": "How many image variations to generate for each prompt (1-10). The no-AI presets always make one image per photo.",
            "default": 1
          },
          "concurrency": {
            "title": "Concurrency",
            "minimum": 1,
            "maximum": 20,
            "type": "integer",
            "description": "How many images to generate in parallel. Higher is faster, but the built-in AI access starts refusing connections above about 6, which shows up as failed prompts rather than as speed. Raise it only when you supply your own OpenRouter API key (1-20).",
            "default": 4
          },
          "maxItems": {
            "title": "Max images (optional cap)",
            "minimum": 1,
            "type": "integer",
            "description": "Optional hard cap on the total number of images generated in this run, useful for controlling spend. Leave empty to generate one image for every prompt × images-per-prompt."
          },
          "openRouterApiKey": {
            "title": "OpenRouter API key (optional)",
            "type": "string",
            "description": "Optional. Bring your own OpenRouter API key to call OpenRouter directly and bill your own OpenRouter account. It starts with sk-or- (create one at https://openrouter.ai/keys); keys from OpenAI, Google or Apify do not work here. Leave empty to use the built-in apify/openrouter proxy (billed as Apify credit, no key needed)."
          },
          "proxyBaseUrl": {
            "title": "OpenRouter proxy base URL (advanced)",
            "type": "string",
            "description": "Advanced. Override the API base URL. Leave empty to use the default (apify/openrouter proxy, or https://openrouter.ai/api/v1 when an OpenRouter API key is provided)."
          }
        }
      },
      "runsResponseSchema": {
        "type": "object",
        "properties": {
          "data": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "actId": {
                "type": "string"
              },
              "userId": {
                "type": "string"
              },
              "startedAt": {
                "type": "string",
                "format": "date-time",
                "example": "2025-01-08T00:00:00.000Z"
              },
              "finishedAt": {
                "type": "string",
                "format": "date-time",
                "example": "2025-01-08T00:00:00.000Z"
              },
              "status": {
                "type": "string",
                "example": "READY"
              },
              "meta": {
                "type": "object",
                "properties": {
                  "origin": {
                    "type": "string",
                    "example": "API"
                  },
                  "userAgent": {
                    "type": "string"
                  }
                }
              },
              "stats": {
                "type": "object",
                "properties": {
                  "inputBodyLen": {
                    "type": "integer",
                    "example": 2000
                  },
                  "rebootCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "restartCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "resurrectCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "computeUnits": {
                    "type": "integer",
                    "example": 0
                  }
                }
              },
              "options": {
                "type": "object",
                "properties": {
                  "build": {
                    "type": "string",
                    "example": "latest"
                  },
                  "timeoutSecs": {
                    "type": "integer",
                    "example": 300
                  },
                  "memoryMbytes": {
                    "type": "integer",
                    "example": 1024
                  },
                  "diskMbytes": {
                    "type": "integer",
                    "example": 2048
                  }
                }
              },
              "buildId": {
                "type": "string"
              },
              "defaultKeyValueStoreId": {
                "type": "string"
              },
              "defaultDatasetId": {
                "type": "string"
              },
              "defaultRequestQueueId": {
                "type": "string"
              },
              "buildNumber": {
                "type": "string",
                "example": "1.0.0"
              },
              "containerUrl": {
                "type": "string"
              },
              "usage": {
                "type": "object",
                "properties": {
                  "ACTOR_COMPUTE_UNITS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_WRITES": {
                    "type": "integer",
                    "example": 1
                  },
                  "KEY_VALUE_STORE_LISTS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_INTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_EXTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_SERPS": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_UNBLOCKER_UNITS": {
                    "type": "integer",
                    "example": 0
                  }
                }
              },
              "usageTotalUsd": {
                "type": "number",
                "example": 0.00005
              },
              "usageUsd": {
                "type": "object",
                "properties": {
                  "ACTOR_COMPUTE_UNITS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_WRITES": {
                    "type": "number",
                    "example": 0.00005
                  },
                  "KEY_VALUE_STORE_LISTS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_INTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_EXTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_SERPS": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_UNBLOCKER_UNITS": {
                    "type": "integer",
                    "example": 0
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}