67 }'67 }'
68```68```
69 69
70```pythonXAI
71from xai_sdk import Client
72
73client = Client()
74
75# Create a batch with a descriptive name
76batch = client.batch.create(batch_name="customer_feedback_analysis")
77print(f"Created batch: {batch.batch_id}")
78
79# Store the batch_id for later use
80batch_id = batch.batch_id
81```
82
83```javascriptWithoutSDK70```javascriptWithoutSDK
84// Create a batch with a descriptive name71// Create a batch with a descriptive name
85const response = await fetch("https://api.x.ai/v1/batches", {72const response = await fetch("https://api.x.ai/v1/batches", {
97const batchId = batch.batch_id;84const batchId = batch.batch_id;
98```85```
99 86
100## Step 2: Add requests to the batch
101
102With your batch created, you can now add requests to it. Each request will be processed asynchronously.
103
104**With the xAI SDK, adding batch requests is simple:** use `chat.create()` for text, `image.prepare()` for images, `video.prepare()` for videos, or `video.prepare_extension()` for video extensions, then pass them as a list. You can also upload a [JSONL file](#jsonl-file-upload) if you prefer.
105
106**Important:** Assign a unique `batch_request_id` to each request. This ID lets you match results back to their original requests, which becomes important when you're processing hundreds or thousands of items. If you don't provide an ID, we generate a UUID for you. Using your own IDs is useful for idempotency (ensuring a request is only processed once) and for linking batch requests to records in your own system.
107
108```pythonXAI87```pythonXAI
109from xai_sdk import Client88from xai_sdk import Client
110from xai_sdk.chat import system, user
111from xai_sdk.tools import web_search, x_search, mcp
112 89
113client = Client()90client = Client()
114 91
115batch_requests = []92# Create a batch with a descriptive name
116 93batch = client.batch.create(batch_name="customer_feedback_analysis")
117# Chat completion with tools94print(f"Created batch: {batch.batch_id}")
118chat = client.chat.create(
119 model="grok-4.3",
120 batch_request_id="chat_001",
121 tools=[web_search(), x_search()],
122)
123chat.append(system("Analyze market sentiment from recent news and posts."))
124chat.append(user("What is the current sentiment around TSLA stock?"))
125batch_requests.append(chat)
126
127# Image generation
128image_req = client.image.prepare(
129 prompt="A sleek modern laptop on a minimalist desk",
130 model="grok-imagine-image-2.0",
131 batch_request_id="img_001",
132)
133batch_requests.append(image_req)
134
135# Image edit
136image_edit_req = client.image.prepare(
137 prompt="Add a rainbow in the background",
138 model="grok-imagine-image-2.0",
139 image_url="https://picsum.photos/800",
140 batch_request_id="img_edit_001",
141)
142batch_requests.append(image_edit_req)
143 95
144# Video generation96# Store the batch_id for later use
145video_req = client.video.prepare(97batch_id = batch.batch_id
146 prompt="A product rotating on a turntable with dramatic lighting",98```
147 model="grok-imagine-video-1.5",
148 batch_request_id="vid_001",
149)
150batch_requests.append(video_req)
151 99
152# Video edit100## Step 2: Add requests to the batch
153video_edit_req = client.video.prepare(
154 prompt="Make it slow motion",
155 model="grok-imagine-video",
156 video_url="https://lorem.video/cat_360p_3s",
157 batch_request_id="vid_edit_001",
158)
159batch_requests.append(video_edit_req)
160 101
161# Video extension102With your batch created, you can now add requests to it. Each request will be processed asynchronously.
162video_ext_req = client.video.prepare_extension(
163 prompt="The camera slowly pans to reveal a sunset behind the mountains",
164 model="grok-imagine-video",
165 video_url="https://lorem.video/cat_360p_3s",
166 duration=6,
167 batch_request_id="vid_ext_001",
168)
169batch_requests.append(video_ext_req)
170 103
171# Remote MCP104**With the xAI SDK, adding batch requests is simple:** use `chat.create()` for text, `image.prepare()` for images, `video.prepare()` for videos, or `video.prepare_extension()` for video extensions, then pass them as a list. You can also upload a [JSONL file](#jsonl-file-upload) if you prefer.
172mcp_chat = client.chat.create(
173 model="grok-4.3",
174 batch_request_id="mcp_001",
175 tools=[mcp(server_url="https://mcp.deepwiki.com/mcp")],
176)
177mcp_chat.append(user("What does the xai-sdk-python repo do?"))
178batch_requests.append(mcp_chat)
179 105
180# Add all requests to the batch106**Important:** Assign a unique `batch_request_id` to each request. This ID lets you match results back to their original requests, which becomes important when you're processing hundreds or thousands of items. If you don't provide an ID, we generate a UUID for you. Using your own IDs is useful for idempotency (ensuring a request is only processed once) and for linking batch requests to records in your own system.
181client.batch.add(batch_id=batch.batch_id, batch_requests=batch_requests)
182print(f"Added {len(batch_requests)} requests to batch")
183```
184 107
185```bash108```bash
186curl -X POST https://api.x.ai/v1/batches/{batch_id}/requests \\109curl -X POST https://api.x.ai/v1/batches/{batch_id}/requests \\
318console.log(\`Added \${batchRequests.length} requests to batch\`);241console.log(\`Added \${batchRequests.length} requests to batch\`);
319```242```
320 243
244```pythonXAI
245from xai_sdk import Client
246from xai_sdk.chat import system, user
247from xai_sdk.tools import web_search, x_search, mcp
248
249client = Client()
250
251batch_requests = []
252
253# Chat completion with tools
254chat = client.chat.create(
255 model="grok-4.3",
256 batch_request_id="chat_001",
257 tools=[web_search(), x_search()],
258)
259chat.append(system("Analyze market sentiment from recent news and posts."))
260chat.append(user("What is the current sentiment around TSLA stock?"))
261batch_requests.append(chat)
262
263# Image generation
264image_req = client.image.prepare(
265 prompt="A sleek modern laptop on a minimalist desk",
266 model="grok-imagine-image-2.0",
267 batch_request_id="img_001",
268)
269batch_requests.append(image_req)
270
271# Image edit
272image_edit_req = client.image.prepare(
273 prompt="Add a rainbow in the background",
274 model="grok-imagine-image-2.0",
275 image_url="https://picsum.photos/800",
276 batch_request_id="img_edit_001",
277)
278batch_requests.append(image_edit_req)
279
280# Video generation
281video_req = client.video.prepare(
282 prompt="A product rotating on a turntable with dramatic lighting",
283 model="grok-imagine-video-1.5",
284 batch_request_id="vid_001",
285)
286batch_requests.append(video_req)
287
288# Video edit
289video_edit_req = client.video.prepare(
290 prompt="Make it slow motion",
291 model="grok-imagine-video",
292 video_url="https://lorem.video/cat_360p_3s",
293 batch_request_id="vid_edit_001",
294)
295batch_requests.append(video_edit_req)
296
297# Video extension
298video_ext_req = client.video.prepare_extension(
299 prompt="The camera slowly pans to reveal a sunset behind the mountains",
300 model="grok-imagine-video",
301 video_url="https://lorem.video/cat_360p_3s",
302 duration=6,
303 batch_request_id="vid_ext_001",
304)
305batch_requests.append(video_ext_req)
306
307# Remote MCP
308mcp_chat = client.chat.create(
309 model="grok-4.3",
310 batch_request_id="mcp_001",
311 tools=[mcp(server_url="https://mcp.deepwiki.com/mcp")],
312)
313mcp_chat.append(user("What does the xai-sdk-python repo do?"))
314batch_requests.append(mcp_chat)
315
316# Add all requests to the batch
317client.batch.add(batch_id=batch.batch_id, batch_requests=batch_requests)
318print(f"Added {len(batch_requests)} requests to batch")
319```
320
321## Step 3: Monitor batch progress321## Step 3: Monitor batch progress
322 322
323After adding requests, they begin processing in the background. Since batch processing is asynchronous, you need to poll the batch status to know when results are ready.323After adding requests, they begin processing in the background. Since batch processing is asynchronous, you need to poll the batch status to know when results are ready.
340# }340# }
341```341```
342 342
343```javascriptWithoutSDK
344// Poll until all requests are processed
345console.log("Waiting for batch to complete...");
346const interval = setInterval(async () => {
347 const response = await fetch(
348 \`https://api.x.ai/v1/batches/\${batchId}\`,
349 { headers: { Authorization: \`Bearer \${process.env.XAI_API_KEY}\` } }
350 );
351 const batch = await response.json();
352
353 const { num_pending, num_success, num_error, num_requests } = batch.state;
354 const completed = num_success + num_error;
355 console.log(\`Progress: \${completed}/\${num_requests} complete, \${num_pending} pending\`);
356
357 if (num_requests > 0 && num_pending === 0) {
358 clearInterval(interval);
359 console.log("Batch processing complete!");
360 }
361 // Wait before polling again (avoid hammering the API)
362}, 5000);
363```
364
343```pythonXAI365```pythonXAI
344import time366import time
345from xai_sdk import Client367from xai_sdk import Client
365 time.sleep(5)387 time.sleep(5)
366```388```
367 389
368```javascriptWithoutSDK
369// Poll until all requests are processed
370console.log("Waiting for batch to complete...");
371const interval = setInterval(async () => {
372 const response = await fetch(
373 \`https://api.x.ai/v1/batches/\${batchId}\`,
374 { headers: { Authorization: \`Bearer \${process.env.XAI_API_KEY}\` } }
375 );
376 const batch = await response.json();
377
378 const { num_pending, num_success, num_error, num_requests } = batch.state;
379 const completed = num_success + num_error;
380 console.log(\`Progress: \${completed}/\${num_requests} complete, \${num_pending} pending\`);
381
382 if (num_requests > 0 && num_pending === 0) {
383 clearInterval(interval);
384 console.log("Batch processing complete!");
385 }
386 // Wait before polling again (avoid hammering the API)
387}, 5000);
388```
389
390### Understanding batch states390### Understanding batch states
391 391
392The Batch API tracks state at two levels: the **batch level** and the **individual request level**.392The Batch API tracks state at two levels: the **batch level** and the **individual request level**.
425 425
426**Pagination:** Results are returned in pages. Use the `limit` parameter to control page size and `pagination_token` to fetch subsequent pages. When `pagination_token` is `None`, you've reached the end.426**Pagination:** Results are returned in pages. Use the `limit` parameter to control page size and `pagination_token` to fetch subsequent pages. When `pagination_token` is `None`, you've reached the end.
427 427
428```pythonXAI
429from xai_sdk import Client
430
431client = Client()
432
433# Paginate through all results
434all_succeeded = []
435all_failed = []
436pagination_token = None
437
438while True:
439 # Fetch a page of results (limit controls page size)
440 page = client.batch.list_batch_results(
441 batch_id=batch.batch_id,
442 limit=100,
443 pagination_token=pagination_token,
444 )
445
446 # Collect results from this page
447 all_succeeded.extend(page.succeeded)
448 all_failed.extend(page.failed)
449
450 # Check if there are more pages
451 if page.pagination_token is None:
452 break
453 pagination_token = page.pagination_token
454
455# Process results - handle different response types
456print(f"Successfully processed: {len(all_succeeded)} requests")
457for result in all_succeeded:
458 rid = result.batch_request_id
459 resp = result.proto.response
460
461 if resp.HasField("completion_response"):
462 # Chat completion response
463 print(f"[{rid}] {result.response.content}")
464 print(f" Tokens used: {result.response.usage.total_tokens}")
465 elif resp.HasField("image_response"):
466 # Image generation response
467 print(f"[{rid}] Image URL: {result.image_response.url}")
468 elif resp.HasField("video_response"):
469 # Video generation response
470 print(f"[{rid}] Video URL: {result.video_response.url}")
471
472if all_failed:
473 print(f"\\nFailed: {len(all_failed)} requests")
474 for result in all_failed:
475 print(f"[{result.batch_request_id}] Error: {result.error_message}")
476```
477
478```bash428```bash
479# Fetch first page429# Fetch first page
480curl "https://api.x.ai/v1/batches/{batch_id}/results?limit=100" \\430curl "https://api.x.ai/v1/batches/{batch_id}/results?limit=100" \\
538}488}
539```489```
540 490
491```pythonXAI
492from xai_sdk import Client
493
494client = Client()
495
496# Paginate through all results
497all_succeeded = []
498all_failed = []
499pagination_token = None
500
501while True:
502 # Fetch a page of results (limit controls page size)
503 page = client.batch.list_batch_results(
504 batch_id=batch.batch_id,
505 limit=100,
506 pagination_token=pagination_token,
507 )
508
509 # Collect results from this page
510 all_succeeded.extend(page.succeeded)
511 all_failed.extend(page.failed)
512
513 # Check if there are more pages
514 if page.pagination_token is None:
515 break
516 pagination_token = page.pagination_token
517
518# Process results - handle different response types
519print(f"Successfully processed: {len(all_succeeded)} requests")
520for result in all_succeeded:
521 rid = result.batch_request_id
522 resp = result.proto.response
523
524 if resp.HasField("completion_response"):
525 # Chat completion response
526 print(f"[{rid}] {result.response.content}")
527 print(f" Tokens used: {result.response.usage.total_tokens}")
528 elif resp.HasField("image_response"):
529 # Image generation response
530 print(f"[{rid}] Image URL: {result.image_response.url}")
531 elif resp.HasField("video_response"):
532 # Video generation response
533 print(f"[{rid}] Video URL: {result.video_response.url}")
534
535if all_failed:
536 print(f"\\nFailed: {len(all_failed)} requests")
537 for result in all_failed:
538 print(f"[{result.batch_request_id}] Error: {result.error_message}")
539```
540
541## Additional operations541## Additional operations
542 542
543Beyond the core workflow, the Batch API provides additional operations for managing your batches.543Beyond the core workflow, the Batch API provides additional operations for managing your batches.
551 -H "Authorization: Bearer $XAI_API_KEY"551 -H "Authorization: Bearer $XAI_API_KEY"
552```552```
553 553
554```pythonXAI
555from xai_sdk import Client
556
557client = Client()
558
559# Cancel processing
560cancelled_batch = client.batch.cancel(batch_id=batch.batch_id)
561print(f"Cancelled batch: {cancelled_batch.batch_id}")
562print(f"Completed before cancellation: {cancelled_batch.state.num_success} requests")
563```
564
565```javascriptWithoutSDK554```javascriptWithoutSDK
566// Cancel processing555// Cancel processing
567const response = await fetch(556const response = await fetch(
573console.log(\`Completed before cancellation: \${cancelledBatch.state.num_success} requests\`);562console.log(\`Completed before cancellation: \${cancelledBatch.state.num_success} requests\`);
574```563```
575 564
565```pythonXAI
566from xai_sdk import Client
567
568client = Client()
569
570# Cancel processing
571cancelled_batch = client.batch.cancel(batch_id=batch.batch_id)
572print(f"Cancelled batch: {cancelled_batch.batch_id}")
573print(f"Completed before cancellation: {cancelled_batch.state.num_success} requests")
574```
575
576### List all batches576### List all batches
577 577
578View all batches belonging to your team. Batches are retained until they expire (check the `expires_at` field). This endpoint supports the same `limit` and `pagination_token` parameters for paginating through large lists.578View all batches belonging to your team. Batches are retained until they expire (check the `expires_at` field). This endpoint supports the same `limit` and `pagination_token` parameters for paginating through large lists.
582 -H "Authorization: Bearer $XAI_API_KEY"582 -H "Authorization: Bearer $XAI_API_KEY"
583```583```
584 584
585```pythonXAI
586from xai_sdk import Client
587
588client = Client()
589
590# List recent batches
591response = client.batch.list(limit=20)
592
593for batch in response.batches:
594 status = "complete" if batch.state.num_pending == 0 else "processing"
595 print(f"{batch.name} ({batch.batch_id}): {status}")
596```
597
598```javascriptWithoutSDK585```javascriptWithoutSDK
599// List recent batches586// List recent batches
600const response = await fetch(587const response = await fetch(
609}596}
610```597```
611 598
599```pythonXAI
600from xai_sdk import Client
601
602client = Client()
603
604# List recent batches
605response = client.batch.list(limit=20)
606
607for batch in response.batches:
608 status = "complete" if batch.state.num_pending == 0 else "processing"
609 print(f"{batch.name} ({batch.batch_id}): {status}")
610```
611
612### Check individual request status612### Check individual request status
613 613
614For detailed tracking, you can inspect the metadata for each request in a batch. This shows the status, timing, and other details for individual requests. This endpoint supports the same `limit` and `pagination_token` parameters for paginating through large batches.614For detailed tracking, you can inspect the metadata for each request in a batch. This shows the status, timing, and other details for individual requests. This endpoint supports the same `limit` and `pagination_token` parameters for paginating through large batches.
618 -H "Authorization: Bearer $XAI_API_KEY"618 -H "Authorization: Bearer $XAI_API_KEY"
619```619```
620 620
621```pythonXAI
622from xai_sdk import Client
623
624client = Client()
625
626# Get metadata for individual requests
627metadata = client.batch.list_batch_requests(batch_id=batch.batch_id)
628
629for request in metadata.batch_request_metadata:
630 print(f"Request {request.batch_request_id}: {request.state}")
631```
632
633```javascriptWithoutSDK621```javascriptWithoutSDK
634// Get metadata for individual requests622// Get metadata for individual requests
635const response = await fetch(623const response = await fetch(
643}631}
644```632```
645 633
634```pythonXAI
635from xai_sdk import Client
636
637client = Client()
638
639# Get metadata for individual requests
640metadata = client.batch.list_batch_requests(batch_id=batch.batch_id)
641
642for request in metadata.batch_request_metadata:
643 print(f"Request {request.batch_request_id}: {request.state}")
644```
645
646### Track costs646### Track costs
647 647
648Each batch tracks the total processing cost. Access the cost breakdown after processing to understand your spending. For pricing details, see [Batch API Pricing on the Pricing page](/developers/pricing#batch-api-pricing).648Each batch tracks the total processing cost. Access the cost breakdown after processing to understand your spending. For pricing details, see [Batch API Pricing on the Pricing page](/developers/pricing#batch-api-pricing).
656# Cost is returned in ticks (1e-10 USD) for precision656# Cost is returned in ticks (1e-10 USD) for precision
657```657```
658 658
659```pythonXAI
660from xai_sdk import Client
661
662client = Client()
663
664# Get batch with cost information
665batch = client.batch.get(batch_id=batch.batch_id)
666
667# Cost is returned in ticks (1e-10 USD) for precision
668total_cost_usd = batch.cost_breakdown.total_cost_usd_ticks / 1e10
669print("Total cost: $%.4f" % total_cost_usd)
670```
671
672```javascriptWithoutSDK659```javascriptWithoutSDK
673// Get batch with cost information660// Get batch with cost information
674const response = await fetch(661const response = await fetch(
685console.log(\`Total cost: $\${(totalTicks / 1e10).toFixed(4)}\`);672console.log(\`Total cost: $\${(totalTicks / 1e10).toFixed(4)}\`);
686```673```
687 674
688## Complete example
689
690This end-to-end example demonstrates a realistic batch workflow: analyzing customer feedback at scale. It creates a batch, submits feedback items for sentiment analysis, waits for processing, and outputs the results. For simplicity, this example doesn't paginate results—see [Step 4](#step-4-retrieve-results) for pagination when processing larger batches.
691
692```pythonXAI675```pythonXAI
693import time
694from xai_sdk import Client676from xai_sdk import Client
695from xai_sdk.chat import system, user
696 677
697client = Client()678client = Client()
698 679
699# Sample dataset: customer feedback to analyze680# Get batch with cost information
700feedback_data = [681batch = client.batch.get(batch_id=batch.batch_id)
701 {"id": "fb_001", "text": "Absolutely love this product! Best purchase ever."},
702 {"id": "fb_002", "text": "Delivery was late and the packaging was damaged."},
703 {"id": "fb_003", "text": "Works fine, nothing special to report."},
704 {"id": "fb_004", "text": "Customer support was incredibly helpful!"},
705 {"id": "fb_005", "text": "The app keeps crashing on my phone."},
706]
707
708# Step 1: Create a batch
709print("Creating batch...")
710batch = client.batch.create(batch_name="feedback_sentiment_analysis")
711print(f"Batch created: {batch.batch_id}")
712
713# Step 2: Build and add requests
714print("\\nAdding requests...")
715batch_requests = []
716for item in feedback_data:
717 chat = client.chat.create(
718 model="grok-4.3",
719 batch_request_id=item["id"],
720 )
721 chat.append(system(
722 "Analyze the sentiment of the customer feedback. "
723 "Respond with exactly one word: positive, negative, or neutral."
724 ))
725 chat.append(user(item["text"]))
726 batch_requests.append(chat)
727
728client.batch.add(batch_id=batch.batch_id, batch_requests=batch_requests)
729print(f"Added {len(batch_requests)} requests")
730
731# Step 3: Wait for completion
732print("\\nProcessing...")
733while True:
734 batch = client.batch.get(batch_id=batch.batch_id)
735 pending = batch.state.num_pending
736 completed = batch.state.num_success + batch.state.num_error
737
738 print(f" {completed}/{batch.state.num_requests} complete")
739
740 if pending == 0:
741 break
742 time.sleep(2)
743
744# Step 4: Retrieve and display results
745print("\\n--- Results ---")
746results = client.batch.list_batch_results(batch_id=batch.batch_id)
747
748# Create a lookup for original feedback text
749feedback_lookup = {item["id"]: item["text"] for item in feedback_data}
750 682
751for result in results.succeeded:683# Cost is returned in ticks (1e-10 USD) for precision
752 original_text = feedback_lookup.get(result.batch_request_id, "")684total_cost_usd = batch.cost_breakdown.total_cost_usd_ticks / 1e10
753 sentiment = result.response.content.strip().lower()685print("Total cost: $%.4f" % total_cost_usd)
754 print(f"[{sentiment.upper()}] {original_text[:50]}...")686```
755 687
756# Report any failures688## Complete example
757if results.failed:
758 print("\\n--- Errors ---")
759 for result in results.failed:
760 print(f"[{result.batch_request_id}] {result.error_message}")
761 689
762# Display cost690This end-to-end example demonstrates a realistic batch workflow: analyzing customer feedback at scale. It creates a batch, submits feedback items for sentiment analysis, waits for processing, and outputs the results. For simplicity, this example doesn't paginate results—see [Step 4](#step-4-retrieve-results) for pagination when processing larger batches.
763cost_usd = batch.cost_breakdown.total_cost_usd_ticks / 1e10
764print("\\nTotal cost: $%.4f" % cost_usd)
765```
766 691
767```javascriptWithoutSDK692```javascriptWithoutSDK
768const BASE_URL = "https://api.x.ai/v1";693const BASE_URL = "https://api.x.ai/v1";
860}, 2000);785}, 2000);
861```786```
862 787
788```pythonXAI
789import time
790from xai_sdk import Client
791from xai_sdk.chat import system, user
792
793client = Client()
794
795# Sample dataset: customer feedback to analyze
796feedback_data = [
797 {"id": "fb_001", "text": "Absolutely love this product! Best purchase ever."},
798 {"id": "fb_002", "text": "Delivery was late and the packaging was damaged."},
799 {"id": "fb_003", "text": "Works fine, nothing special to report."},
800 {"id": "fb_004", "text": "Customer support was incredibly helpful!"},
801 {"id": "fb_005", "text": "The app keeps crashing on my phone."},
802]
803
804# Step 1: Create a batch
805print("Creating batch...")
806batch = client.batch.create(batch_name="feedback_sentiment_analysis")
807print(f"Batch created: {batch.batch_id}")
808
809# Step 2: Build and add requests
810print("\\nAdding requests...")
811batch_requests = []
812for item in feedback_data:
813 chat = client.chat.create(
814 model="grok-4.3",
815 batch_request_id=item["id"],
816 )
817 chat.append(system(
818 "Analyze the sentiment of the customer feedback. "
819 "Respond with exactly one word: positive, negative, or neutral."
820 ))
821 chat.append(user(item["text"]))
822 batch_requests.append(chat)
823
824client.batch.add(batch_id=batch.batch_id, batch_requests=batch_requests)
825print(f"Added {len(batch_requests)} requests")
826
827# Step 3: Wait for completion
828print("\\nProcessing...")
829while True:
830 batch = client.batch.get(batch_id=batch.batch_id)
831 pending = batch.state.num_pending
832 completed = batch.state.num_success + batch.state.num_error
833
834 print(f" {completed}/{batch.state.num_requests} complete")
835
836 if pending == 0:
837 break
838 time.sleep(2)
839
840# Step 4: Retrieve and display results
841print("\\n--- Results ---")
842results = client.batch.list_batch_results(batch_id=batch.batch_id)
843
844# Create a lookup for original feedback text
845feedback_lookup = {item["id"]: item["text"] for item in feedback_data}
846
847for result in results.succeeded:
848 original_text = feedback_lookup.get(result.batch_request_id, "")
849 sentiment = result.response.content.strip().lower()
850 print(f"[{sentiment.upper()}] {original_text[:50]}...")
851
852# Report any failures
853if results.failed:
854 print("\\n--- Errors ---")
855 for result in results.failed:
856 print(f"[{result.batch_request_id}] {result.error_message}")
857
858# Display cost
859cost_usd = batch.cost_breakdown.total_cost_usd_ticks / 1e10
860print("\\nTotal cost: $%.4f" % cost_usd)
861```
862
863## JSONL File Upload863## JSONL File Upload
864 864
865As an alternative to adding requests via the SDK, you can create batches by uploading a JSONL file. This is useful when generating requests from scripts, pipelines, or external tools.865As an alternative to adding requests via the SDK, you can create batches by uploading a JSONL file. This is useful when generating requests from scripts, pipelines, or external tools.
895 895
896Upload the file via the [Files API](/developers/files), then create a batch referencing it:896Upload the file via the [Files API](/developers/files), then create a batch referencing it:
897 897
898```pythonXAI
899from xai_sdk import Client
900
901client = Client()
902
903# Upload the JSONL file
904file = client.files.upload(
905 file=open("batch_requests.jsonl", "rb"),
906)
907
908# Create a batch with the file ID
909batch = client.batch.create(
910 batch_name="sentiment_analysis",
911 input_file_id=file.id,
912)
913print(f"Created batch: {batch.batch_id}")
914```
915
916```bash898```bash
917# Upload the JSONL file899# Upload the JSONL file
918curl -X POST https://api.x.ai/v1/files \\900curl -X POST https://api.x.ai/v1/files \\
957console.log(\`Created batch: \${batch.batch_id}\`);939console.log(\`Created batch: \${batch.batch_id}\`);
958```940```
959 941
942```pythonXAI
943from xai_sdk import Client
944
945client = Client()
946
947# Upload the JSONL file
948file = client.files.upload(
949 file=open("batch_requests.jsonl", "rb"),
950)
951
952# Create a batch with the file ID
953batch = client.batch.create(
954 batch_name="sentiment_analysis",
955 input_file_id=file.id,
956)
957print(f"Created batch: {batch.batch_id}")
958```
959
960The file is processed asynchronously in the background. If any line is invalid, the batch is cancelled with an error message. Monitor progress and retrieve results the same way as inline batches.960The file is processed asynchronously in the background. If any line is invalid, the batch is cancelled with an error message. Monitor progress and retrieve results the same way as inline batches.
961 961
962File-based batches are sealed after creation — you cannot add more requests via `AddBatchRequests`. Maximum file size is **200 MB** with up to **50,000** requests. Each `custom_id` must be unique within the file.962File-based batches are sealed after creation — you cannot add more requests via `AddBatchRequests`. Maximum file size is **200 MB** with up to **50,000** requests. Each `custom_id` must be unique within the file.
985## Related985## Related
986 986
987* [API Reference: Batch endpoints](/developers/rest-api-reference/inference/batches#create-a-new-batch)987* [API Reference: Batch endpoints](/developers/rest-api-reference/inference/batches#create-a-new-batch)
988* [gRPC Reference: Batch Management](/developers/grpc-api-reference/batches)
989* [Pricing — Batch API Pricing](/developers/pricing#batch-api-pricing)988* [Pricing — Batch API Pricing](/developers/pricing#batch-api-pricing)
990* [xAI Python SDK](https://github.com/xai-org/xai-sdk-python)989* [xAI Python SDK](https://github.com/xai-org/xai-sdk-python)