Get statistics for agency clients

Python version 2 or 3 using JSON with the Requests library

This example shows how to use the AgencyClients.get method to get a list of agency clients and then execute requests to the Reports service to get statistics for advertiser accounts for the past day. The mode for generating the report is selected automatically. If the report is added to the queue in offline mode, repeated requests are made.

To use the example, specify the OAuth access token that you received for the agency representative in the input data.

# -*- coding: utf-8 -*-
import requests
from requests.exceptions import ConnectionError
from time import sleep
import json
from datetime import date, timedelta
from time import time

# Method for correctly parsing UTF-8 encoded strings for both Python 3 and Python 2
import sys

if sys.version_info < (3,):
    def u(x):
        try:
            return x.encode("utf8")
        except UnicodeDecodeError:
            return x
else:
    def u(x):
        if isinstance(x, bytes):
            return x.decode('utf8')
        else:
            return x

# --- Input data ---
# Address of the AgencyClients service for sending JSON requests (case-sensitive)
AgencyClientsURL = 'https://api.direct.yandex.com/json/v5/agencyclients'

# Address of the Reports service for sending JSON requests (case-sensitive)
ReportsURL = 'https://api.direct.yandex.com/json/v5/reports'

# OAuth token of the agency representative that requests will be made on behalf of
token = 'TOKEN'

# --- Preparing the request to the AgencyClients service ---
# Creating HTTP request headers
headers = {
           # OAuth token. The word Bearer must be used
           "Authorization": "Bearer " + token,
           # Language for response messages
           "Accept-Language": "en"
           }

AgencyClientsBody = {
    "method": "get",
    "params": {
        "SelectionCriteria": {
            "Archived": "NO"   # Get only active clients
        },
        "FieldNames": ["Login"],
        "Page": {
            "Limit": 10000,  # Get a maximum of 10,000 clients in the server response
            "Offset": 0
        }
    }
}

# --- Executing requests to the AgencyClients service ---
# If LimitedBy is not in the response, it means that
# all clients were received.
HasAllClientLoginsReceived = False
ClientList = []

while not HasAllClientLoginsReceived:
    ClientsResult = requests.post(AgencyClientsURL, json.dumps(AgencyClientsBody), headers=headers).json()
    for Client in ClientsResult['result']['Clients']:
        ClientList.append(Client["Login"])
    if ClientsResult['result'].get("LimitedBy", False):
        AgencyClientsBody['Page']['Offset'] = ClientsResult['result']["LimitedBy"]
    else:
        HasAllClientLoginsReceived = True

# --- Preparing a request to the Reports service ---
# Creating the request body
# The report contains the number of impressions, clicks and spending for all the client's campaigns.
body = {
    "params": {
        "SelectionCriteria": {},
        "FieldNames": [
            "Impressions",
            "Clicks",
            "Cost"
        ],
        "ReportName": u("ACCOUNT_PERFORMANCE"),
        "ReportType": "ACCOUNT_PERFORMANCE_REPORT",
        "DateRangeType": "AUTO",
        "Format": "TSV",
        "IncludeVAT": "NO",
        "IncludeDiscount": "NO"
    }
}

# Creating output data
resultcsv = "Login;Impressions;Clicks;Costs\n"

# Additional HTTP headers for requesting reports
headers['skipReportHeader'] = "true"
headers['skipColumnHeader'] = "true"
headers['skipReportSummary'] = "true"
headers['returnMoneyInMicros'] = "false"

# --- Executing requests to the Reports service ---
for Client in ClientList:
    # Adding the "Client-Login" HTTP header
    headers['Client-Login'] = Client
    # Encoding the request body as JSON
    requestBody = json.dumps(body, indent=4)
    # Starting the request execution loop
    # If the HTTP 200 response is received, the report content is added to the output data
    # If the HTTP 201 or 202 response is received, repeated requests are sent
    while True:
        try:
            req = requests.post(ReportsURL, requestBody, headers=headers)
            req.encoding = 'utf-8'  # Force handling the response in UTF-8 encoding
            if req.status_code == 400:
                print("Invalid request parameters, or the report queue has reached the limit")
                print("RequestId: {}".format(req.headers.get("RequestId", False)))
                print("JSON code of the request: {}".format(u(body)))
                print("JSON code of the server response: \n{}".format(u(req.json())))
                break
            elif req.status_code == 200:
                print("Report for account {} created".format(str(Client)))
                print("RequestId: {}".format(req.headers.get("RequestId", False)))
                if req.text != "":
                    tempresult = req.text.split('\t')
                    resultcsv += "{};{};{};{}\n".format(Client, tempresult[0], tempresult[1], str(tempresult[2]).replace('.', ','))
                else:
                    resultcsv += "{};0;0;0\n".format(Client)
                break
            elif req.status_code == 201:
                print("Report for account {} added to the queue in offline mode".format(str(Client)))
                retryIn = int(req.headers.get("retryIn", 60))
                print("Resend the request in {} seconds".format(retryIn))
                print("RequestId: {}".format(req.headers.get("RequestId", False)))
                sleep(retryIn)
            elif req.status_code == 202:
                print("Report will be generated in offline mode".format(str(Client)))
                retryIn = int(req.headers.get("retryIn", 60))
                print("Repeat the request in {} seconds".format(retryIn))
                print("RequestId: {}".format(req.headers.get("RequestId", False)))
                sleep(retryIn)
            elif req.status_code == 500:
                print("Error generating the report. Please repeat the request again later.")
                print("RequestId: {}".format(req.headers.get("RequestId", False)))
                print("JSON code for the server response: \n{}".format(u(req.json())))
                break
            elif req.status_code == 502:
                print("Exceeded the server limit on report creation time.")
                print(
                    "Please try changing the request parameters: reduce the time period and the amount of data requested.")
                print("JSON code for the request: {}".format(body))
                print("RequestId: {}".format(req.headers.get("RequestId", False)))
                print("JSON code for the server response: \n{}".format(u(req.json())))
                break
            else:
                print("Unexpected error")
                print("RequestId: {}".format(req.headers.get("RequestId", False)))
                print("JSON code for the request: {}".format(body))
                print("JSON code for the server response: \n{}".format(u(req.json())))
                break

        # Error handling if the connection with the Yandex.Direct API server could not be established
        except ConnectionError:
            # In this case, we recommend repeating the request again later
            print("Error connecting to the Yandex.Direct API server")
            # Forced exit from loop
            break

        # If any other error occurred
        except:
            # In this case, we recommend analyzing the application's actions
            print("Unexpected error")
            # Forced exit from loop
            break

print("Finished creating reports for accounts")

# Creating and saving the file
filename = "AccountsPerfomanceReport_{}.csv".format(str(time()))
resultfile = open(filename, 'w+')
resultfile.write(resultcsv)
resultfile.close()

print("Results are saved in the file {}".format(filename))