Skip to main content

cURL

Simple Generation (Auto Aspect Ratio)

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

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)

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

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

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

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

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

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

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));
// 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

// 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

// Good: Use webhooks
{
  "prompt": "...",
  "callback_url": "https://your-backend.com/webhooks"
}

✅ Validate Input Before Sending

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

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;
  }
}