Moderation, SDK incompatibilities, and cost control
On this page
Updated November 2, 2026 — Imagine.
grok-imagine-image-qualitywas removed on November 2, 2026 (its requests are served by Imagine 2.0 inlowquality): examples now usegrok-imagine-image(Imagine 1.0) andgrok-imagine-image-2.0(Imagine 2.0,low,medium, orautoquality). With the OpenAI SDK,aspect_ratio,resolution, andqualitygo throughextra_body, and editing goes through the xAI SDK or an HTTP request.
Understand the image API limits
To build reliable applications with the Grok image generation API, you need to know its limits: automatic moderation, incompatibility with certain OpenAI SDK methods, and cost control mechanisms.
Content moderation
The API automatically moderates prompts and generated images. Certain content types are refused:
- Explicitly violent or gore content
- Explicitly sexual content
- Hateful or discriminatory content
- Content involving minors inappropriately
When moderation is triggered, the API returns an error instead of an image.
Handle moderation refusals
import requests
import os
headers = {
"Authorization": f"Bearer {os.getenv('XAI_API_KEY')}",
"Content-Type": "application/json"
}
def generate_safe(prompt, **kwargs):
"""Generate an image while handling moderation refusals."""
try:
response = requests.post(
"https://api.x.ai/v1/images/generations",
headers=headers,
json={"model": "grok-imagine-image", "prompt": prompt, **kwargs}
)
response.raise_for_status()
return response.json()["data"][0]["url"]
except requests.exceptions.HTTPError as e:
if response.status_code == 400:
print(f"Prompt refused by moderation: {prompt[:50]}...")
return None
raise
Moderation best practices
In practice, handle moderation upstream rather than reactively. If a legitimate prompt is blocked, test variations to identify the trigger word—“epic battle” will pass where a cruder term won’t, and mapping these sensitivities avoids recurrent blocks. When prompts come from your users, add a server-side prefilter before the API call: it intercepts obviously out-of-policy requests without consuming a request, and keeps you in control of the displayed message. Because this last point makes the experience difference: a moderation block should never reach the user as a raw technical error, but as a clear message—“this request does not comply with our terms of use”—that explains without exposing API details.
OpenAI SDK incompatibility for editing
This is a critical point: the OpenAI SDK images.edit() method does not work with the xAI API. The OpenAI SDK sends data as multipart/form-data, while the xAI API expects application/json.
# DOES NOT WORK
from openai import OpenAI
client = OpenAI(api_key=os.getenv("XAI_API_KEY"), base_url="https://api.x.ai/v1")
client.images.edit(
model="grok-imagine-image",
image=open("photo.png", "rb"),
prompt="Edit this image"
)
# → Content-type error!
# WORKS: direct REST call
import requests
response = requests.post(
"https://api.x.ai/v1/images/edits",
headers={
"Authorization": f"Bearer {os.getenv('XAI_API_KEY')}",
"Content-Type": "application/json"
},
json={
"model": "grok-imagine-image",
"prompt": "Edit this image",
"image": {"url": "https://exemple.com/photo.jpg"}
}
)
Compatibility summary
| Operation | OpenAI SDK | REST (requests) |
|---|---|---|
| images.generate() | Compatible | Compatible |
| images.edit() | Incompatible | Compatible |
Cost control
Monitor consumption
Set up a spending counter in your code:
class ImageBudgetTracker:
PRICES = {
"grok-imagine-image": 0.02,
"grok-imagine-image-2.0": 0.04, # low quality; medium at grid rate
}
def __init__(self, budget_limit=10.0):
self.total_spent = 0.0
self.budget_limit = budget_limit
self.image_count = 0
def can_generate(self, model, n=1):
cost = self.PRICES[model] * n
return (self.total_spent + cost) <= self.budget_limit
def record(self, model, n=1):
cost = self.PRICES[model] * n
self.total_spent += cost
self.image_count += n
def report(self):
remaining = self.budget_limit - self.total_spent
print(f"Images generated: {self.image_count}")
print(f"Spent: ${self.total_spent:.2f}")
print(f"Remaining budget: ${remaining:.2f}")
# Usage
tracker = ImageBudgetTracker(budget_limit=5.0)
if tracker.can_generate("grok-imagine-image", n=5):
response = client.images.generate(
model="grok-imagine-image",
prompt="My image",
n=5
)
tracker.record("grok-imagine-image", n=5)
tracker.report()
Optimize costs
The golden rule is to separate exploration and production. During prompt search, work with Imagine 1.0 ($0.02) with n=3-5 to compare variations at lower cost; once the prompt is stable, switch to Imagine 2.0 with n=1 for the final render. This sequencing reserves the highest rate for selected images only.
Two mechanisms complete the setup on the application side. First, a result cache: if the same prompt returns—catalog visuals, standard images regenerated by multiple users—serve the already generated image instead of paying for a new request. Then quotas, if your users trigger generations themselves: a limit per day or hour protects your budget from unreasonable use and abuse. Finally, keep an eye on rate limits (300 RPM standard, 30 RPM pro): a batch pipeline that ignores them accumulates 429 errors and unnecessary retries.
Monthly budget estimation
For an app with 100 users generating 10 images per day:
- Imagine 1.0: 100 x 10 x 30 x $0.02 = $600/month
- Imagine 2.0 in
low: 100 x 10 x 30 x $0.04 = $1,200/month - Mixed (80/20): 24,000 x $0.02 + 6,000 x $0.04 = $720/month
Model discovery endpoint
To programmatically check available image models and their prices:
response = requests.get(
"https://api.x.ai/v1/image-generation-models",
headers={"Authorization": f"Bearer {os.getenv('XAI_API_KEY')}"}
)
for model in response.json()["data"]:
print(f"{model['id']} : ${model['image_price']}/image, "
f"max prompt : {model['max_prompt_length']} chars")
Rates as of August 5, 2026 — prices change regularly: before any budget calculation, check the current grid on the official xAI models and rates page.
Key points to remember
- Moderation is automatic: handle refusals in your code
- OpenAI SDK
images.edit()is incompatible with xAI: userequests - OpenAI SDK
images.generate()works normally - Implement a budget tracker to control spending
- Check models and prices via the
/v1/image-generation-modelsendpoint
Test your knowledge
Image generation and editing: the operational overview.
1. What differentiates Imagine 1.0 and Imagine 2.0?
Answer: The quality/cost trade-off: Imagine 1.0 ($0.02) for volume and iterations, Imagine 2.0 ($0.04 in low, with a quality setting) for final renders—you prototype with the first, finalize with the second.
2. What makes a good image prompt?
Answer: Subject, style, composition, and explicit details—describe the scene like an art direction brief, then iterate with targeted tweaks rather than rewriting.
3. What does the /v1/images/edits endpoint allow?
Answer: Edit existing images: prompt-targeted editing, multi-image editing with references, and multi-turn editing—you retouch precisely instead of regenerating.
4. How to produce in volume efficiently?
Answer: The n parameter for batches, the async client for throughput—and since output URLs are temporary, download and archive immediately.
5. What safeguards before production?
Answer: Moderation of prompts and outputs, knowledge of SDK incompatibilities, and cost control (model, resolution, volumes)—creation at scale requires governance.
Prototype, edit, industrialize, govern: the complete image pipeline—with costs under control at every step.