cURL
Simple Generation (Auto Aspect Ratio)
Copy
curl -X POST https://platform.runblob.io/v1/chatgpt-images/generate -H "Authorization: Bearer YOUR_API_KEY" -H "Content-Type: application/json" -d '{
"prompt": "A futuristic city with flying cars, neon lights, cyberpunk style"
}'
With Custom Aspect Ratio
Copy
curl -X POST https://platform.runblob.io/v1/chatgpt-images/generate -H "Authorization: Bearer YOUR_API_KEY" -H "Content-Type: application/json" -d '{
"prompt": "A beautiful portrait in studio lighting",
"aspect_ratio": "3:4"
}'
With Reference Images (URLs)
Copy
curl -X POST https://platform.runblob.io/v1/chatgpt-images/generate -H "Authorization: Bearer YOUR_API_KEY" -H "Content-Type: application/json" -d '{
"prompt": "Combine these images into a beautiful collage",
"aspect_ratio": "4:3",
"images": [
"https://example.com/image1.jpg",
"https://example.com/image2.jpg",
"https://example.com/image3.jpg"
]
}'
With Base64 Images
Copy
curl -X POST https://platform.runblob.io/v1/chatgpt-images/generate -H "Authorization: Bearer YOUR_API_KEY" -H "Content-Type: application/json" -d '{
"prompt": "Create a story from these moments",
"images": [
"data:image/jpeg;base64,/9j/4AAQSkZJRg...",
"data:image/png;base64,iVBORw0KGgoAAAANS..."
],
"callback_url": "https://your-app.com/webhooks/chatgpt-images"
}'
Check Status
Copy
curl -X GET https://platform.runblob.io/v1/chatgpt-images/generations/dc62d83d-1953-4bca-8554-222679a7a4a9 -H "Authorization: Bearer YOUR_API_KEY"
Python
Simple Client
Copy
import requests
import time
class ChatGPTImageClient:
def __init__(self, api_key):
self.api_key = api_key
self.base_url = "https://platform.runblob.io"
self.headers = {
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json"
}
def generate(self, prompt, aspect_ratio=None, **kwargs):
payload = {"prompt": prompt}
if aspect_ratio:
payload["aspect_ratio"] = aspect_ratio
payload.update(kwargs)
response = requests.post(
f"{self.base_url}/v1/chatgpt-images/generate",
headers=self.headers,
json=payload
)
return response.json()
def generate_with_references(self, prompt, images, aspect_ratio=None, **kwargs):
payload = {
"prompt": prompt,
"images": images
}
if aspect_ratio:
payload["aspect_ratio"] = aspect_ratio
payload.update(kwargs)
response = requests.post(
f"{self.base_url}/v1/chatgpt-images/generate",
headers=self.headers,
json=payload
)
return response.json()
def status(self, task_uuid):
response = requests.get(
f"{self.base_url}/v1/chatgpt-images/generations/{task_uuid}",
headers=self.headers
)
return response.json()
def wait_for_completion(self, task_uuid, poll_interval=10):
while True:
result = self.status(task_uuid)
if result["status"] == "completed":
return result["result_image_url"]
elif result["status"] == "failed":
raise Exception(f"Generation failed: {result.get('message')}")
time.sleep(poll_interval)
# Simple generation (auto aspect ratio)
client = ChatGPTImageClient("YOUR_API_KEY")
result = client.generate("A beautiful landscape with mountains")
image_url = client.wait_for_completion(result["task_uuid"])
print(f"Image ready: {image_url}")
# With custom aspect ratio
result = client.generate("A portrait photo", aspect_ratio="3:4")
image_url = client.wait_for_completion(result["task_uuid"])
# With reference images
result = client.generate_with_references(
"Beautiful collage combining these styles",
images=[
"https://example.com/ref1.jpg",
"https://example.com/ref2.jpg"
],
aspect_ratio="1:1"
)
image_url = client.wait_for_completion(result["task_uuid"])
Advanced Usage with Error Handling
Copy
import requests
import time
from typing import Optional, List
class ChatGPTImageAPI:
def __init__(self, api_key: str):
self.api_key = api_key
self.base_url = "https://platform.runblob.io/v1/chatgpt-images"
self.headers = {
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json"
}
def generate(self, prompt: str,
aspect_ratio: Optional[str] = None,
images: Optional[List[str]] = None,
callback_url: Optional[str] = None) -> dict:
"""Create a new image generation."""
if len(prompt) < 1 or len(prompt) > 4000:
raise ValueError("Prompt must be 1-4000 characters")
payload = {"prompt": prompt}
if aspect_ratio:
if aspect_ratio not in ["1:1", "4:3", "3:4"]:
raise ValueError("aspect_ratio must be one of: 1:1, 4:3, 3:4")
payload["aspect_ratio"] = aspect_ratio
if images:
if len(images) > 4:
raise ValueError("Maximum 4 images allowed")
payload["images"] = images
if callback_url:
payload["callback_url"] = callback_url
try:
response = requests.post(
f"{self.base_url}/generate",
headers=self.headers,
json=payload
)
response.raise_for_status()
return response.json()
except requests.exceptions.HTTPError as e:
if e.response.status_code == 402:
raise Exception("Insufficient credits")
elif e.response.status_code == 401:
raise Exception("Invalid API key")
elif e.response.status_code == 400:
error_msg = e.response.json().get("detail", "Bad request")
raise Exception(f"Invalid request: {error_msg}")
elif e.response.status_code == 500:
error_msg = e.response.json().get("detail", "Server error")
raise Exception(f"Server error: {error_msg}")
elif e.response.status_code == 503:
raise Exception("Service maintenance in progress")
else:
raise Exception(f"API Error: {e.response.text}")
def get_status(self, task_uuid: str) -> dict:
"""Get generation status."""
try:
response = requests.get(
f"{self.base_url}/generations/{task_uuid}",
headers=self.headers
)
response.raise_for_status()
return response.json()
except requests.exceptions.HTTPError as e:
if e.response.status_code == 404:
raise Exception("Task not found")
raise Exception(f"API Error: {e.response.text}")
def wait_for_completion(self, task_uuid: str,
timeout: int = 300) -> Optional[str]:
"""Wait for generation to complete with timeout (default 5 min)."""
start_time = time.time()
while time.time() - start_time < timeout:
result = self.get_status(task_uuid)
if result["status"] == "completed":
return result["result_image_url"]
elif result["status"] == "failed":
error_msg = result.get("message", "Unknown error")
raise Exception(f"Generation failed: {error_msg}")
time.sleep(10)
raise Exception("Generation timeout")
# Usage
try:
client = ChatGPTImageAPI("YOUR_API_KEY")
# Auto aspect ratio (omit parameter)
result = client.generate(
prompt="A futuristic cyberpunk city"
)
print(f"Generation started: {result['task_uuid']}")
print(f"Price: ${result['price']}")
# Wait for completion
image_url = client.wait_for_completion(result['task_uuid'])
print(f"Image ready: {image_url}")
# With custom aspect ratio
result = client.generate(
prompt="Combine these images",
aspect_ratio="4:3",
images=[
"https://example.com/ref1.jpg",
"https://example.com/ref2.jpg"
],
callback_url="https://your-app.com/webhook"
)
except Exception as e:
print(f"Error: {str(e)}")
Upload Images as Base64
Copy
import base64
import requests
def image_to_base64(file_path, with_mime=True):
"""Convert image file to base64 string."""
with open(file_path, "rb") as f:
image_data = base64.b64encode(f.read()).decode("utf-8")
if with_mime:
# Detect file extension
ext = file_path.split('.')[-1].lower()
mime_type = f"image/{ext if ext != 'jpg' else 'jpeg'}"
return f"data:{mime_type};base64,{image_data}"
else:
# Plain base64 (decoded as JPEG by default)
return image_data
# Convert with MIME type
images_with_mime = [
image_to_base64("photo1.jpg", with_mime=True),
image_to_base64("photo2.png", with_mime=True)
]
# Or plain base64
images_plain = [
image_to_base64("photo1.jpg", with_mime=False),
image_to_base64("photo2.jpg", with_mime=False)
]
# Generate image
response = requests.post(
"https://platform.runblob.io/v1/chatgpt-images/generate",
headers={
"Authorization": "Bearer YOUR_API_KEY",
"Content-Type": "application/json"
},
json={
"prompt": "Create a beautiful collage from these photos",
"images": images_with_mime
}
)
result = response.json()
print(f"Task UUID: {result['task_uuid']}")
JavaScript / Node.js
Basic Client
Copy
const fetch = require('node-fetch');
class ChatGPTImageAPI {
constructor(apiKey) {
this.apiKey = apiKey;
this.baseUrl = 'https://platform.runblob.io/v1/chatgpt-images';
}
async generate(params) {
const response = await fetch(`${this.baseUrl}/generate`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${this.apiKey}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(params)
});
if (!response.ok) {
throw new Error(`API Error: ${response.statusText}`);
}
return response.json();
}
async getStatus(taskUuid) {
const response = await fetch(
`${this.baseUrl}/generations/${taskUuid}`,
{
headers: {
'Authorization': `Bearer ${this.apiKey}`
}
}
);
if (!response.ok) {
throw new Error(`API Error: ${response.statusText}`);
}
return response.json();
}
async waitForCompletion(taskUuid, pollInterval = 10000) {
while (true) {
const result = await this.getStatus(taskUuid);
if (result.status === 'completed') {
return result.result_image_url;
} else if (result.status === 'failed') {
throw new Error(`Generation failed: ${result.message}`);
}
await new Promise(resolve => setTimeout(resolve, pollInterval));
}
}
}
// Usage
const client = new ChatGPTImageAPI('YOUR_API_KEY');
// Simple generation
client.generate({
prompt: 'A futuristic cyberpunk city',
aspect_ratio: '4:3'
})
.then(result => {
console.log('Task UUID:', result.task_uuid);
return client.waitForCompletion(result.task_uuid);
})
.then(imageUrl => {
console.log('Image ready:', imageUrl);
})
.catch(error => {
console.error('Error:', error.message);
});
// With reference images
client.generate({
prompt: 'Combine these images',
aspect_ratio: '1:1',
images: [
'https://example.com/ref1.jpg',
'https://example.com/ref2.jpg'
]
})
.then(result => client.waitForCompletion(result.task_uuid))
.then(imageUrl => console.log('Image ready:', imageUrl));
With Webhooks (Recommended)
Copy
// Frontend - Start generation
const response = await fetch('https://platform.runblob.io/v1/chatgpt-images/generate', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
prompt: 'A beautiful landscape',
aspect_ratio: '4:3',
images: [
'https://example.com/ref1.jpg'
],
callback_url: 'https://your-backend.com/webhooks/chatgpt-images'
})
});
const { task_uuid } = await response.json();
// Save task_uuid, wait for webhook
// Backend - Handle webhook
app.post('/webhooks/chatgpt-images', async (req, res) => {
const { task_uuid, status, result_image_url, message } = req.body;
if (status === 'completed') {
// Update database
await db.updateGeneration(task_uuid, {
status: 'completed',
imageUrl: result_image_url
});
// Notify user
io.emit(`generation:${task_uuid}`, {
status: 'completed',
imageUrl: result_image_url
});
} else if (status === 'failed') {
await db.updateGeneration(task_uuid, {
status: 'failed',
error: message
});
io.emit(`generation:${task_uuid}`, {
status: 'failed',
error: message
});
}
res.sendStatus(200);
});
Upload Images from Browser
Copy
// Convert File to Base64
function fileToBase64(file, withMime = true) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = () => {
if (withMime) {
resolve(reader.result); // data:image/jpeg;base64,...
} else {
// Extract just the base64 part
const base64 = reader.result.split(',')[1];
resolve(base64);
}
};
reader.onerror = reject;
reader.readAsDataURL(file);
});
}
// Usage in React/Vue
const handleFileUpload = async (files) => {
const base64Images = await Promise.all(
Array.from(files).map(file => fileToBase64(file, true))
);
const response = await fetch('https://platform.runblob.io/v1/chatgpt-images/generate', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
prompt: 'Create a beautiful collage from these photos',
aspect_ratio: '1:1',
images: base64Images
})
});
const { task_uuid } = await response.json();
return task_uuid;
};
Best Practices
✅ Use Webhooks for Production
Copy
// Good: Use webhooks
{
"prompt": "...",
"callback_url": "https://your-backend.com/webhooks"
}
✅ Validate Input Before Sending
Copy
function validateRequest(data) {
// Check prompt length
if (data.prompt.length < 1 || data.prompt.length > 4000) {
return 'Prompt must be 1-4000 characters';
}
// Check aspect ratio
if (data.aspect_ratio && !['1:1', '4:3', '3:4'].includes(data.aspect_ratio)) {
return 'aspect_ratio must be one of: 1:1, 4:3, 3:4';
}
// Check image count
if (data.images && data.images.length > 4) {
return 'Maximum 4 images allowed';
}
return null; // Valid
}
✅ Handle Errors Gracefully
Copy
async function safeGenerate(request) {
try {
const response = await fetch('/v1/chatgpt-images/generate', {
method: 'POST',
headers: {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(request)
});
if (!response.ok) {
const error = await response.json();
if (response.status === 402) {
throw new Error('INSUFFICIENT_CREDITS: Please top up your balance');
}
if (response.status === 400) {
throw new Error(`Invalid request: ${error.detail}`);
}
if (response.status === 500) {
throw new Error(`Server error: ${error.detail}`);
}
if (response.status === 503) {
throw new Error('Service maintenance in progress');
}
throw new Error(`HTTP ${response.status}: ${error.detail}`);
}
return await response.json();
} catch (error) {
console.error('Generation failed:', error);
throw error;
}
}