Generate images with trained models, popular public models, and reference images.
Image Generation
Use POST /images/generation to start image generation jobs. Generation is asynchronous: the trigger request returns a jobId, then you poll GET /jobs/{id} until the job has finished.
For the shared polling pattern, see Jobs.
Image generation requests send the selected model fields directly:
{
"modelID": "gpt-image-2",
"prompt": "<PROMPT>"
}Use POST /images/generation for both trained models and popular public image models. Use
POST /images/upscaling when you want to upscale an existing image.
Model choices
| Model choice | Use when | Required fields |
|---|---|---|
| Trained model ID | Generate identity-consistent images from your model. | modelID. Most workflows also include prompt, preset, or inputImageId. |
| Popular models like NanoBanana Pro, GPT Image 2, Seedream | Generate, edit, or recompose images with public IDs. | modelID, prompt. You can also include preset. |
| Existing image | Create a higher-resolution version of an image asset. | imageID with POST /images/upscaling. |
Generate with a trained model
Use a trained model ID from GET /models when you need identity consistency. Wait until the model
status is ready before starting generation.
Common fields:
| Field | Description |
|---|---|
modelID | Trained model ID returned by GET /models. |
prompt | Text prompt for the generated image. |
preset | Preset tag returned by GET /presets. |
inputImageId | Uploaded reference image ID for trained-model reference workflows. |
width | Output width in pixels. |
height | Output height in pixels. |
numImages | Number of images to generate. |
steps | Generation step count. |
seed | Seed for repeatable outputs. |
runType | Optional run mode. |
enhanceFace | Enable face enhancement for portrait workflows. |
styleStrength | Controls how strongly a reference image influences the result. |
const API_KEY = '<YOUR_API_KEY>'
const BASE_URL = 'https://developer.photogptai.com/api'
const headers = {
Authorization: `Bearer ${API_KEY}`,
'API-Version': '1',
}
const payload = {
modelID: '<MODEL_ID>',
prompt: 'professional studio headshot, charcoal blazer, soft key light',
width: 1024,
height: 1024,
numImages: 1,
steps: 30,
seed: 0,
enhanceFace: true,
}
const response = await fetch(`${BASE_URL}/images/generation`, {
method: 'POST',
headers: {
...headers,
'Content-Type': 'application/json',
},
body: JSON.stringify(payload),
})
if (!response.ok) {
throw new Error(await response.text())
}
const body = await response.json()
const jobId = body.result.jobId
console.log('Generation queued:', jobId)import requests
API_KEY = "<YOUR_API_KEY>"
BASE_URL = "https://developer.photogptai.com/api"
headers = {
"Authorization": f"Bearer {API_KEY}",
"API-Version": "1",
}
payload = {
"modelID": "<MODEL_ID>",
"prompt": "professional studio headshot, charcoal blazer, soft key light",
"width": 1024,
"height": 1024,
"numImages": 1,
"steps": 30,
"seed": 0,
"enhanceFace": True,
}
response = requests.post(f"{BASE_URL}/images/generation", headers=headers, json=payload)
response.raise_for_status()
job_id = response.json()["result"]["jobId"]
print("Generation queued:", job_id)Use an uploaded reference image
For trained-model reference workflows, upload the reference image first and pass the returned image
ID as inputImageId.
Use type: "auxiliaryType" for reference images. Use type: "modelInput" for model training images.
const referenceFile = document.querySelector('input[type="file"]').files?.[0]
if (!referenceFile) {
throw new Error('Select a reference image before uploading.')
}
const uploadData = {
modelID: '<MODEL_ID>',
type: 'auxiliaryType',
}
const formData = new FormData()
formData.append('file', referenceFile)
formData.append('data', JSON.stringify(uploadData))
const uploadResponse = await fetch(`${BASE_URL}/images/upload`, {
method: 'POST',
headers,
body: formData,
})
if (!uploadResponse.ok) {
throw new Error(await uploadResponse.text())
}
const uploadedImage = await uploadResponse.json()
const inputImageId = uploadedImage.result.id
const payload = {
modelID: '<MODEL_ID>',
prompt: 'cinematic portrait, warm window light',
inputImageId,
styleStrength: 0.35,
numImages: 1,
width: 1024,
height: 1024,
}
const response = await fetch(`${BASE_URL}/images/generation`, {
method: 'POST',
headers: {
...headers,
'Content-Type': 'application/json',
},
body: JSON.stringify(payload),
})
if (!response.ok) {
throw new Error(await response.text())
}
const body = await response.json()
const jobId = body.result.jobIdimport json
import requests
upload_data = {
"modelID": "<MODEL_ID>",
"type": "auxiliaryType",
}
with open("reference.jpg", "rb") as image_file:
files = {
"file": image_file,
"data": (None, json.dumps(upload_data), "application/json"),
}
upload_response = requests.post(
f"{BASE_URL}/images/upload",
headers=headers,
files=files,
)
upload_response.raise_for_status()
input_image_id = upload_response.json()["result"]["id"]
payload = {
"modelID": "<MODEL_ID>",
"prompt": "cinematic portrait, warm window light",
"inputImageId": input_image_id,
"styleStrength": 0.35,
"numImages": 1,
"width": 1024,
"height": 1024,
}
response = requests.post(f"{BASE_URL}/images/generation", headers=headers, json=payload)
response.raise_for_status()
job_id = response.json()["result"]["jobId"]Generate with popular image models
Use a public model ID when you want high-quality general image generation, image editing, product shots, scene recomposition, or reference-image workflows without training a model first. Popular choices include NanoBanana Pro, GPT Image 2, and Seedream.
These models use the same POST /images/generation endpoint as trained models, but the input rules
are different. The request body is matched against the model-family schema selected by modelID.
| Field | Supported values or behavior |
|---|---|
modelID | nanobanana, nanobanana-pro, nanobanana-2, seedream, seedream-4_5, seedream-5-lite, gpt-image-2. |
prompt | Required. Describe the image, edit, style, subject, and any constraints. |
preset | Optional preset tag returned by GET /presets. The preset will be applied to the image. |
aspectRatio | 1:1, 2:3, 3:2, 3:4, 4:3, 4:5, 5:4, 9:16, 16:9, 21:9. Defaults to 1:1. |
numImages | 1 to 4. |
referenceImageURLs | Public image URLs. Limits are model-specific and listed below. |
options | Send only the option group for the selected model: gemini, seedream, or openai. Do not mix option groups. |
NanoBanana
Use modelID: "nanobanana" for Gemini-backed image generation and editing.
| Setting | Values |
|---|---|
| Option group | options.gemini |
| Reference image limit | Up to 3 URLs in referenceImageURLs. |
imageSize | 1K, 2K, 4K. Defaults to 1K. |
safetyFilterLevel | OFF, BLOCK_NONE, BLOCK_ONLY_HIGH, BLOCK_MEDIUM_AND_ABOVE, BLOCK_LOW_AND_ABOVE. |
sequentialMode | disabled, sequential. Use sequential when multiple images should run one after another. |
NanoBanana Pro
Use modelID: "nanobanana-pro" when you want the higher-capability NanoBanana model for more
detailed prompts, sharper image edits, or larger reference sets.
| Setting | Values |
|---|---|
| Option group | options.gemini |
| Reference image limit | Up to 14 URLs in referenceImageURLs. |
imageSize | 1K, 2K, 4K. Defaults to 1K. |
safetyFilterLevel | OFF, BLOCK_NONE, BLOCK_ONLY_HIGH, BLOCK_MEDIUM_AND_ABOVE, BLOCK_LOW_AND_ABOVE. |
sequentialMode | disabled, sequential. Use sequential when multiple images should run one after another. |
NanoBanana 2
Use modelID: "nanobanana-2" for the newer NanoBanana family model when you need the same Gemini
option surface with support for larger reference sets.
| Setting | Values |
|---|---|
| Option group | options.gemini |
| Reference image limit | Up to 14 URLs in referenceImageURLs. |
imageSize | 1K, 2K, 4K. Defaults to 1K. |
safetyFilterLevel | OFF, BLOCK_NONE, BLOCK_ONLY_HIGH, BLOCK_MEDIUM_AND_ABOVE, BLOCK_LOW_AND_ABOVE. |
sequentialMode | disabled, sequential. Use sequential when multiple images should run one after another. |
Seedream
Use modelID: "seedream" for Seedream image generation with the widest Seedream image-size range
and fast optimization mode.
| Setting | Values |
|---|---|
| Option group | options.seedream |
| Reference image limit | Up to 10 URLs in referenceImageURLs. |
imageSize | 1K, 2K, 4K. |
optimizeMode | standard, fast. |
sequentialMode | auto, disabled. Forced to auto when numImages > 1. |
Seedream 4.5
Use modelID: "seedream-4_5" for Seedream 4.5 when you want higher-resolution outputs and do not
need fast optimization mode.
| Setting | Values |
|---|---|
| Option group | options.seedream |
| Reference image limit | Up to 10 URLs in referenceImageURLs. |
imageSize | 2K, 4K. |
optimizeMode | standard. |
sequentialMode | auto, disabled. Forced to auto when numImages > 1. |
Seedream 5 Lite
Use modelID: "seedream-5-lite" for lighter Seedream generation with 2K and 3K output sizes.
| Setting | Values |
|---|---|
| Option group | options.seedream |
| Reference image limit | Up to 10 URLs in referenceImageURLs. |
imageSize | 2K, 3K. |
optimizeMode | standard. |
sequentialMode | auto, disabled. Forced to auto when numImages > 1. |
GPT Image 2
Use modelID: "gpt-image-2" for OpenAI image generation and editing. It is a strong default for
product compositions, marketing assets, and prompt-following edits from reference images.
| Setting | Values or behavior |
|---|---|
| Option group | options.openai |
| Reference image limit | Up to 10 URLs in referenceImageURLs. |
imageSize | 1K, 2K, 4K. Combined with aspectRatio to resolve exact dimensions. |
quality | auto, high, medium, low. |
background | auto, opaque. Defaults to auto. |
moderation | auto, low. Defaults to auto. |
outputFormat | png, jpeg. Defaults to jpeg. |
outputCompression | 0 to 100. Only valid when outputFormat is jpeg. |
Resolved GPT Image 2 dimensions are constrained by the API to a maximum edge of 3840px, a maximum
3:1 aspect ratio, and dimensions that resolve to edge multiples of 16.
const payload = {
modelID: 'gpt-image-2',
prompt: 'minimal product photo of a matte black water bottle on marble',
preset: 'editorial',
aspectRatio: '1:1',
numImages: 1,
referenceImageURLs: ['https://example.com/reference-product.png'],
options: {
openai: {
imageSize: '1K',
quality: 'high',
outputFormat: 'jpeg',
},
},
}
const response = await fetch(`${BASE_URL}/images/generation`, {
method: 'POST',
headers: {
...headers,
'Content-Type': 'application/json',
},
body: JSON.stringify(payload),
})
if (!response.ok) {
throw new Error(await response.text())
}
const body = await response.json()
const jobId = body.result.jobIdpayload = {
"modelID": "gpt-image-2",
"prompt": "minimal product photo of a matte black water bottle on marble",
"preset": "editorial",
"aspectRatio": "1:1",
"numImages": 1,
"referenceImageURLs": [
"https://example.com/reference-product.png",
],
"options": {
"openai": {
"imageSize": "1K",
"quality": "high",
"outputFormat": "jpeg",
},
},
}
response = requests.post(f"{BASE_URL}/images/generation", headers=headers, json=payload)
response.raise_for_status()
job_id = response.json()["result"]["jobId"]Poll the job
Poll GET /jobs/{id} with the jobId returned by POST /images/generation. The helper below is
the same pattern described in Jobs.
async function waitForJob(jobId) {
const runningStatuses = new Set(['created', 'queued', 'running'])
while (true) {
const response = await fetch(`${BASE_URL}/jobs/${jobId}`, {
headers,
})
if (!response.ok) {
throw new Error(await response.text())
}
const body = await response.json()
const job = body.result
const status = String(job.status ?? '').toLowerCase()
if (!runningStatuses.has(status)) {
return job
}
await new Promise((resolve) => setTimeout(resolve, 5000))
}
}
const job = await waitForJob(jobId)
const status = String(job.status ?? '').toLowerCase()
if (status === 'success') {
for (const image of job.images ?? []) {
console.log(image.id, image.url)
}
} else {
throw new Error(job.error ?? `Generation failed: ${job.status}`)
}import time
def wait_for_job(job_id: str):
running_statuses = {"created", "queued", "running"}
while True:
response = requests.get(f"{BASE_URL}/jobs/{job_id}", headers=headers)
response.raise_for_status()
job = response.json()["result"]
status = job.get("status", "").lower()
if status not in running_statuses:
return job
time.sleep(5)
job = wait_for_job(job_id)
if job.get("status", "").lower() == "success":
for image in job.get("images", []):
print(image["id"], image["url"])
else:
raise RuntimeError(job.get("error") or f"Generation failed: {job.get('status')}")Fetch generated images
After the job completes, generated images are returned in result.images. You can also inspect image metadata later:
const imageId = '<IMAGE_ID>'
const response = await fetch(`${BASE_URL}/images/${imageId}`, {
headers,
})
if (!response.ok) {
throw new Error(await response.text())
}
const body = await response.json()
const image = body.result
console.log(image.url)image_id = "<IMAGE_ID>"
response = requests.get(f"{BASE_URL}/images/{image_id}", headers=headers)
response.raise_for_status()
image = response.json()["result"]
print(image["url"])To list output images for a model:
const params = new URLSearchParams({
imageType: 'output',
pageNum: '1',
pageSize: '20',
})
const response = await fetch(`${BASE_URL}/models/<MODEL_ID>/images?${params}`, {
headers,
})
if (!response.ok) {
throw new Error(await response.text())
}
const body = await response.json()
const images = body.resultresponse = requests.get(
f"{BASE_URL}/models/<MODEL_ID>/images",
headers=headers,
params={"imageType": "output", "pageNum": 1, "pageSize": 20},
)
response.raise_for_status()
images = response.json()["result"]