To mutate multiple resource types in a single request or send all mutations to a
unified endpoint, use [`GoogleAdsService.Mutate`](https://developers.google.com/google-ads/api/reference/rpc/v26/GoogleAdsService/Mutate). For the complete
list of supported operations, see the [`MutateOperation`](https://developers.google.com/google-ads/api/reference/rpc/v26/MutateOperation) reference.

## Mutate operations

Each [`MutateGoogleAdsRequest`](https://developers.google.com/google-ads/api/reference/rpc/v26/MutateGoogleAdsRequest) accepts a repeated
[`MutateOperation`](https://developers.google.com/google-ads/api/reference/rpc/v26/MutateOperation) in its `mutate_operations` field:

- **Resource mutate operations:** Each entry can specify a single `create`, `update`, or `remove` operation for one resource type.
- **Action operations:** Each entry can also specify an action operation, such as [`book_campaigns_operation`](https://developers.google.com/google-ads/api/reference/rpc/v26/MutateOperation#book_campaigns_operation) or [`quote_campaigns_operation`](https://developers.google.com/google-ads/api/reference/rpc/v26/MutateOperation#quote_campaigns_operation).

To create dependent entities (such as a campaign and an ad group) in a single
[`GoogleAdsService.Mutate`](https://developers.google.com/google-ads/api/reference/rpc/v26/GoogleAdsService/Mutate) call, create two
[`MutateOperation`](https://developers.google.com/google-ads/api/reference/rpc/v26/MutateOperation) entries (one containing a
[`CampaignOperation`](https://developers.google.com/google-ads/api/reference/rpc/v26/CampaignOperation) and another containing an
[`AdGroupOperation`](https://developers.google.com/google-ads/api/reference/rpc/v26/AdGroupOperation)). Assign a [temporary resource
name](https://developers.google.com/google-ads/api/docs/mutating/best-practices#temporary-resource-names) with a negative
ID (such as `customers/CUSTOMER_ID/campaigns/-1`) to the campaign so the ad
group operation can reference it in the same request:

### Python

```python
import uuid

campaign_budget_service = client.get_service("CampaignBudgetService")
campaign_service = client.get_service("CampaignService")
googleads_service = client.get_service("GoogleAdsService")

campaign_budget_resource_name = campaign_budget_service.campaign_budget_path(
    customer_id, budget_id
)
temp_campaign_resource_name = campaign_service.campaign_path(customer_id, "-1")

mutate_operation1 = client.get_type("MutateOperation")
campaign = mutate_operation1.campaign_operation.create
campaign.resource_name = temp_campaign_resource_name
campaign.name = f"Bulk Mutate Campaign #{uuid.uuid4()}"
campaign.advertising_channel_type = (
    client.enums.AdvertisingChannelTypeEnum.SEARCH
)
campaign.status = client.enums.CampaignStatusEnum.PAUSED
campaign.manual_cpc = client.get_type("ManualCpc")
campaign.campaign_budget = campaign_budget_resource_name
campaign.contains_eu_political_advertising = (
    client.enums.EuPoliticalAdvertisingStatusEnum.DOES_NOT_CONTAIN_EU_POLITICAL_ADVERTISING
)

mutate_operation2 = client.get_type("MutateOperation")
ad_group = mutate_operation2.ad_group_operation.create
ad_group.name = "Bulk Mutate Ad Group"
ad_group.campaign = temp_campaign_resource_name
ad_group.status = client.enums.AdGroupStatusEnum.ENABLED

response = googleads_service.mutate(
    customer_id=customer_id,
    mutate_operations=[mutate_operation1, mutate_operation2],
)

for op_response in response.mutate_operation_responses:
    result_type = op_response._pb.WhichOneof("response")
    result = getattr(op_response, result_type)
    print(f"Created {result_type}: {result.resource_name}")
```

### Ruby

```ruby
campaign_budget_resource_name =
  client.path.campaign_budget(customer_id, budget_id)
temp_campaign_resource_name =
  client.path.campaign(customer_id, -1)

mutate_operation1 = client.operation.mutate do |m|
  m.campaign_operation = client.operation.create_resource.campaign do |c|
    c.resource_name = temp_campaign_resource_name
    c.name = "Bulk Mutate Campaign #{(Time.new.to_f * 1000).to_i}"
    c.advertising_channel_type = :SEARCH
    c.status = :PAUSED
    c.manual_cpc = client.resource.manual_cpc
    c.campaign_budget = campaign_budget_resource_name
    c.contains_eu_political_advertising = :DOES_NOT_CONTAIN_EU_POLITICAL_ADVERTISING
  end
end

mutate_operation2 = client.operation.mutate do |m|
  m.ad_group_operation = client.operation.create_resource.ad_group do |ag|
    ag.name = "Bulk Mutate Ad Group"
    ag.campaign = temp_campaign_resource_name
    ag.status = :ENABLED
  end
end

response = client.service.google_ads.mutate(
  customer_id: customer_id,
  mutate_operations: [mutate_operation1, mutate_operation2]
)

response.mutate_operation_responses.each do |op_response|
  result = op_response.send(op_response.response)
  puts "Created #{op_response.response}: #{result.resource_name}"
end
```

## Atomicity and partial failure

By default, operations in a [`GoogleAdsService.Mutate`](https://developers.google.com/google-ads/api/reference/rpc/v26/GoogleAdsService/Mutate) request
execute atomically: all operations succeed together, or the entire request fails
if any operation contains an error.

Like individual resource services, this endpoint supports the following options:

- **[Partial failure](https://developers.google.com/google-ads/api/docs/best-practices/partial-failures)
  (`partial_failure = true`):** Commits valid operations and returns errors for failed operations in `partial_failure_error`.
- **Validation mode (`validate_only = true`):** Checks operations for errors without committing changes to the account:
  - **Resource mutate operations:** Returns only validation errors and omits results.
  - **Action operations:** Returns the action result (such as `quote_campaigns_result` or `book_campaigns_result`) when validation succeeds; if validation errors occur, the action result is omitted from `MutateOperationResponse` (though a quote may still be returned in `ErrorDetails.reservation_error_details`). Note that [`quote_campaigns_operation`](https://developers.google.com/google-ads/api/reference/rpc/v26/MutateOperation#quote_campaigns_operation) requires `validate_only = true` and `partial_failure = false`.