Repository Public
1> [!NOTE]2> **Note:** This feature is currently only available with the generateContent API. Please follow the content on this page for more information.34The Gemini Batch API is designed to process large volumes of requests5asynchronously at [50% of the standard cost](https://ai.google.dev/gemini-api/docs/pricing).6The target turnaround time is 24 hours, but in majority of cases, it is much7quicker.89Use Batch API for large-scale, non-urgent tasks such as data10pre-processing or running evaluations where an immediate response is not11required.1213## Creating a batch job1415You have two ways to submit your requests in Batch API:1617- **[Inline requests](https://ai.google.dev/gemini-api/docs/batch-api#inline-requests):** A list of [`GenerateContentRequest`](https://ai.google.dev/api/batch-mode#GenerateContentRequest) objects directly included in your batch creation request. This is suitable for smaller batches that keep the total request size under 20MB. The **output** returned from the model is a list of `inlineResponse` objects.18- **[Input file](https://ai.google.dev/gemini-api/docs/batch-api#input-file):** A [JSON Lines (JSONL)](https://jsonlines.org/) file where each line contains a complete [`GenerateContentRequest`](https://ai.google.dev/api/batch-mode#GenerateContentRequest) object. This method is recommended for larger requests. The **output** returned from the model is a JSONL file where each line is either a `GenerateContentResponse` or a status object.1920### Inline requests2122For a small number of requests, you can directly embed the23[`GenerateContentRequest`](https://ai.google.dev/api/batch-mode#GenerateContentRequest) objects24within your [`BatchGenerateContentRequest`](https://ai.google.dev/api/batch-mode#request-body). The25following example calls the26[`BatchGenerateContent`](https://ai.google.dev/api/batch-mode#google.ai.generativelanguage.v1beta.BatchService.BatchGenerateContent)27method with inline requests:2829### Python303132 from google import genai33 from google.genai import types3435 client = genai.Client()3637 # A list of dictionaries, where each is a GenerateContentRequest38 inline_requests = [39 {40 'contents': [{41 'parts': [{'text': 'Tell me a one-sentence joke.'}],42 'role': 'user'43 }]44 },45 {46 'contents': [{47 'parts': [{'text': 'Why is the sky blue?'}],48 'role': 'user'49 }]50 }51 ]5253 inline_batch_job = client.batches.create(54 model="gemini-3.8-flash",55 src=inline_requests,56 config={57 'display_name': "inlined-requests-job-1",58 },59 )6061 print(f"Created batch job: {inline_batch_job.name}")6263### JavaScript646566 import {GoogleGenAI} from '@google/genai';6768 const ai = new GoogleGenAI({});6970 const inlinedRequests = [71 {72 contents: [{73 parts: [{text: 'Tell me a one-sentence joke.'}],74 role: 'user'75 }]76 },77 {78 contents: [{79 parts: [{'text': 'Why is the sky blue?'}],80 role: 'user'81 }]82 }83 ]8485 const response = await ai.batches.create({86 model: 'gemini-3.8-flash',87 src: inlinedRequests,88 config: {89 displayName: 'inlined-requests-job-1',90 }91 });9293 console.log(response);9495### Java9697 import java.util.Arrays;98 import com.google.genai.Client;99 import com.google.genai.types.BatchJob;100 import com.google.genai.types.BatchJobSource;101 import com.google.genai.types.Content;102 import com.google.genai.types.CreateBatchJobConfig;103 import com.google.genai.types.InlinedRequest;104 import com.google.genai.types.Part;105 import java.util.List;106107 Client client = new Client();108109 // A list of InlinedRequest objects110 List<InlinedRequest> inlineRequests =111 Arrays.asList(112 InlinedRequest.builder()113 .contents(114 Arrays.asList(115 Content.builder()116 .role("user")117 .parts(Arrays.asList(Part.fromText("Tell me a one-sentence joke.")))118 .build()))119 .build(),120 InlinedRequest.builder()121 .contents(122 Arrays.asList(123 Content.builder()124 .role("user")125 .parts(Arrays.asList(Part.fromText("Why is the sky blue?")))126 .build()))127 .build());128129 BatchJobSource src = BatchJobSource.builder().inlinedRequests(inlineRequests).build();130 CreateBatchJobConfig config =131 CreateBatchJobConfig.builder().displayName("inlined-requests-job-1").build();132133 BatchJob inlineBatchJob = client.batches.create("gemini-3.8-flash", src, config);134135 System.out.println("Created batch job: " + inlineBatchJob.name().orElse(""));136137### REST138139 curl https://generativelanguage.googleapis.com/v1beta/models/gemini-3.8-flash:batchGenerateContent \140 -H "x-goog-api-key: $GEMINI_API_KEY" \141 -X POST \142 -H "Content-Type:application/json" \143 -d '{144 "batch": {145 "display_name": "my-batch-requests",146 "input_config": {147 "requests": {148 "requests": [149 {150 "request": {"contents": [{"parts": [{"text": "Describe the process of photosynthesis."}]}]},151 "metadata": {152 "key": "request-1"153 }154 },155 {156 "request": {"contents": [{"parts": [{"text": "Describe the process of photosynthesis."}]}]},157 "metadata": {158 "key": "request-2"159 }160 }161 ]162 }163 }164 }165 }'166167### Input file168169For larger sets of requests, prepare a JSON Lines (JSONL) file. Each line in170this file must be a JSON object containing a user-defined key and a request171object, where the request is a valid172[`GenerateContentRequest`](https://ai.google.dev/api/batch-mode#GenerateContentRequest) object. The173user-defined key is used in the response to indicate which output is the result174of which request. For example, the request with the key defined as `request-1`175will have its response annotated with the same key name.176177This file is uploaded using the [File API](https://ai.google.dev/gemini-api/docs/files). The maximum178allowed file size for an input file is 2GB.179180The following is an example of a JSONL file. You can save it in a file named181`my-batch-requests.json`:182183 {"key": "request-1", "request": {"contents": [{"parts": [{"text": "Describe the process of photosynthesis."}]}], "generation_config": {"temperature": 0.7}}}184 {"key": "request-2", "request": {"contents": [{"parts": [{"text": "What are the main ingredients in a Margherita pizza?"}]}]}}185186Similarly to inline requests, you can specify other parameters like system187instructions, tools or other configurations in each request JSON.188189You can upload this file using the [File API](https://ai.google.dev/gemini-api/docs/files) as190shown in the following example. If191you are working with multimodal input, you can reference other uploaded files192within your JSONL file.193194### Python195196197 import json198 from google import genai199 from google.genai import types200201 client = genai.Client()202203 # Create a sample JSONL file204 with open("my-batch-requests.jsonl", "w") as f:205 requests = [206 {"key": "request-1", "request": {"contents": [{"parts": [{"text": "Describe the process of photosynthesis."}]}]}},207 {"key": "request-2", "request": {"contents": [{"parts": [{"text": "What are the main ingredients in a Margherita pizza?"}]}]}}208 ]209 for req in requests:210 f.write(json.dumps(req) + "\n")211212 # Upload the file to the File API213 uploaded_file = client.files.upload(214 file='my-batch-requests.jsonl',215 config=types.UploadFileConfig(display_name='my-batch-requests', mime_type='jsonl')216 )217218 print(f"Uploaded file: {uploaded_file.name}")219220### JavaScript221222223 import {GoogleGenAI} from '@google/genai';224 import * as fs from "fs";225 import * as path from "path";226 import { fileURLToPath } from 'url';227228 const ai = new GoogleGenAI({});229 const fileName = "my-batch-requests.jsonl";230231 // Define the requests232 const requests = [233 { "key": "request-1", "request": { "contents": [{ "parts": [{ "text": "Describe the process of photosynthesis." }] }] } },234 { "key": "request-2", "request": { "contents": [{ "parts": [{ "text": "What are the main ingredients in a Margherita pizza?" }] }] } }235 ];236237 // Construct the full path to file238 const __filename = fileURLToPath(import.meta.url);239 const __dirname = path.dirname(__filename);240 const filePath = path.join(__dirname, fileName); // __dirname is the directory of the current script241242 async function writeBatchRequestsToFile(requests, filePath) {243 try {244 // Use a writable stream for efficiency, especially with larger files.245 const writeStream = fs.createWriteStream(filePath, { flags: 'w' });246247 writeStream.on('error', (err) => {248 console.error(`Error writing to file ${filePath}:`, err);249 });250251 for (const req of requests) {252 writeStream.write(JSON.stringify(req) + '\n');253 }254255 writeStream.end();256257 console.log(`Successfully wrote batch requests to ${filePath}`);258259 } catch (error) {260 // This catch block is for errors that might occur before stream setup,261 // stream errors are handled by the 'error' event.262 console.error(`An unexpected error occurred:`, error);263 }264 }265266 // Write to a file.267 writeBatchRequestsToFile(requests, filePath);268269 // Upload the file to the File API.270 const uploadedFile = await ai.files.upload({file: 'my-batch-requests.jsonl', config: {271 mimeType: 'jsonl',272 }});273 console.log(uploadedFile.name);274275### Java276277 import java.util.Arrays;278 import com.google.genai.Client;279 import com.google.genai.types.File;280 import com.google.genai.types.UploadFileConfig;281 import java.nio.file.Files;282 import java.nio.file.Paths;283 import java.util.List;284285 Client client = new Client();286287 // Create a sample JSONL file288 List<String> requests =289 Arrays.asList(290 "{\"key\": \"request-1\", \"request\": {\"contents\": [{\"parts\": [{\"text\": \"Describe the process of photosynthesis.\"}]}]}}",291 "{\"key\": \"request-2\", \"request\": {\"contents\": [{\"parts\": [{\"text\": \"What are the main ingredients in a Margherita pizza?\"}]}]}}");292 Files.write(Paths.get("my-batch-requests.jsonl"), requests);293294 // Upload the file to the File API295 UploadFileConfig uploadConfig =296 UploadFileConfig.builder()297 .displayName("my-batch-requests")298 .mimeType("jsonl")299 .build();300 File uploadedFile = client.files.upload("my-batch-requests.jsonl", uploadConfig);301302 System.out.println("Uploaded file: " + uploadedFile.name().orElse(""));303304### REST305306 tmp_batch_input_file=batch_input.tmp307 echo -e '{"contents": [{"parts": [{"text": "Describe the process of photosynthesis."}]}], "generationConfig": {"temperature": 0.7}}\n{"contents": [{"parts": [{"text": "What are the main ingredients in a Margherita pizza?"}]}]}' > batch_input.tmp308 MIME_TYPE=$(file -b --mime-type "${tmp_batch_input_file}")309 NUM_BYTES=$(wc -c < "${tmp_batch_input_file}")310 DISPLAY_NAME=BatchInput311312 tmp_header_file=upload-header.tmp313314 # Initial resumable request defining metadata.315 # The upload url is in the response headers dump them to a file.316 curl "https://generativelanguage.googleapis.com/upload/v1beta/files" \317 -D "${tmp_header_file}" \318 -H "x-goog-api-key: $GEMINI_API_KEY" \319 -H "X-Goog-Upload-Protocol: resumable" \320 -H "X-Goog-Upload-Command: start" \321 -H "X-Goog-Upload-Header-Content-Length: ${NUM_BYTES}" \322 -H "X-Goog-Upload-Header-Content-Type: ${MIME_TYPE}" \323 -H "Content-Type: application/jsonl" \324 -d "{'file': {'display_name': '${DISPLAY_NAME}'}}" 2> /dev/null325326 upload_url=$(grep -i "x-goog-upload-url: " "${tmp_header_file}" | cut -d" " -f2 | tr -d "\r")327 rm "${tmp_header_file}"328329 # Upload the actual bytes.330 curl "${upload_url}" \331 -H "Content-Length: ${NUM_BYTES}" \332 -H "X-Goog-Upload-Offset: 0" \333 -H "X-Goog-Upload-Command: upload, finalize" \334 --data-binary "@${tmp_batch_input_file}" 2> /dev/null > file_info.json335336 file_uri=$(jq ".file.uri" file_info.json)337338The following example calls the339[`BatchGenerateContent`](https://ai.google.dev/api/batch-mode#google.ai.generativelanguage.v1beta.BatchService.BatchGenerateContent)340method with the input file uploaded using File API:341342### Python343344 from google import genai345346 # Assumes `uploaded_file` is the file object from the previous step347 client = genai.Client()348 file_batch_job = client.batches.create(349 model="gemini-3.8-flash",350 src=uploaded_file.name,351 config={352 'display_name': "file-upload-job-1",353 },354 )355356 print(f"Created batch job: {file_batch_job.name}")357358### JavaScript359360 // Assumes `uploadedFile` is the file object from the previous step361 const fileBatchJob = await ai.batches.create({362 model: 'gemini-3.8-flash',363 src: uploadedFile.name,364 config: {365 displayName: 'file-upload-job-1',366 }367 });368369 console.log(fileBatchJob);370371### Java372373 import com.google.genai.Client;374 import com.google.genai.types.BatchJob;375 import com.google.genai.types.BatchJobSource;376 import com.google.genai.types.CreateBatchJobConfig;377378 Client client = new Client();379380 // Assumes `uploadedFileName` is the file name from the previous step381 String uploadedFileName = "files/my-batch-requests-id";382383 BatchJobSource src = BatchJobSource.builder().fileName(uploadedFileName).build();384 CreateBatchJobConfig config =385 CreateBatchJobConfig.builder().displayName("file-upload-job-1").build();386387 BatchJob fileBatchJob = client.batches.create("gemini-3.8-flash", src, config);388389 System.out.println("Created batch job: " + fileBatchJob.name().orElse(""));390391### REST392393 # Set the File ID taken from the upload response.394 BATCH_INPUT_FILE='files/123456'395 curl https://generativelanguage.googleapis.com/v1beta/models/gemini-3.8-flash:batchGenerateContent \396 -X POST \397 -H "x-goog-api-key: $GEMINI_API_KEY" \398 -H "Content-Type:application/json" \399 -d "{400 'batch': {401 'display_name': 'my-batch-requests',402 'input_config': {403 'file_name': '${BATCH_INPUT_FILE}'404 }405 }406 }"407408When you create a batch job, you will get a job name returned. Use this name409for [monitoring](https://ai.google.dev/gemini-api/docs/batch-api#batch-job-status) the job status as well as410[retrieving the results](https://ai.google.dev/gemini-api/docs/batch-api#retrieve-batch-results) once the job completes.411412The following is an example output that contains a job name:413414415 Created batch job from file: batches/123456789416417### Batch embedding support418419You can use the Batch API to interact with the420[Embeddings model](https://ai.google.dev/gemini-api/docs/embeddings) for higher throughput.421To create an embeddings batch job with either [inline requests](https://ai.google.dev/gemini-api/docs/batch-api#inline-requests)422or [input files](https://ai.google.dev/gemini-api/docs/batch-api#input-file), use the `batches.create_embeddings` API and423specify the embeddings model.424425### Python426427 from google import genai428429 client = genai.Client()430431 # Creating an embeddings batch job with an input file request:432 file_job = client.batches.create_embeddings(433 model="gemini-embedding-2",434 src={'file_name': uploaded_batch_requests.name},435 config={'display_name': "Input embeddings batch"},436 )437438 # Creating an embeddings batch job with an inline request:439 batch_job = client.batches.create_embeddings(440 model="gemini-embedding-2",441 # For a predefined list of requests `inlined_requests`442 src={'inlined_requests': inlined_requests},443 config={'display_name': "Inlined embeddings batch"},444 )445446### JavaScript447448 // Creating an embeddings batch job with an input file request:449 let fileJob;450 fileJob = await client.batches.createEmbeddings({451 model: 'gemini-embedding-2',452 src: {fileName: uploadedBatchRequests.name},453 config: {displayName: 'Input embeddings batch'},454 });455 console.log(`Created batch job: ${fileJob.name}`);456457 // Creating an embeddings batch job with an inline request:458 let batchJob;459 batchJob = await client.batches.createEmbeddings({460 model: 'gemini-embedding-2',461 // For a predefined a list of requests `inlinedRequests`462 src: {inlinedRequests: inlinedRequests},463 config: {displayName: 'Inlined embeddings batch'},464 });465 console.log(`Created batch job: ${batchJob.name}`);466467### Java468469 import java.util.Arrays;470 import com.google.genai.Client;471 import com.google.genai.types.BatchJob;472 import com.google.genai.types.Content;473 import com.google.genai.types.CreateEmbeddingsBatchJobConfig;474 import com.google.genai.types.EmbedContentBatch;475 import com.google.genai.types.EmbeddingsBatchJobSource;476 import com.google.genai.types.Part;477 import java.util.List;478479 Client client = new Client();480481 String uploadedFileName = "files/my-embedding-requests-id";482483 // Creating an embeddings batch job with an input file request:484 BatchJob fileJob =485 client.batches.createEmbeddings(486 "gemini-embedding-2",487 EmbeddingsBatchJobSource.builder().fileName(uploadedFileName).build(),488 CreateEmbeddingsBatchJobConfig.builder().displayName("Input embeddings batch").build());489 System.out.println("Created batch job: " + fileJob.name().orElse(""));490491 // Creating an embeddings batch job with an inline request:492 EmbedContentBatch inlinedRequests =493 EmbedContentBatch.builder()494 .contents(Arrays.asList(Content.fromParts(Part.fromText("What is the meaning of life?"))))495 .build();496 BatchJob batchJob =497 client.batches.createEmbeddings(498 "gemini-embedding-2",499 EmbeddingsBatchJobSource.builder().inlinedRequests(inlinedRequests).build(),500 CreateEmbeddingsBatchJobConfig.builder().displayName("Inlined embeddings batch").build());501 System.out.println("Created batch job: " + batchJob.name().orElse(""));502503Read the Embeddings section in the [Batch API cookbook](https://github.com/google-gemini/cookbook/blob/main/quickstarts/Batch_mode.ipynb)504for more examples.505506### Request configuration507508You can include any request configurations you would use in a standard non-batch509request. For example, you could specify the temperature, system instructions or510even pass in other modalities. The following example shows an example inline511request that contains a system instruction for one of the requests:512513### Python514515 inline_requests_list = [516 {'contents': [{'parts': [{'text': 'Write a short poem about a cloud.'}]}]},517 {'contents': [{518 'parts': [{519 'text': 'Write a short poem about a cat.'520 }]521 }],522 'config': {523 'system_instruction': {'parts': [{'text': 'You are a cat. Your name is Neko.'}]}}524 }525 ]526527### JavaScript528529 inlineRequestsList = [530 {contents: [{parts: [{text: 'Write a short poem about a cloud.'}]}]},531 {contents: [{parts: [{text: 'Write a short poem about a cat.'}]}],532 config: {systemInstruction: {parts: [{text: 'You are a cat. Your name is Neko.'}]}}}533 ]534535### Java536537 import java.util.Arrays;538 import com.google.genai.types.Content;539 import com.google.genai.types.GenerateContentConfig;540 import com.google.genai.types.InlinedRequest;541 import com.google.genai.types.Part;542 import java.util.List;543544 List<InlinedRequest> inlineRequestsList =545 Arrays.asList(546 InlinedRequest.builder()547 .contents(Arrays.asList(Content.fromParts(Part.fromText("Write a short poem about a cloud."))))548 .build(),549 InlinedRequest.builder()550 .contents(Arrays.asList(Content.fromParts(Part.fromText("Write a short poem about a cat."))))551 .config(552 GenerateContentConfig.builder()553 .systemInstruction(554 Content.fromParts(Part.fromText("You are a cat. Your name is Neko.")))555 .build())556 .build());557558Similarly can specify tools to use for a request. The following example559shows a request that enables the [Google Search tool](https://ai.google.dev/gemini-api/docs/google-search):560561### Python562563 inlined_requests = [564 {'contents': [{'parts': [{'text': 'Who won the euro 1998?'}]}]},565 {'contents': [{'parts': [{'text': 'Who won the euro 2025?'}]}],566 'config':{'tools': [{'google_search': {}}]}}]567568### JavaScript569570 inlineRequestsList = [571 {contents: [{parts: [{text: 'Who won the euro 1998?'}]}]},572 {contents: [{parts: [{text: 'Who won the euro 2025?'}]}],573 config: {tools: [{googleSearch: {}}]}}574 ]575576### Java577578 import java.util.Arrays;579 import com.google.genai.types.Content;580 import com.google.genai.types.GenerateContentConfig;581 import com.google.genai.types.GoogleSearch;582 import com.google.genai.types.InlinedRequest;583 import com.google.genai.types.Part;584 import com.google.genai.types.Tool;585 import java.util.List;586587 List<InlinedRequest> inlinedRequests =588 Arrays.asList(589 InlinedRequest.builder()590 .contents(Arrays.asList(Content.fromParts(Part.fromText("Who won the euro 1998?"))))591 .build(),592 InlinedRequest.builder()593 .contents(Arrays.asList(Content.fromParts(Part.fromText("Who won the euro 2025?"))))594 .config(595 GenerateContentConfig.builder()596 .tools(Tool.builder().googleSearch(GoogleSearch.builder().build()).build())597 .build())598 .build());599600You can specify [structured output](https://ai.google.dev/gemini-api/docs/structured-output) as well.601The following example shows how to specify for your batch requests.602603### Python604605 import time606 from google import genai607 from pydantic import BaseModel, TypeAdapter608609 class Recipe(BaseModel):610 recipe_name: str611 ingredients: list[str]612613 client = genai.Client()614615 # A list of dictionaries, where each is a GenerateContentRequest616 inline_requests = [617 {618 'contents': [{619 'parts': [{'text': 'List a few popular cookie recipes, and include the amounts of ingredients.'}],620 'role': 'user'621 }],622 'config': {623 'response_mime_type': 'application/json',624 'response_schema': list[Recipe]625 }626 },627 {628 'contents': [{629 'parts': [{'text': 'List a few popular gluten free cookie recipes, and include the amounts of ingredients.'}],630 'role': 'user'631 }],632 'config': {633 'response_mime_type': 'application/json',634 'response_schema': list[Recipe]635 }636 }637 ]638639 inline_batch_job = client.batches.create(640 model="gemini-3.8-flash",641 src=inline_requests,642 config={643 'display_name': "structured-output-job-1"644 },645 )646647 # wait for the job to finish648 job_name = inline_batch_job.name649 print(f"Polling status for job: {job_name}")650651 while True:652 batch_job_inline = client.batches.get(name=job_name)653 if batch_job_inline.state.name in ('JOB_STATE_SUCCEEDED', 'JOB_STATE_FAILED', 'JOB_STATE_CANCELLED', 'JOB_STATE_EXPIRED'):654 break655 print(f"Job not finished. Current state: {batch_job_inline.state.name}. Waiting 30 seconds...")656 time.sleep(30)657658 print(f"Job finished with state: {batch_job_inline.state.name}")659660 # print the response661 for i, inline_response in enumerate(batch_job_inline.dest.inlined_responses, start=1):662 print(f"\n--- Response {i} ---")663664 # Check for a successful response665 if inline_response.response:666 # The .text property is a shortcut to the generated text.667 print(inline_response.response.text)668669### JavaScript670671672 import {GoogleGenAI, Type} from '@google/genai';673674 const ai = new GoogleGenAI({});675676 const inlinedRequests = [677 {678 contents: [{679 parts: [{text: 'List a few popular cookie recipes, and include the amounts of ingredients.'}],680 role: 'user'681 }],682 config: {683 responseMimeType: 'application/json',684 responseSchema: {685 type: Type.ARRAY,686 items: {687 type: Type.OBJECT,688 properties: {689 'recipeName': {690 type: Type.STRING,691 description: 'Name of the recipe',692 nullable: false,693 },694 'ingredients': {695 type: Type.ARRAY,696 items: {697 type: Type.STRING,698 description: 'Ingredients of the recipe',699 nullable: false,700 },701 },702 },703 required: ['recipeName'],704 },705 },706 }707 },708 {709 contents: [{710 parts: [{text: 'List a few popular gluten free cookie recipes, and include the amounts of ingredients.'}],711 role: 'user'712 }],713 config: {714 responseMimeType: 'application/json',715 responseSchema: {716 type: Type.ARRAY,717 items: {718 type: Type.OBJECT,719 properties: {720 'recipeName': {721 type: Type.STRING,722 description: 'Name of the recipe',723 nullable: false,724 },725 'ingredients': {726 type: Type.ARRAY,727 items: {728 type: Type.STRING,729 description: 'Ingredients of the recipe',730 nullable: false,731 },732 },733 },734 required: ['recipeName'],735 },736 },737 }738 }739 ]740741 const inlinedBatchJob = await ai.batches.create({742 model: 'gemini-3.8-flash',743 src: inlinedRequests,744 config: {745 displayName: 'inlined-requests-job-1',746 }747 });748749### Java750751 import java.util.HashMap;752 import java.util.HashSet;753 import java.util.Arrays;754 import java.util.Collections;755 import com.google.genai.Client;756 import com.google.genai.types.BatchJob;757 import com.google.genai.types.BatchJobSource;758 import com.google.genai.types.Content;759 import com.google.genai.types.CreateBatchJobConfig;760 import com.google.genai.types.GenerateContentConfig;761 import com.google.genai.types.InlinedRequest;762 import com.google.genai.types.InlinedResponse;763 import com.google.genai.types.JobState;764 import com.google.genai.types.Part;765 import com.google.genai.types.Schema;766 import com.google.genai.types.Type;767 import java.util.List;768 import java.util.Map;769 import java.util.Set;770771 Client client = new Client();772773 Map<String, Schema> properties = new HashMap<>();774 properties.put("recipeName", Schema.builder().type(Type.Known.STRING).build());775 properties.put(776 "ingredients",777 Schema.builder()778 .type(Type.Known.ARRAY)779 .items(Schema.builder().type(Type.Known.STRING).build())780 .build());781782 Schema recipeSchema =783 Schema.builder()784 .type(Type.Known.ARRAY)785 .items(786 Schema.builder()787 .type(Type.Known.OBJECT)788 .properties(789 properties)790 .required("recipeName")791 .build())792 .build();793794 GenerateContentConfig jsonConfig =795 GenerateContentConfig.builder()796 .responseMimeType("application/json")797 .responseSchema(recipeSchema)798 .build();799800 List<InlinedRequest> inlineRequests =801 Arrays.asList(802 InlinedRequest.builder()803 .contents(804 Arrays.asList(805 Content.builder()806 .role("user")807 .parts(808 Arrays.asList(809 Part.fromText(810 "List a few popular cookie recipes, and include the amounts of ingredients.")))811 .build()))812 .config(jsonConfig)813 .build(),814 InlinedRequest.builder()815 .contents(816 Arrays.asList(817 Content.builder()818 .role("user")819 .parts(820 Arrays.asList(821 Part.fromText(822 "List a few popular gluten free cookie recipes, and include the amounts of ingredients.")))823 .build()))824 .config(jsonConfig)825 .build());826827 BatchJob inlineBatchJob =828 client.batches.create(829 "gemini-3.8-flash",830 BatchJobSource.builder().inlinedRequests(inlineRequests).build(),831 CreateBatchJobConfig.builder().displayName("structured-output-job-1").build());832833 // Wait for the job to finish834 String jobName = inlineBatchJob.name().get();835 System.out.println("Polling status for job: " + jobName);836837 Set<JobState.Known> completedStates =838 new HashSet<>(Arrays.asList(839 JobState.Known.JOB_STATE_SUCCEEDED,840 JobState.Known.JOB_STATE_FAILED,841 JobState.Known.JOB_STATE_CANCELLED,842 JobState.Known.JOB_STATE_EXPIRED));843844 BatchJob batchJobInline = client.batches.get(jobName, null);845 while (!completedStates.contains(batchJobInline.state().get().knownEnum())) {846 System.out.println(847 "Job not finished. Current state: " + batchJobInline.state().get() + ". Waiting 30 seconds...");848 Thread.sleep(30000);849 batchJobInline = client.batches.get(jobName, null);850 }851852 System.out.println("Job finished with state: " + batchJobInline.state().get());853854 // Print the response855 List<InlinedResponse> responses = batchJobInline.dest().get().inlinedResponses().orElse(Collections.emptyList());856 for (int i = 0; i < responses.size(); i++) {857 System.out.println("\n--- Response " + (i + 1) + " ---");858 InlinedResponse inlineResponse = responses.get(i);859 if (inlineResponse.response().isPresent()) {860 System.out.println(inlineResponse.response().get().text());861 }862 }863864The following shows an example output of this job:865866 --- Response 1 ---867 [868 {869 "recipe_name": "Chocolate Chip Cookies",870 "ingredients": [871 "1 cup (2 sticks) unsalted butter, softened",872 "3/4 cup granulated sugar",873 "3/4 cup packed light brown sugar",874 "1 large egg",875 "1 teaspoon vanilla extract",876 "2 1/4 cups all-purpose flour",877 "1 teaspoon baking soda",878 "1/2 teaspoon salt",879 "1 1/2 cups chocolate chips"880 ]881 },882 {883 "recipe_name": "Oatmeal Raisin Cookies",884 "ingredients": [885 "1 cup (2 sticks) unsalted butter, softened",886 "1 cup packed light brown sugar",887 "1/2 cup granulated sugar",888 "2 large eggs",889 "1 teaspoon vanilla extract",890 "1 1/2 cups all-purpose flour",891 "1 teaspoon baking soda",892 "1 teaspoon ground cinnamon",893 "1/2 teaspoon salt",894 "3 cups old-fashioned rolled oats",895 "1 cup raisins"896 ]897 },898 {899 "recipe_name": "Sugar Cookies",900 "ingredients": [901 "1 cup (2 sticks) unsalted butter, softened",902 "1 1/2 cups granulated sugar",903 "1 large egg",904 "1 teaspoon vanilla extract",905 "2 3/4 cups all-purpose flour",906 "1 teaspoon baking powder",907 "1/2 teaspoon salt"908 ]909 }910 ]911912 --- Response 2 ---913 [914 {915 "recipe_name": "Gluten-Free Chocolate Chip Cookies",916 "ingredients": [917 "1 cup (2 sticks) unsalted butter, softened",918 "3/4 cup granulated sugar",919 "3/4 cup packed light brown sugar",920 "2 large eggs",921 "1 teaspoon vanilla extract",922 "2 1/4 cups gluten-free all-purpose flour blend (with xanthan gum)",923 "1 teaspoon baking soda",924 "1/2 teaspoon salt",925 "1 1/2 cups chocolate chips"926 ]927 },928 {929 "recipe_name": "Gluten-Free Peanut Butter Cookies",930 "ingredients": [931 "1 cup (250g) creamy peanut butter",932 "1/2 cup (100g) granulated sugar",933 "1/2 cup (100g) packed light brown sugar",934 "1 large egg",935 "1 teaspoon vanilla extract",936 "1/2 teaspoon baking soda",937 "1/4 teaspoon salt"938 ]939 },940 {941 "recipe_name": "Gluten-Free Oatmeal Raisin Cookies",942 "ingredients": [943 "1/2 cup (1 stick) unsalted butter, softened",944 "1/2 cup granulated sugar",945 "1/2 cup packed light brown sugar",946 "1 large egg",947 "1 teaspoon vanilla extract",948 "1 cup gluten-free all-purpose flour blend",949 "1/2 teaspoon baking soda",950 "1/2 teaspoon ground cinnamon",951 "1/4 teaspoon salt",952 "1 1/2 cups gluten-free rolled oats",953 "1/2 cup raisins"954 ]955 }956 ]957958## Monitoring job status959960Use the operation name obtained when creating the batch job to poll its status.961The state field of the batch job will indicate its current status. A batch job962can be in one of the following states:963964- `JOB_STATE_PENDING`: The job has been created and is waiting to be processed by the service.965- `JOB_STATE_RUNNING`: The job is in progress.966- `JOB_STATE_SUCCEEDED`: The job completed successfully. You can now retrieve the results.967- `JOB_STATE_FAILED`: The job failed. Check the error details for more information.968- `JOB_STATE_CANCELLED`: The job was cancelled by the user.969- `JOB_STATE_EXPIRED`: The job has expired because it was running or pending for more than 48 hours. The job will not have any results to retrieve. You can try submitting the job again or splitting up the requests into smaller batches.970971You can poll the job status periodically to check for completion.972973### Python974975 import time976 from google import genai977978 client = genai.Client()979980 # Use the name of the job you want to check981 # e.g., inline_batch_job.name from the previous step982 job_name = "YOUR_BATCH_JOB_NAME" # (e.g. 'batches/your-batch-id')983 batch_job = client.batches.get(name=job_name)984985 completed_states = set([986 'JOB_STATE_SUCCEEDED',987 'JOB_STATE_FAILED',988 'JOB_STATE_CANCELLED',989 'JOB_STATE_EXPIRED',990 ])991992 print(f"Polling status for job: {job_name}")993 batch_job = client.batches.get(name=job_name) # Initial get994 while batch_job.state.name not in completed_states:995 print(f"Current state: {batch_job.state.name}")996 time.sleep(30) # Wait for 30 seconds before polling again997 batch_job = client.batches.get(name=job_name)998999 print(f"Job finished with state: {batch_job.state.name}")1000 if batch_job.state.name == 'JOB_STATE_FAILED':1001 print(f"Error: {batch_job.error}")10021003### JavaScript10041005 // Use the name of the job you want to check1006 // e.g., inlinedBatchJob.name from the previous step1007 let batchJob;1008 const completedStates = new Set([1009 'JOB_STATE_SUCCEEDED',1010 'JOB_STATE_FAILED',1011 'JOB_STATE_CANCELLED',1012 'JOB_STATE_EXPIRED',1013 ]);10141015 try {1016 batchJob = await ai.batches.get({name: inlinedBatchJob.name});1017 while (!completedStates.has(batchJob.state)) {1018 console.log(`Current state: ${batchJob.state}`);1019 // Wait for 30 seconds before polling again1020 await new Promise(resolve => setTimeout(resolve, 30000));1021 batchJob = await client.batches.get({ name: batchJob.name });1022 }1023 console.log(`Job finished with state: ${batchJob.state}`);1024 if (batchJob.state === 'JOB_STATE_FAILED') {1025 // The exact structure of `error` might vary depending on the SDK1026 // This assumes `error` is an object with a `message` property.1027 console.error(`Error: ${batchJob.state}`);1028 }1029 } catch (error) {1030 console.error(`An error occurred while polling job ${batchJob.name}:`, error);1031 }10321033### Java10341035 import java.util.HashSet;1036 import java.util.Arrays;1037 import com.google.genai.Client;1038 import com.google.genai.types.BatchJob;1039 import com.google.genai.types.JobState;1040 import java.util.Set;10411042 Client client = new Client();10431044 // Use the name of the job you want to check1045 String jobName = "batches/your-batch-id";10461047 Set<JobState.Known> completedStates =1048 new HashSet<>(Arrays.asList(1049 JobState.Known.JOB_STATE_SUCCEEDED,1050 JobState.Known.JOB_STATE_FAILED,1051 JobState.Known.JOB_STATE_CANCELLED,1052 JobState.Known.JOB_STATE_EXPIRED));10531054 System.out.println("Polling status for job: " + jobName);1055 BatchJob batchJob = client.batches.get(jobName, null);1056 while (!completedStates.contains(batchJob.state().get().knownEnum())) {1057 System.out.println("Current state: " + batchJob.state().get());1058 Thread.sleep(30000); // Wait for 30 seconds before polling again1059 batchJob = client.batches.get(jobName, null);1060 }10611062 System.out.println("Job finished with state: " + batchJob.state().get());1063 if (batchJob.state().get().knownEnum() == JobState.Known.JOB_STATE_FAILED) {1064 System.out.println("Error: " + batchJob.error().orElse(null));1065 }10661067### Polling and webhooks10681069**Tired of polling?** Gemini now supports1070[Webhooks](https://ai.google.dev/gemini-api/docs/webhooks) for processing completions asynchronously.1071Instead of continuously calling `GET / operations`, subscribe to1072`batch.succeeded` directly to allow the Gemini API to push real-time1073notifications to your server when asynchronous or long-running operations1074complete.10751076### Python10771078 from google import genai10791080 client = genai.Client()10811082 webhook = client.webhooks.create(1083 name="MyBatchWebhook",1084 subscribed_events=["batch.succeeded", "batch.failed"],1085 uri="https://my-api.com/gemini-callback",1086 )10871088 print(f"Created webhook: {webhook.name}")10891090### JavaScript10911092 import { GoogleGenAI } from "@google/genai";10931094 const client = new GoogleGenAI();10951096 async function createWebhook() {1097 const webhook = await client.webhooks.create({1098 name: "MyBatchWebhook",1099 subscribed_events: ["batch.succeeded", "batch.failed"],1100 uri: "https://my-api.com/gemini-callback",1101 });11021103 console.log(`Created webhook: ${webhook.name}`);1104 }11051106 createWebhook();11071108### Java11091110 import java.util.Arrays;1111 import com.google.genai.Client;1112 import com.google.genai.gaos.models.webhooks.Webhook;1113 import com.google.genai.gaos.models.webhooks.WebhookInput;1114 import com.google.genai.gaos.models.webhooks.WebhookSubscribedEvent;1115 import java.util.List;11161117 Client client = new Client();11181119 WebhookInput input =1120 WebhookInput.builder()1121 .name("MyBatchWebhook")1122 .subscribedEvents(1123 Arrays.asList(1124 WebhookSubscribedEvent.BATCH_SUCCEEDED,1125 WebhookSubscribedEvent.BATCH_FAILED))1126 .uri("https://my-api.com/gemini-callback")1127 .build();11281129 Webhook webhook = client.webhooks.create(input).webhook().get();1130 System.out.println("Created webhook: " + webhook.name().orElse(""));11311132### REST11331134 curl -X POST \1135 "https://generativelanguage.googleapis.com/v1/webhooks?webhook_id=my-example-webhook-123" \1136 -H "Content-Type: application/json" \1137 -H "x-goog-api-key: $GOOGLE_API_KEY" \1138 -d '{1139 "name": "My Example Webhook",1140 "uri": "https://my-api.com/gemini-callback",1141 "subscribed_events": ["batch.succeeded", "batch.failed"]1142 }'11431144## Retrieving results11451146Once the job status indicates your batch job has succeeded, the results are1147available in the `response` field.1148By default, batch job results are stored and available for download for 6 weeks,1149before they are permanently deleted.11501151### Python11521153 import json1154 from google import genai11551156 client = genai.Client()11571158 # Use the name of the job you want to check1159 # e.g., inline_batch_job.name from the previous step1160 job_name = "YOUR_BATCH_JOB_NAME"1161 batch_job = client.batches.get(name=job_name)11621163 if batch_job.state.name == 'JOB_STATE_SUCCEEDED':11641165 # If batch job was created with a file1166 if batch_job.dest and batch_job.dest.file_name:1167 # Results are in a file1168 result_file_name = batch_job.dest.file_name1169 print(f"Results are in file: {result_file_name}")11701171 print("Downloading result file content...")1172 file_content = client.files.download(file=result_file_name)1173 # Process file_content (bytes) as needed1174 print(file_content.decode('utf-8'))11751176 # If batch job was created with inline request1177 # (for embeddings, use batch_job.dest.inlined_embed_content_responses)1178 elif batch_job.dest and batch_job.dest.inlined_responses:1179 # Results are inline1180 print("Results are inline:")1181 for i, inline_response in enumerate(batch_job.dest.inlined_responses):1182 print(f"Response {i+1}:")1183 if inline_response.response:1184 # Accessing response, structure may vary.1185 try:1186 print(inline_response.response.text)1187 except AttributeError:1188 print(inline_response.response) # Fallback1189 elif inline_response.error:1190 print(f"Error: {inline_response.error}")1191 else:1192 print("No results found (neither file nor inline).")1193 else:1194 print(f"Job did not succeed. Final state: {batch_job.state.name}")1195 if batch_job.error:1196 print(f"Error: {batch_job.error}")11971198### JavaScript11991200 // Use the name of the job you want to check1201 // e.g., inlinedBatchJob.name from the previous step1202 const jobName = "YOUR_BATCH_JOB_NAME";12031204 try {1205 const batchJob = await ai.batches.get({ name: jobName });12061207 if (batchJob.state === 'JOB_STATE_SUCCEEDED') {1208 console.log('Found completed batch:', batchJob.displayName);1209 console.log(batchJob);12101211 // If batch job was created with a file destination1212 if (batchJob.dest?.fileName) {1213 const resultFileName = batchJob.dest.fileName;1214 console.log(`Results are in file: ${resultFileName}`);12151216 console.log("Downloading result file content...");1217 const fileContentBuffer = await ai.files.download({ file: resultFileName });12181219 // Process fileContentBuffer (Buffer) as needed1220 console.log(fileContentBuffer.toString('utf-8'));1221 }12221223 // If batch job was created with inline responses1224 else if (batchJob.dest?.inlinedResponses) {1225 console.log("Results are inline:");1226 for (let i = 0; i < batchJob.dest.inlinedResponses.length; i++) {1227 const inlineResponse = batchJob.dest.inlinedResponses[i];1228 console.log(`Response ${i + 1}:`);1229 if (inlineResponse.response) {1230 // Accessing response, structure may vary.1231 if (inlineResponse.response.text !== undefined) {1232 console.log(inlineResponse.response.text);1233 } else {1234 console.log(inlineResponse.response); // Fallback1235 }1236 } else if (inlineResponse.error) {1237 console.error(`Error: ${inlineResponse.error}`);1238 }1239 }1240 }12411242 // If batch job was an embedding batch with inline responses1243 else if (batchJob.dest?.inlinedEmbedContentResponses) {1244 console.log("Embedding results found inline:");1245 for (let i = 0; i < batchJob.dest.inlinedEmbedContentResponses.length; i++) {1246 const inlineResponse = batchJob.dest.inlinedEmbedContentResponses[i];1247 console.log(`Response ${i + 1}:`);1248 if (inlineResponse.response) {1249 console.log(inlineResponse.response);1250 } else if (inlineResponse.error) {1251 console.error(`Error: ${inlineResponse.error}`);1252 }1253 }1254 } else {1255 console.log("No results found (neither file nor inline).");1256 }1257 } else {1258 console.log(`Job did not succeed. Final state: ${batchJob.state}`);1259 if (batchJob.error) {1260 console.error(`Error: ${typeof batchJob.error === 'string' ? batchJob.error : batchJob.error.message || JSON.stringify(batchJob.error)}`);1261 }1262 }1263 } catch (error) {1264 console.error(`An error occurred while processing job ${jobName}:`, error);1265 }12661267### Java12681269 import com.google.genai.Client;1270 import com.google.genai.types.BatchJob;1271 import com.google.genai.types.BatchJobDestination;1272 import com.google.genai.types.InlinedEmbedContentResponse;1273 import com.google.genai.types.InlinedResponse;1274 import com.google.genai.types.JobState;1275 import java.nio.file.Files;1276 import java.nio.file.Paths;1277 import java.util.List;12781279 Client client = new Client();12801281 // Use the name of the job you want to check1282 String jobName = "batches/your-batch-id";1283 BatchJob batchJob = client.batches.get(jobName, null);12841285 if (batchJob.state().get().knownEnum() == JobState.Known.JOB_STATE_SUCCEEDED) {1286 BatchJobDestination dest = batchJob.dest().orElse(null);12871288 // If batch job was created with a file destination1289 if (dest != null && dest.fileName().isPresent()) {1290 String resultFileName = dest.fileName().get();1291 System.out.println("Results are in file: " + resultFileName);12921293 System.out.println("Downloading result file content...");1294 client.files.download(resultFileName, "batch_results.jsonl", null);1295 String fileContent = Files.readString(Paths.get("batch_results.jsonl"));1296 System.out.println(fileContent);1297 }1298 // If batch job was created with inline requests1299 else if (dest != null && dest.inlinedResponses().isPresent()) {1300 System.out.println("Results are inline:");1301 List<InlinedResponse> responses = dest.inlinedResponses().get();1302 for (int i = 0; i < responses.size(); i++) {1303 System.out.println("Response " + (i + 1) + ":");1304 InlinedResponse inlineResponse = responses.get(i);1305 if (inlineResponse.response().isPresent()) {1306 System.out.println(inlineResponse.response().get().text());1307 } else if (inlineResponse.error().isPresent()) {1308 System.out.println("Error: " + inlineResponse.error().get());1309 }1310 }1311 }1312 // If batch job was an embedding batch with inline responses1313 else if (dest != null && dest.inlinedEmbedContentResponses().isPresent()) {1314 System.out.println("Embedding results found inline:");1315 List<InlinedEmbedContentResponse> responses = dest.inlinedEmbedContentResponses().get();1316 for (int i = 0; i < responses.size(); i++) {1317 System.out.println("Response " + (i + 1) + ":");1318 InlinedEmbedContentResponse inlineResponse = responses.get(i);1319 if (inlineResponse.response().isPresent()) {1320 System.out.println(inlineResponse.response().get());1321 } else if (inlineResponse.error().isPresent()) {1322 System.out.println("Error: " + inlineResponse.error().get());1323 }1324 }1325 } else {1326 System.out.println("No results found (neither file nor inline).");1327 }1328 } else {1329 System.out.println("Job did not succeed. Final state: " + batchJob.state().get());1330 batchJob.error().ifPresent(err -> System.out.println("Error: " + err));1331 }13321333### REST13341335 BATCH_NAME="batches/123456" # Your batch job name13361337 curl https://generativelanguage.googleapis.com/v1beta/$BATCH_NAME \1338 -H "x-goog-api-key: $GEMINI_API_KEY" \1339 -H "Content-Type:application/json" 2> /dev/null > batch_status.json13401341 if jq -r '.done' batch_status.json | grep -q "false"; then1342 echo "Batch has not finished processing"1343 fi13441345 batch_state=$(jq -r '.metadata.state' batch_status.json)1346 if [[ $batch_state = "JOB_STATE_SUCCEEDED" ]]; then1347 if [[ $(jq '.response | has("inlinedResponses")' batch_status.json) = "true" ]]; then1348 jq -r '.response.inlinedResponses' batch_status.json1349 exit1350 fi1351 responses_file_name=$(jq -r '.response.responsesFile' batch_status.json)1352 curl https://generativelanguage.googleapis.com/download/v1beta/$responses_file_name:download?alt=media \1353 -H "x-goog-api-key: $GEMINI_API_KEY" 2> /dev/null1354 elif [[ $batch_state = "JOB_STATE_FAILED" ]]; then1355 jq '.error' batch_status.json1356 elif [[ $batch_state == "JOB_STATE_CANCELLED" ]]; then1357 echo "Batch was cancelled by the user"1358 elif [[ $batch_state == "JOB_STATE_EXPIRED" ]]; then1359 echo "Batch expired after 48 hours"1360 fi13611362## Listing batch jobs13631364You can list your recent batch jobs.13651366### Python13671368 batch_jobs = client.batches.list()13691370 # Optional query config:1371 # batch_jobs = client.batches.list(config={'page_size': 5})13721373 for batch_job in batch_jobs:1374 print(batch_job)13751376### JavaScript13771378 const batchJobs = await ai.batches.list();13791380 // Optional query config:1381 // const batchJobs = await ai.batches.list({config: {'pageSize': 5}});13821383 for await (const batchJob of batchJobs) {1384 console.log(batchJob);1385 }13861387### Java13881389 import com.google.genai.Client;1390 import com.google.genai.Pager;1391 import com.google.genai.types.BatchJob;1392 import com.google.genai.types.ListBatchJobsConfig;13931394 Client client = new Client();13951396 Pager<BatchJob> batchJobs = client.batches.list(null);13971398 // Optional query config:1399 // Pager<BatchJob> batchJobs = client.batches.list(ListBatchJobsConfig.builder().pageSize(5).build());14001401 for (BatchJob batchJob : batchJobs) {1402 System.out.println(batchJob);1403 }14041405### REST14061407 curl https://generativelanguage.googleapis.com/v1beta/batches \1408 -H "x-goog-api-key: $GEMINI_API_KEY"14091410## Cancelling a batch job14111412You can cancel an ongoing batch job using its name. When a job is1413canceled, it stops processing new requests.14141415### Python14161417 client.batches.cancel(name=batch_job_to_cancel.name)14181419### JavaScript14201421 await ai.batches.cancel({name: batchJobToCancel.name});14221423### Java14241425 import com.google.genai.Client;14261427 Client client = new Client();14281429 String batchJobToCancelName = "batches/your-batch-id";1430 client.batches.cancel(batchJobToCancelName, null);14311432### REST14331434 BATCH_NAME="batches/123456" # Your batch job name14351436 # Cancel the batch1437 curl https://generativelanguage.googleapis.com/v1beta/$BATCH_NAME:cancel \1438 -H "x-goog-api-key: $GEMINI_API_KEY" \14391440 # Confirm that the status of the batch after cancellation is JOB_STATE_CANCELLED1441 curl https://generativelanguage.googleapis.com/v1beta/$BATCH_NAME \1442 -H "x-goog-api-key: $GEMINI_API_KEY" \1443 -H "Content-Type:application/json" 2> /dev/null | jq -r '.metadata.state'14441445## Deleting a batch job14461447You can delete an existing batch job using its name. When a job is1448deleted, it stops processing new requests and is removed from the list of1449batch jobs.14501451### Python14521453 client.batches.delete(name=batch_job_to_delete.name)14541455### JavaScript14561457 await ai.batches.delete({name: batchJobToDelete.name});14581459### Java14601461 import com.google.genai.Client;14621463 Client client = new Client();14641465 String batchJobToDeleteName = "batches/your-batch-id";1466 client.batches.delete(batchJobToDeleteName, null);14671468### REST14691470 BATCH_NAME="batches/123456" # Your batch job name14711472 # Delete the batch job1473 curl -X DELETE "https://generativelanguage.googleapis.com/v1beta/$BATCH_NAME" \1474 -H "x-goog-api-key: $GEMINI_API_KEY"14751476## Generating images in batch14771478If you're using [Gemini Nano Banana](https://ai.google.dev/gemini-api/docs/image-generation) and need to generate a lot1479of images, you can use the Batch API to get higher1480[rate limits](https://ai.google.dev/gemini-api/docs/rate-limits) in exchange for a turnaround of up1481to 24 hours.14821483You can either use [inline requests](https://ai.google.dev/gemini-api/docs/batch-api#inline-requests-images) for small batches of requests (under 20MB) or1484a [JSONL input file](https://ai.google.dev/gemini-api/docs/batch-api#input-file-images) for large batches (recommended for image generation):14851486### Inline requests for images14871488### Python14891490 import time1491 import base641492 import json1493 from google import genai1494 from google.genai import types1495 from PIL import Image14961497 client = genai.Client()14981499 # 1. Create batch job with inline requests1500 inline_requests = [1501 {1502 'contents': [{'parts': [{'text': 'A big letter A surrounded by animals starting with the A letter'}]}],1503 'config': {'response_modalities': ['TEXT', 'IMAGE']}1504 },1505 {1506 'contents': [{'parts': [{'text': 'A big letter B surrounded by animals starting with the B letter'}]}],1507 'config': {'response_modalities': ['TEXT', 'IMAGE']}1508 }1509 ]15101511 inline_batch_job = client.batches.create(1512 model="gemini-3-pro-image-preview",1513 src=inline_requests,1514 config={1515 'display_name': "inlined-image-requests-job-1",1516 },1517 )15181519 print(f"Created batch job: {inline_batch_job.name}")15201521 # 2. Monitor job status1522 job_name = inline_batch_job.name1523 print(f"Polling status for job: {job_name}")15241525 completed_states = set([1526 'JOB_STATE_SUCCEEDED',1527 'JOB_STATE_FAILED',1528 'JOB_STATE_CANCELLED',1529 'JOB_STATE_EXPIRED',1530 ])15311532 batch_job = client.batches.get(name=job_name) # Initial get1533 while batch_job.state.name not in completed_states:1534 print(f"Current state: {batch_job.state.name}")1535 time.sleep(10) # Wait for 10 seconds before polling again1536 batch_job = client.batches.get(name=job_name)15371538 print(f"Job finished with state: {batch_job.state.name}")15391540 # 3. Retrieve results1541 if batch_job.state.name == 'JOB_STATE_SUCCEEDED':1542 print("Results are inline:")1543 for i, inline_response in enumerate(batch_job.dest.inlined_responses):1544 print(f"Response {i+1}:")1545 if inline_response.response:1546 for part in inline_response.response.candidates[0].content.parts:1547 if part.text:1548 print(part.text)1549 elif part.inline_data:1550 print(f"Image mime type: {part.inline_data.mime_type}")1551 image = part.as_image()1552 image.save(f"image_{i+1}.png")1553 elif inline_response.error:1554 print(f"Error: {inline_response.error}")1555 elif batch_job.state.name == 'JOB_STATE_FAILED':1556 print(f"Error: {batch_job.error}")15571558### JavaScript15591560 import {GoogleGenAI} from '@google/genai';15611562 const ai = new GoogleGenAI({});15631564 async function run() {1565 // 1. Create batch job with inline requests1566 const inlinedRequests = [1567 {1568 contents: [{parts: [{text: 'A big letter A surrounded by animals starting with the A letter'}]}],1569 config: {responseModalities: ['TEXT', 'IMAGE']}1570 },1571 {1572 contents: [{parts: [{text: 'A big letter B surrounded by animals starting with the B letter'}]}],1573 config: {responseModalities: ['TEXT', 'IMAGE']}1574 }1575 ]15761577 const inlineBatchJob = await ai.batches.create({1578 model: 'gemini-3-pro-image-preview',1579 src: inlinedRequests,1580 config: {1581 displayName: 'inlined-image-requests-job-1',1582 }1583 });15841585 console.log(inlineBatchJob);15861587 // 2. Monitor job status1588 let batchJob;1589 const completedStates = new Set([1590 'JOB_STATE_SUCCEEDED',1591 'JOB_STATE_FAILED',1592 'JOB_STATE_CANCELLED',1593 'JOB_STATE_EXPIRED',1594 ]);15951596 try {1597 batchJob = await ai.batches.get({name: inlineBatchJob.name});1598 while (!completedStates.has(batchJob.state)) {1599 console.log(`Current state: ${batchJob.state}`);1600 // Wait for 10 seconds before polling again1601 await new Promise(resolve => setTimeout(resolve, 10000));1602 batchJob = await ai.batches.get({ name: batchJob.name });1603 }1604 console.log(`Job finished with state: ${batchJob.state}`);1605 } catch (error) {1606 console.error(`An error occurred while polling job ${inlineBatchJob.name}:`, error);1607 return;1608 }16091610 // 3. Retrieve results1611 if (batchJob.state === 'JOB_STATE_SUCCEEDED') {1612 if (batchJob.dest?.inlinedResponses) {1613 console.log("Results are inline:");1614 for (let i = 0; i < batchJob.dest.inlinedResponses.length; i++) {1615 const inlineResponse = batchJob.dest.inlinedResponses[i];1616 console.log(`Response ${i + 1}:`);1617 if (inlineResponse.response) {1618 for (const part of inlineResponse.response.candidates[0].content.parts) {1619 if (part.text) {1620 console.log(part.text);1621 } else if (part.inlineData) {1622 console.log(`Image mime type: ${part.inlineData.mimeType}`);1623 }1624 }1625 } else if (inlineResponse.error) {1626 console.error(`Error: ${inlineResponse.error}`);1627 }1628 }1629 } else {1630 console.log("No inline results found.");1631 }1632 } else if (batchJob.state === 'JOB_STATE_FAILED') {1633 console.error(`Error: ${typeof batchJob.error === 'string' ? batchJob.error : batchJob.error.message || JSON.stringify(batchJob.error)}`);1634 }1635 }1636 run();16371638### Java16391640 import java.util.HashSet;1641 import java.util.Arrays;1642 import java.util.Collections;1643 import com.google.genai.Client;1644 import com.google.genai.types.BatchJob;1645 import com.google.genai.types.BatchJobSource;1646 import com.google.genai.types.Content;1647 import com.google.genai.types.CreateBatchJobConfig;1648 import com.google.genai.types.GenerateContentConfig;1649 import com.google.genai.types.InlinedRequest;1650 import com.google.genai.types.InlinedResponse;1651 import com.google.genai.types.JobState;1652 import com.google.genai.types.Part;1653 import java.nio.file.Files;1654 import java.nio.file.Paths;1655 import java.util.List;1656 import java.util.Set;16571658 Client client = new Client();16591660 // 1. Create batch job with inline requests1661 GenerateContentConfig imageConfig =1662 GenerateContentConfig.builder().responseModalities("TEXT", "IMAGE").build();16631664 List<InlinedRequest> inlineRequests =1665 Arrays.asList(1666 InlinedRequest.builder()1667 .contents(1668 Arrays.asList(1669 Content.fromParts(1670 Part.fromText(1671 "A big letter A surrounded by animals starting with the A letter"))))1672 .config(imageConfig)1673 .build(),1674 InlinedRequest.builder()1675 .contents(1676 Arrays.asList(1677 Content.fromParts(1678 Part.fromText(1679 "A big letter B surrounded by animals starting with the B letter"))))1680 .config(imageConfig)1681 .build());16821683 BatchJob inlineBatchJob =1684 client.batches.create(1685 "gemini-3-pro-image-preview",1686 BatchJobSource.builder().inlinedRequests(inlineRequests).build(),1687 CreateBatchJobConfig.builder().displayName("inlined-image-requests-job-1").build());16881689 System.out.println("Created batch job: " + inlineBatchJob.name().orElse(""));16901691 // 2. Monitor job status1692 String jobName = inlineBatchJob.name().get();1693 System.out.println("Polling status for job: " + jobName);16941695 Set<JobState.Known> completedStates =1696 new HashSet<>(Arrays.asList(1697 JobState.Known.JOB_STATE_SUCCEEDED,1698 JobState.Known.JOB_STATE_FAILED,1699 JobState.Known.JOB_STATE_CANCELLED,1700 JobState.Known.JOB_STATE_EXPIRED));17011702 BatchJob batchJob = client.batches.get(jobName, null);1703 while (!completedStates.contains(batchJob.state().get().knownEnum())) {1704 System.out.println("Current state: " + batchJob.state().get());1705 Thread.sleep(10000); // Wait for 10 seconds before polling again1706 batchJob = client.batches.get(jobName, null);1707 }17081709 System.out.println("Job finished with state: " + batchJob.state().get());17101711 // 3. Retrieve results1712 if (batchJob.state().get().knownEnum() == JobState.Known.JOB_STATE_SUCCEEDED) {1713 System.out.println("Results are inline:");1714 List<InlinedResponse> responses = batchJob.dest().get().inlinedResponses().orElse(Collections.emptyList());1715 for (int i = 0; i < responses.size(); i++) {1716 System.out.println("Response " + (i + 1) + ":");1717 InlinedResponse inlineResponse = responses.get(i);1718 if (inlineResponse.response().isPresent()) {1719 for (Part part : inlineResponse.response().get().parts()) {1720 if (part.text().isPresent()) {1721 System.out.println(part.text().get());1722 } else if (part.inlineData().isPresent()) {1723 System.out.println("Image mime type: " + part.inlineData().get().mimeType().orElse(""));1724 Files.write(1725 Paths.get("image_" + (i + 1) + ".png"),1726 part.inlineData().get().data().get());1727 }1728 }1729 } else if (inlineResponse.error().isPresent()) {1730 System.out.println("Error: " + inlineResponse.error().get());1731 }1732 }1733 } else if (batchJob.state().get().knownEnum() == JobState.Known.JOB_STATE_FAILED) {1734 System.out.println("Error: " + batchJob.error().orElse(null));1735 }17361737### REST17381739 # 1. Create batch job1740 printf -v request_data '{1741 "batch": {1742 "display_name": "my-batch-image-requests",1743 "input_config": {1744 "requests": {1745 "requests": [1746 {1747 "request": {1748 "contents": [{"parts": [{"text": "A big letter A surrounded by animals starting with the A letter"}]}],1749 "generation_config": {"responseModalities": ["TEXT", "IMAGE"]}1750 },1751 "metadata": { "key": "request-1" }1752 },1753 {1754 "request": {1755 "contents": [{"parts": [{"text": "A big letter B surrounded by animals starting with the B letter"}]}],1756 "generation_config": {"responseModalities": ["TEXT", "IMAGE"]}1757 },1758 "metadata": { "key": "request-2" }1759 }1760 ]1761 }1762 }1763 }1764 }'1765 curl https://generativelanguage.googleapis.com/v1beta/models/gemini-3-pro-image-preview:batchGenerateContent \1766 -H "x-goog-api-key: $GEMINI_API_KEY" \1767 -X POST \1768 -H "Content-Type:application/json" \1769 -d "$request_data" > created_batch.json17701771 BATCH_NAME=$(jq -r '.name' created_batch.json)1772 echo "Created batch job: $BATCH_NAME"17731774 # 2. Poll job status until completion by repeating the following command1775 # Replace $BATCH_NAME with the name returned above.1776 curl https://generativelanguage.googleapis.com/v1beta/$BATCH_NAME \1777 -H "x-goog-api-key: $GEMINI_API_KEY" \1778 -H "Content-Type:application/json" > batch_status.json17791780 echo "Current status:"1781 jq '.' batch_status.json17821783 # 3. If state is JOB_STATE_SUCCEEDED, retrieve results from batch_status.json1784 batch_state=$(jq -r '.state' batch_status.json)1785 if [[ $batch_state = "JOB_STATE_SUCCEEDED" ]]; then1786 echo "Job succeeded. Results:"1787 jq -r '.dest.inlinedResponses' batch_status.json1788 fi17891790### Input file for images17911792### Python17931794 import json1795 import time1796 import base641797 from google import genai1798 from google.genai import types1799 from PIL import Image18001801 client = genai.Client()18021803 # 1. Create and upload file1804 file_name = "my-batch-image-requests.jsonl"1805 with open(file_name, "w") as f:1806 requests = [1807 {"key": "request-1", "request": {"contents": [{"parts": [{"text": "A big letter A surrounded by animals starting with the A letter"}]}], "generation_config": {"responseModalities": ["TEXT", "IMAGE"]}}},1808 {"key": "request-2", "request": {"contents": [{"parts": [{"text": "A big letter B surrounded by animals starting with the B letter"}]}], "generation_config": {"responseModalities": ["TEXT", "IMAGE"]}}}1809 ]1810 for req in requests:1811 f.write(json.dumps(req) + "\n")18121813 uploaded_file = client.files.upload(1814 file=file_name,1815 config=types.UploadFileConfig(display_name='my-batch-image-requests', mime_type='jsonl')1816 )1817 print(f"Uploaded file: {uploaded_file.name}")18181819 # 2. Create batch job1820 file_batch_job = client.batches.create(1821 model="gemini-3-pro-image-preview",1822 src=uploaded_file.name,1823 config={1824 'display_name': "file-image-upload-job-1",1825 },1826 )1827 print(f"Created batch job: {file_batch_job.name}")18281829 # 3. Monitor job status1830 job_name = file_batch_job.name1831 print(f"Polling status for job: {job_name}")18321833 completed_states = set([1834 'JOB_STATE_SUCCEEDED',1835 'JOB_STATE_FAILED',1836 'JOB_STATE_CANCELLED',1837 'JOB_STATE_EXPIRED',1838 ])18391840 batch_job = client.batches.get(name=job_name) # Initial get1841 while batch_job.state.name not in completed_states:1842 print(f"Current state: {batch_job.state.name}")1843 time.sleep(10) # Wait for 10 seconds before polling again1844 batch_job = client.batches.get(name=job_name)18451846 print(f"Job finished with state: {batch_job.state.name}")18471848 # 4. Retrieve results1849 if batch_job.state.name == 'JOB_STATE_SUCCEEDED':1850 result_file_name = batch_job.dest.file_name1851 print(f"Results are in file: {result_file_name}")1852 print("Downloading result file content...")1853 file_content_bytes = client.files.download(file=result_file_name)1854 file_content = file_content_bytes.decode('utf-8')1855 # The result file is also a JSONL file. Parse and print each line.1856 for line in file_content.splitlines():1857 if line:1858 parsed_response = json.loads(line)1859 if 'response' in parsed_response and parsed_response['response']:1860 for part in parsed_response['response']['candidates'][0]['content']['parts']:1861 if part.get('text'):1862 print(part['text'])1863 elif part.get('inlineData'):1864 print(f"Image mime type: {part['inlineData']['mimeType']}")1865 data = base64.b64decode(part['inlineData']['data'])1866 elif 'error' in parsed_response:1867 print(f"Error: {parsed_response['error']}")1868 elif batch_job.state.name == 'JOB_STATE_FAILED':1869 print(f"Error: {batch_job.error}")18701871### JavaScript18721873 import {GoogleGenAI} from '@google/genai';1874 import * as fs from "fs";1875 import * as path from "path";1876 import { fileURLToPath } from 'url';18771878 const ai = new GoogleGenAI({});18791880 async function run() {1881 // 1. Create and upload file1882 const fileName = "my-batch-image-requests.jsonl";1883 const requests = [1884 { "key": "request-1", "request": { "contents": [{ "parts": [{ "text": "A big letter A surrounded by animals starting with the A letter" }] }], "generation_config": {"responseModalities": ["TEXT", "IMAGE"]} } },1885 { "key": "request-2", "request": { "contents": [{ "parts": [{ "text": "A big letter B surrounded by animals starting with the B letter" }] }], "generation_config": {"responseModalities": ["TEXT", "IMAGE"]} } }1886 ];1887 const __filename = fileURLToPath(import.meta.url);1888 const __dirname = path.dirname(__filename);1889 const filePath = path.join(__dirname, fileName);18901891 try {1892 const writeStream = fs.createWriteStream(filePath, { flags: 'w' });1893 for (const req of requests) {1894 writeStream.write(JSON.stringify(req) + '\n');1895 }1896 writeStream.end();1897 console.log(`Successfully wrote batch requests to ${filePath}`);1898 } catch (error) {1899 console.error(`An unexpected error occurred writing file:`, error);1900 return;1901 }19021903 const uploadedFile = await ai.files.upload({file: fileName, config: { mimeType: 'jsonl' }});1904 console.log(`Uploaded file: ${uploadedFile.name}`);19051906 // 2. Create batch job1907 const fileBatchJob = await ai.batches.create({1908 model: 'gemini-3-pro-image-preview',1909 src: uploadedFile.name,1910 config: {1911 displayName: 'file-image-upload-job-1',1912 }1913 });1914 console.log(fileBatchJob);19151916 // 3. Monitor job status1917 let batchJob;1918 const completedStates = new Set([1919 'JOB_STATE_SUCCEEDED',1920 'JOB_STATE_FAILED',1921 'JOB_STATE_CANCELLED',1922 'JOB_STATE_EXPIRED',1923 ]);19241925 try {1926 batchJob = await ai.batches.get({name: fileBatchJob.name});1927 while (!completedStates.has(batchJob.state)) {1928 console.log(`Current state: ${batchJob.state}`);1929 // Wait for 10 seconds before polling again1930 await new Promise(resolve => setTimeout(resolve, 10000));1931 batchJob = await ai.batches.get({ name: batchJob.name });1932 }1933 console.log(`Job finished with state: ${batchJob.state}`);1934 } catch (error) {1935 console.error(`An error occurred while polling job ${fileBatchJob.name}:`, error);1936 return;1937 }19381939 // 4. Retrieve results1940 if (batchJob.state === 'JOB_STATE_SUCCEEDED') {1941 if (batchJob.dest?.fileName) {1942 const resultFileName = batchJob.dest.fileName;1943 console.log(`Results are in file: ${resultFileName}`);1944 console.log("Downloading result file content...");1945 const fileContentBuffer = await ai.files.download({ file: resultFileName });1946 const fileContent = fileContentBuffer.toString('utf-8');1947 for (const line of fileContent.split('\n')) {1948 if (line) {1949 const parsedResponse = JSON.parse(line);1950 if (parsedResponse.response) {1951 for (const part of parsedResponse.response.candidates[0].content.parts) {1952 if (part.text) {1953 console.log(part.text);1954 } else if (part.inlineData) {1955 console.log(`Image mime type: ${part.inlineData.mimeType}`);1956 }1957 }1958 } else if (parsedResponse.error) {1959 console.error(`Error: ${parsedResponse.error}`);1960 }1961 }1962 }1963 } else {1964 console.log("No result file found.");1965 }1966 } else if (batchJob.state === 'JOB_STATE_FAILED') {1967 console.error(`Error: ${typeof batchJob.error === 'string' ? batchJob.error : batchJob.error.message || JSON.stringify(batchJob.error)}`);1968 }1969 }1970 run();19711972### Java19731974 import java.util.HashSet;1975 import java.util.Arrays;1976 import com.google.genai.Client;1977 import com.google.genai.types.BatchJob;1978 import com.google.genai.types.BatchJobSource;1979 import com.google.genai.types.CreateBatchJobConfig;1980 import com.google.genai.types.File;1981 import com.google.genai.types.JobState;1982 import com.google.genai.types.UploadFileConfig;1983 import java.nio.file.Files;1984 import java.nio.file.Paths;1985 import java.util.List;1986 import java.util.Set;19871988 Client client = new Client();19891990 // 1. Create and upload file1991 String fileName = "my-batch-image-requests.jsonl";1992 List<String> requests =1993 Arrays.asList(1994 "{\"key\": \"request-1\", \"request\": {\"contents\": [{\"parts\": [{\"text\": \"A big letter A surrounded by animals starting with the A letter\"}]}], \"generation_config\": {\"responseModalities\": [\"TEXT\", \"IMAGE\"]}}}",1995 "{\"key\": \"request-2\", \"request\": {\"contents\": [{\"parts\": [{\"text\": \"A big letter B surrounded by animals starting with the B letter\"}]}], \"generation_config\": {\"responseModalities\": [\"TEXT\", \"IMAGE\"]}}}");1996 Files.write(Paths.get(fileName), requests);19971998 File uploadedFile =1999 client.files.upload(2000 fileName,2001 UploadFileConfig.builder()2002 .displayName("my-batch-image-requests")2003 .mimeType("jsonl")2004 .build());2005 System.out.println("Uploaded file: " + uploadedFile.name().orElse(""));20062007 // 2. Create batch job2008 BatchJob fileBatchJob =2009 client.batches.create(2010 "gemini-3-pro-image-preview",2011 BatchJobSource.builder().fileName(uploadedFile.name().get()).build(),2012 CreateBatchJobConfig.builder().displayName("file-image-upload-job-1").build());2013 System.out.println("Created batch job: " + fileBatchJob.name().orElse(""));20142015 // 3. Monitor job status2016 String jobName = fileBatchJob.name().get();2017 System.out.println("Polling status for job: " + jobName);20182019 Set<JobState.Known> completedStates =2020 new HashSet<>(Arrays.asList(2021 JobState.Known.JOB_STATE_SUCCEEDED,2022 JobState.Known.JOB_STATE_FAILED,2023 JobState.Known.JOB_STATE_CANCELLED,2024 JobState.Known.JOB_STATE_EXPIRED));20252026 BatchJob batchJob = client.batches.get(jobName, null);2027 while (!completedStates.contains(batchJob.state().get().knownEnum())) {2028 System.out.println("Current state: " + batchJob.state().get());2029 Thread.sleep(10000); // Wait for 10 seconds before polling again2030 batchJob = client.batches.get(jobName, null);2031 }20322033 System.out.println("Job finished with state: " + batchJob.state().get());20342035 // 4. Retrieve results2036 if (batchJob.state().get().knownEnum() == JobState.Known.JOB_STATE_SUCCEEDED) {2037 String resultFileName = batchJob.dest().get().fileName().get();2038 System.out.println("Results are in file: " + resultFileName);2039 System.out.println("Downloading result file content...");2040 client.files.download(resultFileName, "batch_image_results.jsonl", null);2041 for (String line : Files.readAllLines(Paths.get("batch_image_results.jsonl"))) {2042 if (!line.isEmpty()) {2043 System.out.println(line);2044 }2045 }2046 } else if (batchJob.state().get().knownEnum() == JobState.Known.JOB_STATE_FAILED) {2047 System.out.println("Error: " + batchJob.error().orElse(null));2048 }20492050### REST20512052 # 1. Create and upload file2053 echo '{"key": "request-1", "request": {"contents": [{"parts": [{"text": "A big letter A surrounded by animals starting with the A letter"}]}], "generation_config": {"responseModalities": ["TEXT", "IMAGE"]}}}' > my-batch-image-requests.jsonl2054 echo '{"key": "request-2", "request": {"contents": [{"parts": [{"text": "A big letter B surrounded by animals starting with the B letter"}]}], "generation_config": {"responseModalities": ["TEXT", "IMAGE"]}}}' >> my-batch-image-requests.jsonl20552056 # Follow File API guide to upload: https://ai.google.dev/gemini-api/docs/files#upload_a_file2057 # This example assumes you have uploaded the file and set BATCH_INPUT_FILE to its name (e.g., files/abcdef123)2058 BATCH_INPUT_FILE="files/your-uploaded-file-name"20592060 # 2. Create batch job2061 printf -v request_data '{2062 "batch": {2063 "display_name": "my-batch-file-image-requests",2064 "input_config": { "file_name": "%s" }2065 }2066 }' "$BATCH_INPUT_FILE"2067 curl https://generativelanguage.googleapis.com/v1beta/models/gemini-3-pro-image-preview:batchGenerateContent \2068 -X POST \2069 -H "x-goog-api-key: $GEMINI_API_KEY" \2070 -H "Content-Type:application/json" \2071 -d "$request_data" > created_batch.json20722073 BATCH_NAME=$(jq -r '.name' created_batch.json)2074 echo "Created batch job: $BATCH_NAME"20752076 # 3. Poll job status until completion by repeating the following command:2077 curl https://generativelanguage.googleapis.com/v1beta/$BATCH_NAME \2078 -H "x-goog-api-key: $GEMINI_API_KEY" \2079 -H "Content-Type:application/json" > batch_status.json20802081 echo "Current status:"2082 jq '.' batch_status.json20832084 # 4. If state is JOB_STATE_SUCCEEDED, download results file2085 batch_state=$(jq -r '.state' batch_status.json)2086 if [[ $batch_state = "JOB_STATE_SUCCEEDED" ]]; then2087 responses_file_name=$(jq -r '.dest.fileName' batch_status.json)2088 echo "Job succeeded. Downloading results from $responses_file_name..."2089 curl https://generativelanguage.googleapis.com/download/v1beta/$responses_file_name:download?alt=media \2090 -H "x-goog-api-key: $GEMINI_API_KEY" > batch_results.jsonl2091 echo "Results saved to batch_results.jsonl"2092 fi20932094## Technical details20952096- **Supported models:** Batch API supports a range of Gemini models. Refer to the [Models page](https://ai.google.dev/gemini-api/docs/models) for each model's support of Batch API. The supported modalities for Batch API are the same as what's supported on the interactive (or non-batch) API.2097- **Pricing:** Batch API usage is priced at 50% of the standard interactive API cost for the equivalent model. See the [pricing page](https://ai.google.dev/gemini-api/docs/pricing) for details. Refer to the [rate limits page](https://ai.google.dev/gemini-api/docs/rate-limits#batch-mode) for details on rate limits for this feature.2098- **Service level objective (SLO):** Batch jobs are designed to complete within a 24-hour turnaround time. Many jobs may complete much faster depending on their size and current system load.2099- **Caching:** [Context caching](https://ai.google.dev/gemini-api/docs/caching) is supported for batch requests. Reuse cached content by specifying the `cached_content` resource name in the configuration of individual requests within your batch. If a request in your batch results in a cache hit, you pay the [standard context caching rates](https://ai.google.dev/gemini-api/docs/pricing).21002101## Best practices21022103- **Use input files for large requests:** For a large number of requests, always use the file input method for better manageability and to avoid hitting request size limits for the [`BatchGenerateContent`](https://ai.google.dev/api/batch-mode#google.ai.generativelanguage.v1beta.BatchService.BatchGenerateContent) call itself. Note that there's a 2GB file size limit per input file.2104- **Error handling:** Check the `batchStats` for `failedRequestCount` after a job completes. If using file output, parse each line to check if it's a `GenerateContentResponse` or a status object indicating an error for that specific request. See the [troubleshooting2105 guide](https://ai.google.dev/gemini-api/docs/troubleshooting#error-codes) for a complete set of error codes.2106- **Submit jobs once:** The creation of a batch job is not idempotent. If you send the same creation request twice, two separate batch jobs will be created.2107- **Break up very large batches:** While the target turnaround time is 24 hours, actual processing time can vary based on system load and job size. For large jobs, consider breaking them into smaller batches if intermediate results are needed sooner.21082109## What's next21102111- Check out the [Batch API notebook](https://colab.research.google.com/github/google-gemini/cookbook/blob/main/quickstarts/Batch_mode.ipynb) for more examples.2112- The OpenAI compatibility layer supports Batch API. Read the examples on the [OpenAI Compatibility](https://ai.google.dev/gemini-api/docs/openai#batch) page.