Usage flow

The steps for using batch processing are as follows:

Create a new batch job

To create aBatchJob resource, callMutateBatchJob.

Java

privateStringcreateBatchJob(BatchJobServiceClientbatchJobServiceClient,longcustomerId){BatchJobOperationoperation=BatchJobOperation.newBuilder().setCreate(BatchJob.newBuilder().build()).build();StringbatchJobResourceName=batchJobServiceClient.mutateBatchJob(Long.toString(customerId),operation).getResult().getResourceName();System.out.printf("Created a mutate job with resource name: '%s'.%n",batchJobResourceName);returnbatchJobResourceName;}

C#

privatestaticstringCreateBatchJob(BatchJobServiceClientbatchJobService,longcustomerId){BatchJobOperationoperation=newBatchJobOperation(){Create=newBatchJob(){}};stringbatchJobResourceName=batchJobService.MutateBatchJob(customerId.ToString(),operation).Result.ResourceName;Console.WriteLine($"Created a batch job with resource name: "+$"'{batchJobResourceName}'.");returnbatchJobResourceName;}

PHP

private static function createBatchJob(    BatchJobServiceClient $batchJobServiceClient,    int $customerId): string {    // Creates a batch job operation to create a new batch job.    $batchJobOperation = new BatchJobOperation();    $batchJobOperation->setCreate(new BatchJob());    // Issues a request to the API and get the batch job's resource name.    $batchJobResourceName = $batchJobServiceClient->mutateBatchJob(        MutateBatchJobRequest::build($customerId, $batchJobOperation)    )->getResult()->getResourceName();    printf(        "Created a batch job with resource name: '%s'.%s",        $batchJobResourceName,        PHP_EOL    );    return $batchJobResourceName;}

Python

defcreate_batch_job(batch_job_service,customer_id,batch_job_operation):"""Creates a batch job for the specified customer ID.    Args:        batch_job_service: an instance of the BatchJobService message class.        customer_id: a str of a customer ID.        batch_job_operation: a BatchJobOperation instance set to "create"    Returns: a str of a resource name for a batch job.    """try:response=batch_job_service.mutate_batch_job(customer_id=customer_id,operation=batch_job_operation)resource_name=response.result.resource_nameprint(f'Created a batch job with resource name "{resource_name}"')returnresource_nameexceptGoogleAdsExceptionasexception:handle_googleads_exception(exception)

Ruby

defcreate_batch_job(client,batch_job_service,customer_id)# Creates a batch job operation to create a new batch job.operation=client.operation.create_resource.batch_job# Issues a request to the API and get the batch job's resource name.response=batch_job_service.mutate_batch_job(customer_id:customer_id,operation:operation)batch_job_resource_name=response.result.resource_nameputs"Created a batch job with resource name: '#{batch_job_resource_name}'"batch_job_resource_nameend

Perl

subcreate_batch_job{my($batch_job_service,$customer_id)=@_;# Create a batch job operation.my$batch_job_operation=Google::Ads::GoogleAds::V20::Services::BatchJobService::BatchJobOperation->new({create=>Google::Ads::GoogleAds::V20::Resources::BatchJob->new({})});my$batch_job_resource_name=$batch_job_service->mutate({customerId=>$customer_id,operation=>$batch_job_operation})->{result}{resourceName};printf"Created a batch job with resource name: '%s'.\n",$batch_job_resource_name;return$batch_job_resource_name;}

curl

#Createsabatchjob.##Variables:#API_VERSION,#CUSTOMER_ID,#DEVELOPER_TOKEN,#MANAGER_CUSTOMER_ID,#OAUTH2_ACCESS_TOKEN:#Seehttps://developers.google.com/google-ads/api/rest/auth#request_headers#fordetails.curl -f --request POST \"https://googleads.googleapis.com/v${API_VERSION}/customers/${CUSTOMER_ID}/batchJobs:mutate" \--header "Content-Type: application/json" \--header "developer-token: ${DEVELOPER_TOKEN}" \--header "login-customer-id: ${MANAGER_CUSTOMER_ID}" \--header "Authorization: Bearer ${OAUTH2_ACCESS_TOKEN}" \--data @- <<EOF{  "operation": {    "create": {}  }}EOF

At this point in the process, thestatus ofthe job isPENDING.

Add one or more mutate operations to the batch job

Add one or moreMutateOperation to the batchjob created in the previous step by callingAddBatchJobOperations.Theresponse then contains thefollowing:

  • Total number of operations added so far for this job
  • Sequence token to be used when calling this method to add more operations

When you callAddBatchJobOperationsagain to add more operations, ensure you specify the previously obtainedsequence token in thesequence_tokenfield of arequest. If you callthe method using any sequence token other than the previously obtained one, itresults in an error.

sequence_token is also available asnext_add_sequence_token ofBatchJob, which you canretrieve later.

If you're creating dependent objects such as a complete campaign consisting ofa new campaign and corresponding ad groups, ads, and keywords, you canusetemporary IDs to specify aresource name.

Java

privatevoidaddAllBatchJobOperations(BatchJobServiceClientbatchJobServiceClient,longcustomerId,StringbatchJobResourceName){AddBatchJobOperationsResponseresponse=batchJobServiceClient.addBatchJobOperations(AddBatchJobOperationsRequest.newBuilder().setResourceName(batchJobResourceName).addAllMutateOperations(buildAllOperations(customerId)).build());System.out.printf("%d mutate operations have been added so far.%n",response.getTotalOperations());// You can use this next sequence token for calling addBatchJobOperations() next time.System.out.printf("Next sequence token for adding next operations is '%s'.%n",response.getNextSequenceToken());}

C#

privatestaticvoidAddAllBatchJobOperations(BatchJobServiceClientbatchJobService,longcustomerId,stringbatchJobResourceName){AddBatchJobOperationsResponseresponse=batchJobService.AddBatchJobOperations(newAddBatchJobOperationsRequest(){ResourceName=batchJobResourceName,MutateOperations={BuildAllOperations(customerId)}});Console.WriteLine($"{response.TotalOperations} mutate operations have been added"+$" so far.");// You can use this next sequence token for calling AddBatchJobOperations() next time.Console.WriteLine($"Next sequence token for adding next operations is "+$"'{response.NextSequenceToken}'.");}

PHP

private static function addAllBatchJobOperations(    BatchJobServiceClient $batchJobServiceClient,    int $customerId,    string $batchJobResourceName): void {    $response = $batchJobServiceClient->addBatchJobOperations(        AddBatchJobOperationsRequest::build(            $batchJobResourceName,            '',            self::buildAllOperations($customerId)        )    );    printf(        "%d mutate operations have been added so far.%s",        $response->getTotalOperations(),        PHP_EOL    );    // You can use this next sequence token for calling addBatchJobOperations() next time.    printf(        "Next sequence token for adding next operations is '%s'.%s",        $response->getNextSequenceToken(),        PHP_EOL    );}

Python

defadd_all_batch_job_operations(batch_job_service,operations,resource_name):"""Adds all mutate operations to the batch job.    As this is the first time for this batch job, we pass null as a sequence    token. The response will contain the next sequence token that we can use    to upload more operations in the future.    Args:        batch_job_service: an instance of the BatchJobService message class.        operations: a list of a mutate operations.        resource_name: a str of a resource name for a batch job.    """try:response=batch_job_service.add_batch_job_operations(resource_name=resource_name,sequence_token=None,mutate_operations=operations,)print(f"{response.total_operations} mutate operations have been ""added so far.")# You can use this next sequence token for calling# add_batch_job_operations() next time.print("Next sequence token for adding next operations is "f"{response.next_sequence_token}")exceptGoogleAdsExceptionasexception:handle_googleads_exception(exception)

Ruby

defadd_all_batch_job_operations(client,batch_job_service,customer_id,batch_job_resource_name)response=batch_job_service.add_batch_job_operations(resource_name:batch_job_resource_name,mutate_operations:build_all_operations(client,customer_id),)puts"#{response.total_operations} mutate operations have been added so far."# You can use this next sequence token for calling# add_all_batch_job_operations() next timeputs"Next sequence token for adding next operations is "\"'#{response.next_sequence_token}'"end

Perl

subadd_all_batch_job_operations{my($batch_job_service,$customer_id,$batch_job_resource_name)=@_;my$add_batch_job_operations_response=$batch_job_service->add_operations({resourceName=>$batch_job_resource_name,sequenceToken=>undef,mutateOperations=>build_all_operations($customer_id)});printf"%d batch operations have been added so far.\n",$add_batch_job_operations_response->{totalOperations};# You can use this next sequence token for calling add_operations() next time.printf"Next sequence token for adding next operations is '%s'.\n",$add_batch_job_operations_response->{nextSequenceToken};}

curl

#Addsoperationstoabatchjob.##Variables:#API_VERSION,#CUSTOMER_ID,#DEVELOPER_TOKEN,#MANAGER_CUSTOMER_ID,#OAUTH2_ACCESS_TOKEN:#Seehttps://developers.google.com/google-ads/api/rest/auth#request_headers#fordetails.#BATCH_JOB_RESOURCE_NAME:#Theresourcenameofthebatchjobtowhichtheoperationsshouldbeadded#asreturnedbythepreviousstep.curl -f --request POST \"https://googleads.googleapis.com/v${API_VERSION}/${BATCH_JOB_RESOURCE_NAME}:addOperations" \--header "Content-Type: application/json" \--header "developer-token: ${DEVELOPER_TOKEN}" \--header "login-customer-id: ${MANAGER_CUSTOMER_ID}" \--header "Authorization: Bearer ${OAUTH2_ACCESS_TOKEN}" \--data @- <<EOF{  "mutateOperations": [    {      "campaignBudgetOperation": {        "create": {          "resourceName": "customers/${CUSTOMER_ID}/campaignBudgets/-1",          "name": "batch job budget #${RANDOM}",          "deliveryMethod": "STANDARD",          "amountMicros": 5000000        }      }    },    {      "campaignOperation": {        "create": {          "advertisingChannelType": "SEARCH",          "status": "PAUSED",          "name": "batch job campaign #${RANDOM}",          "campaignBudget": "customers/${CUSTOMER_ID}/campaignBudgets/-1",          "resourceName": "customers/${CUSTOMER_ID}/campaigns/-2",          "manualCpc": {          }        }      },    }  ]}EOF

Click to see the content of the build operations function in GitHub for yourclient library:

Tip: The order of your operations can have a significant impact on your job'sperformance. Check out the tip on operation order inBestpractices.

Run the batch job

After adding all your operations, you can request the Google Ads API to run the batchjob by callingRunBatchJob on theuploaded operations.

Java

privateOperationFuturerunBatchJob(BatchJobServiceClientbatchJobServiceClient,StringbatchJobResourceName){OperationFutureoperationResponse=batchJobServiceClient.runBatchJobAsync(batchJobResourceName);// BEWARE! The above call returns an OperationFuture. The execution of that future depends on// the thread pool which is owned by batchJobServiceClient. If you use this future, you *must*// keep the service client in scope too.// See https://developers.google.com/google-ads/api/docs/client-libs/java/lro for more detail.System.out.printf("Mutate job with resource name '%s' has been executed.%n",batchJobResourceName);returnoperationResponse;}

C#

privateOperation<Empty,BatchJobMetadata>RunBatchJob(BatchJobServiceClientbatchJobService,stringbatchJobResourceName){Operation<Empty,BatchJobMetadata>operationResponse=batchJobService.RunBatchJob(batchJobResourceName);Console.WriteLine($"Batch job with resource name '{batchJobResourceName}' has been "+$"executed.");returnoperationResponse;}

PHP

private static function runBatchJob(    BatchJobServiceClient $batchJobServiceClient,    string $batchJobResourceName): OperationResponse {    $operationResponse =        $batchJobServiceClient->runBatchJob(RunBatchJobRequest::build($batchJobResourceName));    printf(        "Batch job with resource name '%s' has been executed.%s",        $batchJobResourceName,        PHP_EOL    );    return $operationResponse;}

Python

defrun_batch_job(batch_job_service,resource_name):"""Runs the batch job for executing all uploaded mutate operations.    Args:        batch_job_service: an instance of the BatchJobService message class.        resource_name: a str of a resource name for a batch job.    Returns: a google.api_core.operation.Operation instance.    """try:response=batch_job_service.run_batch_job(resource_name=resource_name)print(f'Batch job with resource name "{resource_name}" has been '"executed.")returnresponseexceptGoogleAdsExceptionasexception:handle_googleads_exception(exception)

Ruby

defrun_batch_job(batch_job_service,batch_job_resource_name)operation_response=batch_job_service.run_batch_job(resource_name:batch_job_resource_name,)puts"Batch job with resource name '#{batch_job_resource_name}' "\"has been executed."operation_responseend

Perl

subrun_batch_job{my($batch_job_service,$batch_job_resource_name)=@_;my$batch_job_lro=$batch_job_service->run({resourceName=>$batch_job_resource_name});printf"Batch job with resource name '%s' has been executed.\n",$batch_job_resource_name;return$batch_job_lro;}

curl

#Runsabatchjob.##Variables:#API_VERSION,#CUSTOMER_ID,#DEVELOPER_TOKEN,#MANAGER_CUSTOMER_ID,#OAUTH2_ACCESS_TOKEN:#Seehttps://developers.google.com/google-ads/api/rest/auth#request_headers#fordetails.#BATCH_JOB_RESOURCE_NAME:#Theresourcenameofthebatchjobtorunasreturnedbythepreviousstep.curl -f --request POST \"https://googleads.googleapis.com/v19/${BATCH_JOB_RESOURCE_NAME}:run" \--header "Content-Type: application/json" \--header "developer-token: ${DEVELOPER_TOKEN}" \--header "login-customer-id: ${MANAGER_CUSTOMER_ID}" \--header "Authorization: Bearer ${OAUTH2_ACCESS_TOKEN}" \--data @- <<EOF{}EOF

The returned response is an object of along-runningOperation(LRO). The LRO contains the metadata of your batchjob along with the information about the job status.

Poll the status of the batch job until it's done

The next step is to poll the status of the batch job using the LRO'sGetOperation until the LRO'sdone value istrue.

Java

privatevoidpollBatchJob(OperationFutureoperationResponse){try{operationResponse.get(MAX_TOTAL_POLL_INTERVAL_SECONDS,TimeUnit.SECONDS);}catch(InterruptedException|ExecutionException|TimeoutExceptione){System.err.printf("Failed polling the mutate job. Exception: %s%n",e);System.exit(1);}}

C#

privatestaticvoidPollBatchJob(Operation<Empty,BatchJobMetadata>operationResponse){PollSettingspollSettings=newPollSettings(Expiration.FromTimeout(TimeSpan.FromSeconds(MAX_TOTAL_POLL_INTERVAL_SECONDS)),TimeSpan.FromSeconds(1));operationResponse.PollUntilCompleted(pollSettings);}

PHP

private static function pollBatchJob(OperationResponse $operationResponse): void{    $operationResponse->pollUntilComplete([        'initialPollDelayMillis' => self::POLL_FREQUENCY_SECONDS * 1000,        'totalPollTimeoutMillis' => self::MAX_TOTAL_POLL_INTERVAL_SECONDS * 1000    ]);}

Python

defpoll_batch_job(operations_response,event):"""Polls the server until the batch job execution finishes.    Sets the initial poll delay time and the total time to wait before time-out.    Args:        operations_response: a google.api_core.operation.Operation instance.        event: an instance of asyncio.Event to invoke once the operations have            completed, alerting the awaiting calling code that it can proceed.    """loop=asyncio.get_event_loop()defdone_callback(future):# The operations_response object will call callbacks from a daemon# thread so we must use a threadsafe method of setting the event here# otherwise it will not trigger the awaiting code.loop.call_soon_threadsafe(event.set)# operations_response represents a Long-Running Operation or LRO. The class# provides an interface for polling the API to check when the operation is# complete. Below we use the asynchronous interface, but there's also a# synchronous interface that uses the Operation.result method.# See: https://googleapis.dev/python/google-api-core/latest/operation.htmloperations_response.add_done_callback(done_callback)

Ruby

defpoll_batch_job(operation_response)operation_response.wait_until_done!end

Perl

subpoll_batch_job{my($operation_service,$batch_job_lro)=@_;$operation_service->poll_until_done({name=>$batch_job_lro->{name},pollFrequencySeconds=>POLL_FREQUENCY_SECONDS,pollTimeoutSeconds=>POLL_TIMEOUT_SECONDS});}

curl

#Getsthestatusofabatchjob.##Variables:#API_VERSION,#CUSTOMER_ID,#DEVELOPER_TOKEN,#MANAGER_CUSTOMER_ID,#OAUTH2_ACCESS_TOKEN:#Seehttps://developers.google.com/google-ads/api/rest/auth#request_headers#fordetails.#BATCH_JOB_OPERATION_NAME:#Theoperationnameoftherunningbatchjobasreturnedbytheprevious#step.curl -f --request GET \"https://googleads.googleapis.com/v${API_VERSION}/${BATCH_JOB_OPERATION_NAME}" \--header "Content-Type: application/json" \--header "developer-token: ${DEVELOPER_TOKEN}" \--header "login-customer-id: ${MANAGER_CUSTOMER_ID}" \--header "Authorization: Bearer ${OAUTH2_ACCESS_TOKEN}" \

List all batch job results

When all of your batch jobs finish, useListBatchJobResults tolist their results, and print their statuses and responses:

Java

privatevoidfetchAndPrintResults(BatchJobServiceClientbatchJobServiceClient,StringbatchJobResourceName){System.out.printf("Mutate job with resource name '%s' has finished. Now, printing its results...%n",batchJobResourceName);// Gets all the results from running mutate job and prints their information.ListBatchJobResultsPagedResponsebatchJobResults=batchJobServiceClient.listBatchJobResults(ListBatchJobResultsRequest.newBuilder().setResourceName(batchJobResourceName).setPageSize(PAGE_SIZE).build());for(BatchJobResultbatchJobResult:batchJobResults.iterateAll()){System.out.printf("Mutate job #%d has a status '%s' and response of type '%s'.%n",batchJobResult.getOperationIndex(),batchJobResult.getStatus().getMessage().isEmpty()?"N/A":batchJobResult.getStatus().getMessage(),batchJobResult.getMutateOperationResponse().getResponseCase().equals(ResponseCase.RESPONSE_NOT_SET)?"N/A":batchJobResult.getMutateOperationResponse().getResponseCase());}}

C#

privatestaticvoidFetchAndPrintResults(BatchJobServiceClientbatchJobService,stringbatchJobResourceName){Console.WriteLine($"batch job with resource name '{batchJobResourceName}' has "+$"finished. Now, printing its results...");ListBatchJobResultsRequestrequest=newListBatchJobResultsRequest(){ResourceName=batchJobResourceName,PageSize=PAGE_SIZE,};ListBatchJobResultsResponseresp=newListBatchJobResultsResponse();// Gets all the results from running batch job and prints their information.foreach(BatchJobResultbatchJobResultinbatchJobService.ListBatchJobResults(request)){if(!batchJobResult.IsFailed){Console.WriteLine($"batch job result #{batchJobResult.OperationIndex} is "+$"successful and response is of type "+$"'{batchJobResult.MutateOperationResponse.ResponseCase}'.");}else{Console.WriteLine($"batch job result #{batchJobResult.OperationIndex} "+$"failed with error message {batchJobResult.Status.Message}.");foreach(GoogleAdsErrorerrorinbatchJobResult.Failure.Errors){Console.WriteLine($"Error found: {error}.");}}}}

PHP

private static function fetchAndPrintResults(    BatchJobServiceClient $batchJobServiceClient,    string $batchJobResourceName): void {    printf(        "Batch job with resource name '%s' has finished. Now, printing its results...%s",        $batchJobResourceName,        PHP_EOL    );    // Gets all the results from running batch job and print their information.    $batchJobResults = $batchJobServiceClient->listBatchJobResults(        ListBatchJobResultsRequest::build($batchJobResourceName)->setPageSize(self::PAGE_SIZE)    );    foreach ($batchJobResults->iterateAllElements() as $batchJobResult) {        /** @var BatchJobResult $batchJobResult */        printf(            "Batch job #%d has a status '%s' and response of type '%s'.%s",            $batchJobResult->getOperationIndex(),            $batchJobResult->getStatus()                ? $batchJobResult->getStatus()->getMessage() : 'N/A',            $batchJobResult->getMutateOperationResponse()                ? $batchJobResult->getMutateOperationResponse()->getResponse()                : 'N/A',            PHP_EOL        );    }}

Python

deffetch_and_print_results(client,batch_job_service,resource_name):"""Prints all the results from running the batch job.    Args:        client: an initialized GoogleAdsClient instance.        batch_job_service: an instance of the BatchJobService message class.        resource_name: a str of a resource name for a batch job.    """print(f'Batch job with resource name "{resource_name}" has finished. '"Now, printing its results...")list_results_request=client.get_type("ListBatchJobResultsRequest")list_results_request.resource_name=resource_namelist_results_request.page_size=1000# Gets all the results from running batch job and prints their information.batch_job_results=batch_job_service.list_batch_job_results(request=list_results_request)forbatch_job_resultinbatch_job_results:status=batch_job_result.status.messagestatus=statusifstatuselse"N/A"result=batch_job_result.mutate_operation_responseresult=resultor"N/A"print(f"Batch job #{batch_job_result.operation_index} "f'has a status "{status}" and response type "{result}"')

Ruby

deffetch_and_print_results(batch_job_service,batch_job_resource_name)puts"Batch job with resource name '#{batch_job_resource_name}' has "\"finished. Now, printing its results..."\# Gets all the results from running batch job and print their information.batch_job_results=batch_job_service.list_batch_job_results(resource_name:batch_job_resource_name,page_size:PAGE_SIZE,)batch_job_results.eachdo|result|puts"Batch job ##{result.operation_index} has a status "\"#{result.status?result.status.message:'N/A'} and response of type "\"#{result.mutate_operation_response?result.mutate_operation_response.response:'N/A'}"endend

Perl

subfetch_and_print_results{my($batch_job_service,$batch_job_resource_name)=@_;printf"Batch job with resource name '%s' has finished. "."Now, printing its results...\n",$batch_job_resource_name;# Get all the results from running batch job and print their information.my$list_batch_job_results_response=$batch_job_service->list_results({resourceName=>$batch_job_resource_name,pageSize=>PAGE_SIZE});foreachmy$batch_job_result(@{$list_batch_job_results_response->{results}}){printf"Batch job #%d has a status '%s' and response of type '%s'.\n",$batch_job_result->{operationIndex},$batch_job_result->{status}?$batch_job_result->{status}{message}:"N/A",$batch_job_result->{mutateOperationResponse}?[keys%{$batch_job_result->{mutateOperationResponse}}]->[0]:"N/A";}}

curl

#Getstheresultsofabatchjob.##Variables:#API_VERSION,#CUSTOMER_ID,#DEVELOPER_TOKEN,#MANAGER_CUSTOMER_ID,#OAUTH2_ACCESS_TOKEN:#Seehttps://developers.google.com/google-ads/api/rest/auth#request_headers#fordetails.#BATCH_JOB_RESOURCE_NAME:#Theoperationnameoftherunningbatchjobasreturnedbytheprevious#step.curl -f --request GET \"https://googleads.googleapis.com/v${API_VERSION}/${BATCH_JOB_RESOURCE_NAME}:listResults?pageSize=1000" \--header "Content-Type: application/json" \--header "developer-token: ${DEVELOPER_TOKEN}" \--header "login-customer-id: ${MANAGER_CUSTOMER_ID}" \--header "Authorization: Bearer ${OAUTH2_ACCESS_TOKEN}"

If the corresponding operation was successful, theresponse of themutate_operation_responsecontains the result with itsresource_name. In addition, the resource of theresult contains the modified resource with all of its mutable fields populatedifresponse_content_typeis set toMUTABLE_RESOURCE.

If the corresponding operation produced errors and can't be completed, themutate_operation_responsefield isnull.

Thestatus field ofBatchJobResult contains error details foreach failed operation.

Key Point: If you callListBatchJobResultsbefore callingRunBatchJob,an error is returned since no operations would have been processed.

Cancel a batch job

If necessary, you can attempt to cancel a batch job. Seecustomers.operations.cancel.

Error handling

BatchJobService automatically retries operations that fail due to transienterrors. However, not all failure scenarios can be avoided. Operations thatfailed due to validation errors can be fixed and resubmitted in a newbatch job. Operations that were cancelled can be retried by adding them to a newbatch job.

Except as otherwise noted, the content of this page is licensed under theCreative Commons Attribution 4.0 License, and code samples are licensed under theApache 2.0 License. For details, see theGoogle Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.

Last updated 2025-07-17 UTC.