The Ad Manager SOAP API is a legacy API for reading and writing your Ad Manager
data and running reports. If you can migrate, we recommend using the Ad Manager
API (Beta). However, Ad Manager SOAP API versions are supported for their
typical lifecycle. For more information, see the Ad Manager SOAP API
[Deprecation Schedule](https://developers.google.com/ad-manager/api/deprecation).

The following guide outlines differences between the Ad Manager SOAP
API and the Ad Manager API (Beta).

## Learn

The standard Ad Manager SOAP API service methods have equivalent
concepts in the Ad Manager API. The Ad Manager API also has methods for reading
single entities. In addition, state change actions that used a single
`perform<Entity>Action` method in the SOAP API now have dedicated methods for
each action type in the REST API.

The following table shows an example mapping for `Order` methods:

| SOAP method | REST methods |
|---|---|
| `createOrders` | `networks.orders.batchCreate` |
| `getOrdersByStatement` | `networks.orders.get` `networks.orders.list` |
| `updateOrders` | `networks.orders.batchUpdate` |
| `performOrderAction` | One method per action type. For example: `networks.orders.batchApprove` `networks.orders.batchPause` `networks.orders.batchResume` |

### State change action responses

In the SOAP API, `perform<Entity>Action` returned an `UpdateResult` object with
a `numChanges` field indicating how many entities were modified. In the Ad
Manager API (Beta), batch action methods return an empty response object. Check
for successful execution (an HTTP `200 OK` status or lack of an exception in
client libraries) to determine whether the action succeeded.

### Renamed and split services

Some services have been renamed or split in the Ad Manager API:

| SOAP service | REST resource / service |
|---|---|
| `InventoryService` | `networks.adUnits` |
| `MobileApplicationService` | `networks.applications` |
| `CustomTargetingService` | `networks.customTargetingKeys` `networks.customTargetingValues` |

## Authenticate

To authenticate with the Ad Manager API (Beta), you can use your existing
Ad Manager SOAP API credentials or create new ones. With either option, you must
first enable the
[Ad Manager API](https://console.cloud.google.com/apis/library/admanager.googleapis.com) in your
Google Cloud project. For more details, see
[Authentication](https://developers.google.com/ad-manager/api/beta/authentication).

If you are using a client library, set up application default credentials by
setting the environment variable `GOOGLE_APPLICATION_CREDENTIALS` to the path of
your service account key file. For more details, see
[How Application Default Credentials works](https://cloud.google.com/docs/authentication/application-default-credentials).

If you are using Installed Application credentials, create a JSON file
in the following format and set the environment variable to its path instead:

    {
      "client_id": "CLIENT_ID",
      "client_secret": "CLIENT_SECRET",
      "refresh_token": "REFRESH_TOKEN",
      "type": "authorized_user"
    }

Replace the following values:

- `CLIENT_ID`: Your new or existing client ID.
- `CLIENT_SECRET`: Your new or existing client secret.
- `REFRESH_TOKEN`: Your new or existing refresh
  token.

### Linux or macOS

    export GOOGLE_APPLICATION_CREDENTIALS=KEY_FILE_PATH

### Windows

    set GOOGLE_APPLICATION_CREDENTIALS=KEY_FILE_PATH

## Understand resource names

In the Ad Manager SOAP API, entities are identified by numeric `Long` IDs.
Entity relationships in SOAP also reference these numeric IDs.

In the Ad Manager API, entities are identified by standard **resource names**
formatted as strings:

    networks/{networkCode}/{collection}/{id}

For example, an order with ID `123456` in network `123` has the resource name
`networks/123/orders/123456`.

When migrating your code:

- Single-entity methods and batch action methods take resource name strings rather than numeric IDs.
- Entity relationships and foreign key references use resource names. For example, `Order.advertiser` is `networks/123/companies/456` instead of `Order.advertiserId`.
- The underlying ID space is unchanged from SOAP. You can extract the numeric ID from the last segment of the resource name.

## Understand update masks

In the Ad Manager SOAP API, update methods accepted full entity objects and
updated all modified fields.

In the Ad Manager API, update operations use **update masks**. An update mask
controls which fields are modified during an update:

- Only fields listed in the `updateMask` are modified. Fields omitted from the mask remain unchanged.
- If you don't specify an `updateMask`, all fields present in the request are updated.

For more information, see [Field Masks](https://developers.google.com/ad-manager/api/beta/field-masks).

## Understand filter differences

The Ad Manager API (Beta) query language supports all Publisher Query Language
(PQL) features, but significant syntax differences exist.

This example for listing `Order` objects illustrates the major changes such as
the removal of bind variables, case sensitive operators, and the replacement of
`ORDER BY` and `LIMIT` clauses with separate fields:

### Ad Manager SOAP API

    <filterStatement>
      <query>WHERE name like "PG_%" and lastModifiedDateTime &gt;= :lastModifiedDateTime ORDER BY id ASC LIMIT 500</query>
      <values>
        <key>lastModifiedDateTime</key>
        <value xmlns:ns2="https://www.google.com/apis/ads/publisher/v202502" xsi:type="ns2:DateTimeValue">
          <value>
            <date>
              <year>2024</year>
              <month>1</month>
              <day>1</day>
            </date>
            <hour>0</hour>
            <minute>0</minute>
            <second>0</second>
            <timeZoneId>America/New_York</timeZoneId>
          </value>
        </value>
      </values>
    </filterStatement>

### Ad Manager API (Beta)

JSON format

    {
      "filter": "displayName = \"PG_*\" AND updateTime > \"2024-01-01T00:00:00-5:00\"",
      "pageSize": 500,
      "orderBy":  "name"
    }

URL encoded

    GET https://admanager.googleapis.com/v1/networks/123/orders?filter=displayName+%3D+\"PG_*\"+AND+updateTime+%3E+\"2024-01-01T00%3A00%3A00-5%3A00\"

The Ad Manager API (Beta) supports all PQL capabilities, with the following
syntax differences from the Ad Manager SOAP API:

- The operators `AND` and `OR` are *case sensitive* in the
  Ad Manager API (Beta). Lowercase `and` and `or` are treated as bare
  literal search strings, a feature in the Ad Manager API (Beta) to search
  across fields.

  **Use uppercase operators**

      // Matches unarchived Orders where order.notes has the value 'lorem ipsum'.
      notes = "lorem ipsum" AND archived = false

  **Lowercase treated as literal**

      // Matches unarchived Orders where order.notes has the value 'lorem ipsum'
      // and any field in the order has the literal value 'and'.
      notes = "lorem ipsum" and archived = false

- The character `*` is a wildcard for string matching. The Ad Manager API (Beta)
  doesn't support the `like` operator.

  **Ad Manager SOAP API PQL**

      // Matches orders where displayName starts with the string 'PG_'
      displayName like "PG_%"

  **Ad Manager API (Beta)**

      // Matches orders where displayName starts with the string 'PG_'
      displayName = "PG_*"

- Field names must appear on the left-hand side of a comparison operator:

  **Valid filter**

      updateTime > "2024-01-01T00:00:00Z"

  **Invalid filter**

      "2024-01-01T00:00:00Z" < updateTime

- The Ad Manager API (Beta) does not support bind variables. All values must be
  inlined.

- String literals containing spaces must be wrapped in double quotes,
  for example, `"Foo bar"`. You can't use single quotes to wrap string literals.

### Understand field naming conventions

Field names in the Ad Manager API follow standardized REST and Google Cloud
conventions that differ from SOAP:

- **Display names:** The SOAP `name` field is renamed to `displayName` in the Ad Manager API. For example, `Order.name` is now `Order.displayName`, and `AdUnit.name` is now `AdUnit.displayName`.
- **Timestamps:** SOAP `DateTime` fields such as `lastModifiedDateTime` and `startDateTime` are replaced by RFC 3339 timestamp strings. `updateTime` and `startTime`.
- **Booleans:** Boolean fields drop prefixes like `is`. For example, `isArchived` is now `archived`.

### Remove order by clauses

Specifying a sorting order is optional in the Ad Manager API (Beta). If you
want to specify a sorting order for your result set, remove the PQL `ORDER BY`
clause and set the `orderBy` field instead:

    GET networks/${NETWORK_CODE}/orders?orderBy=updateTime+desc

> [!TIP]
> **Tip:** While the Ad Manager SOAP API recommends always including an `ORDER BY` clause to ensure pagination consistency, the Ad Manager API (Beta) maintains consistency with pagination tokens.

### Migrate from offsets to pagination tokens

The Ad Manager API (Beta) uses pagination tokens instead of `LIMIT` and `OFFSET`
clauses for paging through large result sets.

The Ad Manager API (Beta) uses a `pageSize` parameter to control the page size.
Unlike the `LIMIT` clause in the Ad Manager SOAP API, omitting a page size does
*not* return the entire result set. Instead, the list method uses a default page
size of `50`. The following example sets `pageSize` and `pageToken`
as URL parameters:

    # Initial request
    GET networks/${NETWORK_CODE}/orders?pageSize=50

    # Next page
    GET networks/${NETWORK_CODE}/orders?pageSize=50&pageToken=${TOKEN_FROM_INITIAL_REQUEST}

Unlike the Ad Manager SOAP API, the Ad Manager API (Beta) may return fewer
results than the requested page size even if there are additional pages. Use the
`nextPageToken` field to determine if there are additional
results.

Although an offset is not required for pagination, you may use the `skip`
field for multithreading. When multithreading, use the pagination token from the
first page to ensure you are reading from the same result set:

    # First thread
    GET networks/${NETWORK_CODE}/orders?pageSize=50&pageToken=${TOKEN_FROM_INITIAL_REQUEST}

    # Second thread
    GET networks/${NETWORK_CODE}/orders?pageSize=50&pageToken=${TOKEN_FROM_INITIAL_REQUEST}&skip=50

## Migrate reports

The SOAP API can only read and run reports in the deprecated Reports tool.
Conversely, the REST API can only read, write, and run Interactive Reports.

The reporting tools and APIs have a *different ID space* . The ID of a
`SavedQuery` in the SOAP API cannot be used in the REST API.

If you are using `SavedQuery`, you can migrate the report to an Interactive
report in the UI and create a mapping between the two ID spaces. For more
information about migrating reports in the UI, see
[Migrate reports to Interactive reports](https://support.google.com/admanager/answer/16071282#migrate).

For a complete mapping of SOAP to REST enum values, see
[Report reference](https://developers.google.com/ad-manager/api/beta/migration/report_reference).

### Understand API differences

There are some differences in how the SOAP API and REST API handle report
definitions and results:

- The SOAP API automatically added a corresponding `ID` dimension to the results
  when a report only requested the `NAME`. In the REST API, you must explicitly
  add the `ID` dimension to the `ReportDefinition` for it to be included in the
  results.

- The SOAP API did not have explicit types for metrics. The REST API defines
  a data type, documented on the [`Metric`](https://developers.google.com/ad-manager/api/beta/reference/rest/v1/networks.reports#Metric)
  and [`Dimension`](https://developers.google.com/ad-manager/api/beta/reference/rest/v1/networks.reports#Dimension)
  enum values. Note that `ENUM` dimensions are *open enums*. You must handle
  new and unknown enum values when parsing results.

- The SOAP API separated `Dimensions` and `DimensionAttributes`. The REST API
  has a unified `Dimension` enum that contains both.

- The SOAP API did not have a limit on the number of dimensions. Interactive
  Reports have a limit of 10 dimensions in both the UI and API. Dimensions that
  break down by the same ID space are counted as a single dimension. For
  example, including `ORDER_NAME`, `ORDER_ID`, and `ORDER_START_DATE` only
  counts as 1 dimension when calculating the limit.

## Handle errors

In the SOAP API, errors were returned as SOAP faults and handled using
`ApiException` with service-specific reason codes.

The Ad Manager API uses standard Google Cloud RPC and HTTP error models:

- Errors return standard HTTP status codes such as `400 INVALID_ARGUMENT`, `404 NOT_FOUND`, or `403 PERMISSION_DENIED`.
- Detailed API errors such as field violation reasons are returned in the error payload's error details.