1#### Tools
2
3# Image Generation Tool
4
5The image generation tool lets Grok create and edit images with [Grok Imagine](/developers/model-capabilities/images/generation) as part of a conversation. It uses the latest Imagine image models (`grok-imagine-image-quality`). You hand the model the tool; it decides when to call it, writes the image prompt, picks an aspect ratio, and returns the finished image alongside its text response. Because the tool runs server-side, the model can also chain calls—generating an image and then editing it—within a single request.
6
7If you already have the exact prompt and want direct control over aspect ratio and resolution, call the [image generation](/developers/model-capabilities/images/generation) and [image editing](/developers/model-capabilities/images/editing) endpoints instead. Reach for the tool when image creation is one step in a larger conversational or agentic workflow.
8
9## SDK support
10
11| SDK/API | Tool Name |
12|---------|-----------|
13| OpenAI Responses API | `image_generation` |
14
15This tool is also supported in all Responses API compatible SDKs. The Vercel AI SDK does not yet expose the image generation tool.
16
17## Basic usage
18
19Add `image_generation` to `tools` and ask for an image. In the Responses API, each image arrives as an `image_generation_call` output item whose `result` field carries the base64-encoded image with no data-URL prefix, so you can decode it directly.
20
21```bash customLanguage="bash"
22curl https://api.x.ai/v1/responses \
23 -H "Content-Type: application/json" \
24 -H "Authorization: Bearer $XAI_API_KEY" \
25 -d '{
26 "model": "grok-4.5",
27 "input": "Generate an image of a corgi surfing a big wave, in the style of a Japanese woodblock print",
28 "tools": [
29 {
30 "type": "image_generation"
31 }
32 ]
33}' | jq -r '.output[] | select(.type == "image_generation_call") | .result' \
34 | base64 --decode > corgi_surfing.jpg
35```
36
37```python customLanguage="pythonOpenAISDK"
38import base64
39import os
40
41from openai import OpenAI
42
43client = OpenAI(
44 api_key=os.getenv("XAI_API_KEY"),
45 base_url="https://api.x.ai/v1",
46)
47
48response = client.responses.create(
49 model="grok-4.5",
50 input="Generate an image of a corgi surfing a big wave, in the style of a Japanese woodblock print",
51 tools=[{"type": "image_generation"}],
52)
53
54image_data = [
55 output.result
56 for output in response.output
57 if output.type == "image_generation_call"
58]
59
60if image_data:
61 with open("corgi_surfing.jpg", "wb") as f:
62 f.write(base64.b64decode(image_data[0]))
63```
64
65```python customLanguage="pythonRequests"
66import base64
67import os
68
69import requests
70
71url = "https://api.x.ai/v1/responses"
72headers = {
73 "Content-Type": "application/json",
74 "Authorization": f"Bearer {os.getenv('XAI_API_KEY')}",
75}
76payload = {
77 "model": "grok-4.5",
78 "input": "Generate an image of a corgi surfing a big wave, in the style of a Japanese woodblock print",
79 "tools": [{"type": "image_generation"}],
80}
81response = requests.post(url, headers=headers, json=payload)
82data = response.json()
83
84for item in data["output"]:
85 if item["type"] == "image_generation_call":
86 with open("corgi_surfing.jpg", "wb") as f:
87 f.write(base64.b64decode(item["result"]))
88```
89
90```javascript customLanguage="javascriptOpenAISDK"
91import fs from "fs";
92import OpenAI from "openai";
93
94const client = new OpenAI({
95 apiKey: process.env.XAI_API_KEY,
96 baseURL: "https://api.x.ai/v1",
97});
98
99const response = await client.responses.create({
100 model: "grok-4.5",
101 input:
102 "Generate an image of a corgi surfing a big wave, in the style of a Japanese woodblock print",
103 tools: [{ type: "image_generation" }],
104});
105
106const imageData = response.output
107 .filter((output) => output.type === "image_generation_call")
108 .map((output) => output.result);
109
110if (imageData.length > 0) {
111 fs.writeFileSync("corgi_surfing.jpg", Buffer.from(imageData[0], "base64"));
112}
113```
114
115A completed `image_generation_call` output item looks like this:
116
117```json
118{
119 "type": "image_generation_call",
120 "id": "ig_d817cfd0-4f39-9cb3-bda2-44e538841ef2_call-a1b4dd05",
121 "status": "completed",
122 "prompt": "A corgi surfing a big wave, Japanese woodblock print style",
123 "result": "/9j/4AAQSkZJRgABAQAAAQABAAD..."
124}
125```
126
127The `prompt` field shows the prompt the model wrote for the image model, useful for understanding and debugging what was generated. Item IDs are prefixed `ig_` for generations and `ie_` for edits.
128
129The tool takes no size or format parameters; the model picks an aspect ratio for each call. To control it, ask in your request ("in a 9:16 vertical aspect ratio") and the generated image will match.
130
131## The action parameter
132
133By default the model can both generate new images and edit existing ones. The optional `action` parameter restricts this:
134
135| Action | Behavior |
136|--------|----------|
137| `auto` | Default. The model can generate and edit images |
138| `generate` | Text-to-image generation only |
139| `edit` | Image editing only |
140
141For example, to let the model create images but never modify ones already in the conversation:
142
143```bash customLanguage="bash"
144curl https://api.x.ai/v1/responses \
145 -H "Content-Type: application/json" \
146 -H "Authorization: Bearer $XAI_API_KEY" \
147 -d '{
148 "model": "grok-4.5",
149 "input": "Generate an image of a hot air balloon over the desert",
150 "tools": [
151 {
152 "type": "image_generation",
153 "action": "generate"
154 }
155 ]
156}'
157```
158
159```python customLanguage="pythonOpenAISDK"
160response = client.responses.create(
161 model="grok-4.5",
162 input="Generate an image of a hot air balloon over the desert",
163 tools=[{"type": "image_generation", "action": "generate"}],
164)
165```
166
167## Editing input images
168
169With `action` set to `edit` (or the default `auto`), the model can edit any image already in the conversation: images you attach as input as well as images it generated earlier. Edits produce `image_generation_call` items with an `ie_` ID prefix.
170
171```bash customLanguage="bash"
172curl https://api.x.ai/v1/responses \
173 -H "Content-Type: application/json" \
174 -H "Authorization: Bearer $XAI_API_KEY" \
175 -d '{
176 "model": "grok-4.5",
177 "input": [
178 {
179 "role": "user",
180 "content": [
181 {
182 "type": "input_text",
183 "text": "Edit this image so it looks like a watercolor painting."
184 },
185 {
186 "type": "input_image",
187 "image_url": "https://docs.x.ai/assets/api-examples/images/style-realistic.png"
188 }
189 ]
190 }
191 ],
192 "tools": [
193 {
194 "type": "image_generation",
195 "action": "edit"
196 }
197 ]
198}'
199```
200
201```python customLanguage="pythonOpenAISDK"
202import base64
203import os
204
205from openai import OpenAI
206
207client = OpenAI(
208 api_key=os.getenv("XAI_API_KEY"),
209 base_url="https://api.x.ai/v1",
210)
211
212response = client.responses.create(
213 model="grok-4.5",
214 input=[
215 {
216 "role": "user",
217 "content": [
218 {
219 "type": "input_text",
220 "text": "Edit this image so it looks like a watercolor painting.",
221 },
222 {
223 "type": "input_image",
224 "image_url": "https://docs.x.ai/assets/api-examples/images/style-realistic.png",
225 },
226 ],
227 }
228 ],
229 tools=[{"type": "image_generation", "action": "edit"}],
230)
231
232image_data = [
233 output.result
234 for output in response.output
235 if output.type == "image_generation_call"
236]
237
238if image_data:
239 with open("watercolor.jpg", "wb") as f:
240 f.write(base64.b64decode(image_data[0]))
241```
242
243## Multi-turn editing
244
245Images generated on a previous turn stay editable on follow-up turns. Continue the conversation with `previous_response_id`, and the model can refine its earlier images by reference:
246
247```python customLanguage="pythonOpenAISDK"
248import base64
249import os
250
251from openai import OpenAI
252
253client = OpenAI(
254 api_key=os.getenv("XAI_API_KEY"),
255 base_url="https://api.x.ai/v1",
256)
257
258response = client.responses.create(
259 model="grok-4.5",
260 input="Generate an image of a lighthouse on a rocky coast",
261 tools=[{"type": "image_generation"}],
262)
263
264image_data = [
265 output.result
266 for output in response.output
267 if output.type == "image_generation_call"
268]
269
270if image_data:
271 with open("lighthouse.jpg", "wb") as f:
272 f.write(base64.b64decode(image_data[0]))
273
274# Follow up: edit the image from the previous turn
275followup = client.responses.create(
276 model="grok-4.5",
277 previous_response_id=response.id,
278 input="Make it night time with a full moon",
279 tools=[{"type": "image_generation"}],
280)
281
282image_data_followup = [
283 output.result
284 for output in followup.output
285 if output.type == "image_generation_call"
286]
287
288if image_data_followup:
289 with open("lighthouse_night.jpg", "wb") as f:
290 f.write(base64.b64decode(image_data_followup[0]))
291```
292
293If you manage conversation state yourself instead of using `previous_response_id`, pass the previous turn's output items (including the `image_generation_call` items) back verbatim in `input`; the images they carry remain editable on the next request.
294
295## Combining with other tools
296
297The image generation tool composes with the other server-side tools. Include several tools in the same request and the model orchestrates them within a single agentic loop, feeding what one tool found into the next. Here it looks up a fact with [web search](/developers/tools/web-search) first, then writes an image prompt from what it learned:
298
299```bash customLanguage="bash"
300curl https://api.x.ai/v1/responses \
301 -H "Content-Type: application/json" \
302 -H "Authorization: Bearer $XAI_API_KEY" \
303 -d '{
304 "model": "grok-4.5",
305 "input": "Find out which team won the most recent FIFA World Cup, then generate an image of a celebratory poster for that team, in a vintage travel-poster style.",
306 "tools": [
307 {
308 "type": "web_search"
309 },
310 {
311 "type": "image_generation"
312 }
313 ]
314}' | jq -r '.output[] | select(.type == "image_generation_call") | .result' \
315 | base64 --decode > champions_poster.jpg
316```
317
318```python customLanguage="pythonOpenAISDK"
319import base64
320import os
321
322from openai import OpenAI
323
324client = OpenAI(
325 api_key=os.getenv("XAI_API_KEY"),
326 base_url="https://api.x.ai/v1",
327)
328
329response = client.responses.create(
330 model="grok-4.5",
331 input=(
332 "Find out which team won the most recent FIFA World Cup, then generate an "
333 "image of a celebratory poster for that team, in a vintage travel-poster style."
334 ),
335 tools=[
336 {"type": "web_search"},
337 {"type": "image_generation"},
338 ],
339)
340
341for output in response.output:
342 if output.type == "web_search_call":
343 print(f"Web search: {output.action}")
344 elif output.type == "image_generation_call":
345 print(f"Image prompt: {output.prompt}")
346 with open("champions_poster.jpg", "wb") as f:
347 f.write(base64.b64decode(output.result))
348 elif output.type == "message":
349 print(output.content[0].text)
350```
351
352The response output interleaves the tool calls in the order they ran: a `web_search_call` item, a message answering the factual question with citations, and an `image_generation_call` item carrying the poster.
353
354The same pattern works with [X search](/developers/tools/x-search), [code execution](/developers/tools/code-execution), and your own client-side functions. See [Advanced Usage](/developers/tools/advanced-usage#tool-combinations) for more tool combination patterns.
355
356## Streaming
357
358When streaming, each image generation call emits progress events—`in_progress`, then `generating`, then `completed`—followed by a `response.output_item.done` event whose item carries the base64 result. Partial image previews are not emitted.
359
360```python customLanguage="pythonOpenAISDK"
361import base64
362import os
363
364from openai import OpenAI
365
366client = OpenAI(
367 api_key=os.getenv("XAI_API_KEY"),
368 base_url="https://api.x.ai/v1",
369)
370
371stream = client.responses.create(
372 model="grok-4.5",
373 input="Generate an image of an origami fox in a paper forest",
374 tools=[{"type": "image_generation"}],
375 stream=True,
376)
377
378for event in stream:
379 if event.type.startswith("response.image_generation_call."):
380 # in_progress -> generating -> completed
381 print(f"Image generation status: {event.type.rsplit('.', 1)[-1]}")
382 elif event.type == "response.output_item.done" and event.item.type == "image_generation_call":
383 # The base64 image rides on the final output item
384 with open("origami_fox.jpg", "wb") as f:
385 f.write(base64.b64decode(event.item.result))
386 elif event.type == "response.output_text.delta":
387 print(event.delta, end="", flush=True)
388```
389
390```javascript customLanguage="javascriptOpenAISDK"
391import fs from "fs";
392import OpenAI from "openai";
393
394const client = new OpenAI({
395 apiKey: process.env.XAI_API_KEY,
396 baseURL: "https://api.x.ai/v1",
397});
398
399const stream = await client.responses.create({
400 model: "grok-4.5",
401 input: "Generate an image of an origami fox in a paper forest",
402 tools: [{ type: "image_generation" }],
403 stream: true,
404});
405
406for await (const event of stream) {
407 if (event.type.startsWith("response.image_generation_call.")) {
408 // in_progress -> generating -> completed
409 console.log(`Image generation status: ${event.type.split(".").pop()}`);
410 } else if (
411 event.type === "response.output_item.done" &&
412 event.item.type === "image_generation_call"
413 ) {
414 // The base64 image rides on the final output item
415 fs.writeFileSync(
416 "origami_fox.jpg",
417 Buffer.from(event.item.result, "base64")
418 );
419 } else if (event.type === "response.output_text.delta") {
420 process.stdout.write(event.delta);
421 }
422}
423```
424
425## Related
426
427* [Image Generation](/developers/model-capabilities/images/generation) — Generate images directly with the images endpoint
428* [Image Editing](/developers/model-capabilities/images/editing) — Edit images with natural language
429* [Tools Overview](/developers/tools/overview) — All built-in tools
430* [Streaming & Sync](/developers/tools/streaming-and-sync) — Streaming behavior of tool-enabled requests
431* [Pricing](/developers/pricing#tools-pricing) — Tool invocation costs