# Synchronous Requests

The new Search Ads 360 Reporting API is now available. The new API provides enhanced flexibility to build custom reports and integrate the data into your reporting applications and processes. Learn more about migrating to and using the [new Search Ads 360 Reporting
API](https://developers.google.com/search-ads/reporting/overview). If you're requesting small to moderate advertiser or engine-account reports, you can
send just a single, synchronous report request. In response to the request, the Search Ads 360 API will return the entire report in a JSON object. Synchronous requests:

- Can return only [advertiser](https://developers.google.com/search-ads/v2/report-types/advertiser) and [engine account](https://developers.google.com/search-ads/v2/report-types/account) reports
- Block your client until Search Ads 360 generates the report


If you're requesting large advertiser or engine-account reports, we recommend the [asynchronous
approach](https://developers.google.com/search-ads/v2/how-tos/reporting/asynchronous-requests).

### To make a synchronous request


Call `https://developers.google.com/search-ads/v2/reference/reports/generate`
to specify the type of data you want in your [advertiser](https://developers.google.com/search-ads/v2/report-types/advertiser) or [engine account](https://developers.google.com/search-ads/v2/report-types/account) report.


Search Ads 360 validates the request, generates the report, and returns the report as a [Reports resource](https://developers.google.com/search-ads/v2/reference/reports#resource) in the
response body.

### Example synchronous request


The following is an example `https://developers.google.com/search-ads/v2/reference/reports/generate`
request.

### JSON

```
POST  https://www.googleapis.com/doubleclicksearch/v2/reports/generate
Authorization: Bearer your OAuth 2.0 access token
Content-type: application/json

{
  "reportScope": {
    "agencyId": "12300000000000456", // Replace with your ID
    "advertiserId": "21700000000011523", // Replace with your ID
    "engineAccountId": "700000000073991" // Replace with your ID
  },
  "reportType": "account",              // This report covers all revenue and visits in the
                                        // engine account specified in reportScope.
  "columns": [
    { "columnName": "date" },           // The date column segments the report by individual days.

    { "columnName": "dfaRevenue" },     // Here are some metric columns available for keyword
    {                                   // reports.
      "columnName": "visits",
      "startDate": "2013-01-01",        // Each metric column can optionally specify its own start 
      "endDate": "2013-01-31",          // and end date; by default the report timeRange is used.
      "headerText": "January visits"    // Every column can optionally specify a headerText, which
                                        // changes the name of the column in the report.
    }
  ],
  "timeRange" : {
    "startDate" : "2012-05-01",         // Dates are inclusive and specified in YYYY-MM-DD format.
    "endDate" : "2013-05-01"

    // Alternatively, try the "changedMetricsSinceTimestamp" or "changedAttributesSinceTimestamp"
    // options. See https://developers.google.com/search-ads/v2/how-tos/reporting/incremental-reports.

  },
  "statisticsCurrency": "agency",       // Required. See https://developers.google.com/search-ads/v2/how-tos/reporting#currency.
  "verifySingleTimeZone": false,        // Optional. Defaults to false. See https://developers.google.com/search-ads/v2/how-tos/reporting#time_zone.
  "includeRemovedEntities": false           // Optional. Defaults to false.
}
        
```

#### Use the Search Ads 360 utility script to send this request


To send a raw JSON POST request, you can use the [sa360Api.py
script](https://developers.google.com/search-ads/v2/prereqs#ds3py) as follows:

1. Copy the example JSON object (everything between and including the two curly brackets) into a new text file named `request.txt`.
2. Change the agency ID that's in the JSON code to your own agency ID.
3. Remove any comments, such as `// The date column segments the report by individual days.`
4. Assemble your OAuth 2.0 credentials into a single, comma-delimited string as follows:  
   `client-ID,client-secret,refresh-token`   
   (This is the same string that `sa360Api.py` outputs when you run `sa360Api.py
   --login` as described in [Set Up
   Authorization](https://developers.google.com/search-ads/v2/authorizing).)
5. Invoke `sa360Api.py` as follows:  
   `sa360Api.py --cred
   CREDENTIALS --server API-method --post < request.txt
   `  
   In the command above, substitute the string you assembled in the previous step for `CREDENTIALS`.   
   Substitute the name of the POST method in the box below for `API-method`.


   For example:  
   `sa360Api.py --cred
   123456789123.apps.googleusercontent.com,ABCDEFGHIJKLMNOPQR_abcdef,1/HIJklM01OPQR23NOP456rst890uvw
   --server https://www.googleapis.com/doubleclicksearch/v2/reports/generate --post < request.txt`

### Java

```
  public static void main(String[] args) throws Exception {
    Doubleclicksearch service = getService(); // See https://developers.google.com/search-ads/v2/configure.
    Report report = generateAccountReport(service);
    outputReport(report, "./");
  }

  /**
   * Creates an account report using the synchronous Report.generate method.
   *
   * @throws IOException
   */
  private static Report generateAccountReport(Doubleclicksearch service) throws IOException {
    try {
      return service.reports().generate(generateAccountRequest()).execute();
    } catch (GoogleJsonResponseException e) {
      System.err.println("Report request was rejected.");
      for (ErrorInfo error : e.getDetails().getErrors()) {
        System.err.println(error.getMessage());
      }
      System.exit(e.getStatusCode());
      return null; // Unreachable code.
    }
  }

  /**
   * Creates a simple static request that lists the clicks and visits for an engine account. Use
   * your own agency ID, advertiser ID, and engine account ID.
   */
  private static ReportRequest generateAccountRequest() {
    return new ReportRequest().setReportScope(
      new ReportScope()
        .setAgencyId(20700000000000451L) // Replace with your ID
        .setAdvertiserId(21700000000010391L) // Replace with your ID
        .setEngineAccountId(700000000042201L)) // Replace with your ID
        .setReportType("account")
        .setColumns(Arrays.asList(new ReportApiColumnSpec[] {
            new ReportApiColumnSpec().setColumnName("date"),
            new ReportApiColumnSpec().setColumnName("dfaRevenue"),
            new ReportApiColumnSpec()
                .setColumnName("visits")
                .setHeaderText("January visits")
                .setStartDate("2013-01-01")
                .setEndDate("2013-01-31"),}))
        .setTimeRange(new TimeRange()
          .setStartDate("2012-05-01")
          .setEndDate("2013-05-01"))
        .setStatisticsCurrency("agency");
  }

  /**
   * Outputs a synchronous report to a file.
   */
  private static void outputReport(Report report, String localPath)
      throws IOException {
    FileOutputStream outputStream = new FileOutputStream(new File(localPath, "Report"));
    final PrintStream printStream = new PrintStream(outputStream);
    printStream.print(report);
    printStream.close();
  }
        
```

### Python

```
def generate_report(service):
  """Generate and print sample report.

  Args:
    service: An authorized Doubleclicksearch service.  See Set Up Your Application.
  """
  request = service.reports().generate(
      body=
      {
        "reportScope
            "agencyId": "12300000000000456", // Replace with your ID
            "advertiserId": "21700000000011523", // Replace with your ID
            "engineAccountId": "700000000073991" // Replace with your ID
            },
        "reportType": "account",
        "columns": [
            { "columnName": "date" },
            { "columnName": "dfaRevenue" },
            {
              "columnName": "visits",
              "startDate": "2013-01-01",
              "endDate": "2013-01-31",
              "headerText": "January visits"
             }
        ],
        "timeRange" : {
            "startDate" : "2012-05-01",
            "endDate" : "2013-05-01"
        },
        "statisticsCurrency": "agency",
        "verifySingleTimeZone": "false",
        "includeRemovedEntities": "false"
        }
  )

  pprint.pprint(request.execute())
```

## Example report


The response to a synchronous request is a [report](https://developers.google.com/search-ads/v2/reference/reports) object.
If the request successfully validated, the first few properties in the object contain metadata that
describes the request you submitted. The report itself is in the object's `rows`
property.

```
{
  "kind":"doubleclicksearch#report",
  "request":{
    "columns":[
      {"columnName":"date"},
      {"columnName":"dfaRevenue"},
      {"columnName":"visits","endDate":"2013-01-31","headerText":"visits last month","startDate":"2013-01-01"}
    ],
    "includeDeletedEntities":false,
    "reportScope":{
      "agencyId":"12300000000000456",
      "advertiserId":"21700000000011523",
      "engineAccountId":"700000000073991"
     },
    "reportType":"account",
    "rowCount":10000,
    "startRow":0,
    "statisticsCurrency":"agency",
    "timeRange":{
      "endDate":"2013-05-01",
      "startDate":"2012-05-01"
     }
  },
  "rowCount":366,
  "rows":[
    {
      "date":"2012-05-01",
      "dfaRevenue":0.0,
      "visits last month":0.0
    },
    {
      "date":"2012-05-02",
      "dfaRevenue":0.0,
      "visits last month":0.0
    },
    {
      "date":"2012-05-03",
      "dfaRevenue":0.0,
      "visits last month":0.0
    },
    {
      "date":"2012-05-04",
      "dfaRevenue":0.0,
      "visits last month":0.0
     },
     ...
  ]
}
        
```

#### If validation fails


If the report does not pass validation, Search Ads 360 returns an HTTP `400` response
with an error object. For example, the example request above did not specify a real
agency:

```
{
 "error": {
   "code": 400,
   "message": "statisticsCurrency: the agency in scope does not have a valid currency. Please make sure the agency is properly initialized in Search Ads 360."
 }
}
```

## Splitting synchronous reports into multiple responses


By default, a synchronous request returns the first 10000 rows. To change that behavior,
use the `https://developers.google.com/search-ads/v2/reference/reports#request.startRow`
and `https://developers.google.com/search-ads/v2/reference/reports#request.rowCount`
properties to retrieve specific parts of the report with each request.

### Example of splitting a synchronous report

For example, this request will return the first hundred rows (0 through 99) of an agency report
that's segmented by day:

```
{
  "reportScope": {
    "agencyId": "12300000000000456", // Replace with your ID
    "advertiserId": "21700000000011523", // Replace with your ID
    "engineAccountId": "700000000073991" // Replace with your ID
  },
  "reportType": "account",
  "columns": [
    { "columnName": "date" },
    { "columnName": "dfaRevenue" }
  ],
  "timeRange" : {
    "startDate" : "2012-05-01",
    "endDate" : "2013-05-01"
  },
  "startRow":"0",
  "rowCount":"100",
  "statisticsCurrency": "agency",
  "verifySingleTimeZone": false,
  "includeRemovedEntities": false
}
    
```

You can follow this request with another request for rows 100 to 199:

```
{
  "reportScope": {
    "agencyId": "12300000000000456", // Replace with your ID
    "advertiserId": "21700000000011523", // Replace with your ID
    "engineAccountId": "700000000073991" // Replace with your ID
  },
  "reportType": "account",
  "columns": [
    { "columnName": "date" },
    { "columnName": "dfaRevenue" }
  ],
  "timeRange" : {
    "startDate" : "2012-05-01",
    "endDate" : "2013-05-01"
  },
  "startRow":"100",
  "rowCount":"100",
  "statisticsCurrency": "agency",
  "verifySingleTimeZone": false,
  "includeRemovedEntities": false
}
    
```