-
Notifications
You must be signed in to change notification settings - Fork 200
NoClientLibrary
We recommend using the Ads API .NET library to make calls to the AdWords API and Google Ad Manager API with .NET languages (C#, VB.NET, etc.). But in case you don't want to use the client library, but rather want to write your own custom solution, this document explains how you can get that done. All the code samples are written in C#, but can be easily translated to VB.NET or Managed C++.
All the Ads APIs use OAuth2 as its primary authentication mechanism. We support Web flow, Installed application flow and service account flows when using OAuth2. You can learn more about Google's support of OAuth2 at https://developers.google.com/accounts/docs/OAuth2.
The OAuth2 scopes for various Ads APIs are as follows:
API | OAuth2 Scope |
---|---|
AdWords API | https://www.googleapis.com/auth/adwords |
Google Ad Manager API | https://www.googleapis.com/auth/dfp |
We recommend using an open source implementation of OAuth2 like DotNet OpenAuth instead of implementing the OAuth2 protocol on your own.
If you want to stick to raw HTTP calls and choose not to use SOAP code generators (like wsdl.exe
) or any SOAP framework provided by Microsoft .NET, then you can construct the raw SOAP xml and POST it to the appropriate webservice endpoint. Some examples are given below:
private static void GetAllCampaigns() {
string accessToken = GetOAuth2AccessToken();
string requestXml = string.Format(@"
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Header>
<RequestHeader xmlns="https://adwords.google.com/api/adwords/cm/v201806">
<developerToken xmlns="https://adwords.google.com/api/adwords/cm/v201806">{0}</developerToken>
<clientCustomerId xmlns="https://adwords.google.com/api/adwords/cm/v201806">{1}</clientCustomerId>
<userAgent xmlns="https://adwords.google.com/api/adwords/cm/v201806">{2}</userAgent>
</RequestHeader>
</soap:Header>
<soap:Body>
<get xmlns="https://adwords.google.com/api/adwords/cm/v201806">
<serviceSelector>
<fields>Id</fields>
<fields>Name</fields>
<fields>Status</fields>
<paging>
<startIndex>0</startIndex>
<numberResults>500</numberResults>
</paging>
</serviceSelector>
</get>
</soap:Body>
</soap:Envelope>",
"INSERT_CLIENT_CUSTOMER_ID_HERE",
"INSERT_DEVELOPER_TOKEN_HERE",
"INSERT_USERAGENT_HERE").Trim();
WebRequest webRequest = HttpWebRequest.Create(
"https://adwords.google.com/api/adwords/cm/v201806/CampaignService");
webRequest.Method = "POST";
webRequest.ContentType = "text/xml; charset=utf-8";
webRequest.Headers.Add("SOAPAction", "");
if (accessToken != null) {
webRequest.Headers.Add("Authorization", "Bearer " + accessToken);
}
byte[] postBytes = Encoding.UTF8.GetBytes(requestXml);
webRequest.ContentLength = postBytes.Length;
using (Stream strmReq = webRequest.GetRequestStream()) {
strmReq.Write(postBytes, 0, postBytes.Length);
}
try {
WebResponse response = webRequest.GetResponse();
using (StreamReader reader = new StreamReader(response.GetResponseStream())) {
string responseXml = reader.ReadToEnd();
XmlDocument xDoc = new XmlDocument();
xDoc.LoadXml(responseXml);
XmlNamespaceManager xmlns = new XmlNamespaceManager(xDoc.NameTable);
xmlns.AddNamespace("soap", "http://schemas.xmlsoap.org/soap/envelope/");
xmlns.AddNamespace("v201806", "https://adwords.google.com/api/adwords/cm/v201806");
XmlElement faultNode =
(XmlElement) xDoc.SelectSingleNode("soap:Envelope/soap:Body/soap:Fault",
xmlns);
if (faultNode != null) {
// Something went wrong with API call. Parse faultNode for more details.
} else {
XmlElement mutateResponseNode = (XmlElement) xDoc.SelectSingleNode(
"soap:Envelope/soap:Body/v201605:mutateResponse", xmlns);
// Parse mutateResponseNode contents to get the campaign id.
}
}
} catch (WebException ex) {
throw new ApplicationException("Could not make Api call.", ex);
}
}
private static void GetUsers() {
string accessToken = GetOAuth2AccessToken();
string NETWORK_CODE = "INSERT_YOUR_NETWORK_CODE_HERE";
string APPLICATION_NAME = "INSERT_YOUR_APPLICATION_NAME_HERE";
string requestXml = string.Format(@"
<?xml version='1.0' encoding='utf-8'?>
<soap:Envelope xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/'
xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
xmlns:xsd='http://www.w3.org/2001/XMLSchema'>
<soap:Header>
<RequestHeader xmlns='https://www.google.com/apis/ads/publisher/v201808'>
<networkCode xmlns='https://www.google.com/apis/ads/publisher/v201808'>{0}</networkCode>
<applicationName xmlns='https://www.google.com/apis/ads/publisher/v201808'>{1}</applicationName>
</RequestHeader>
</soap:Header>
<soap:Body>
<getUsersByStatement xmlns='https://www.google.com/apis/ads/publisher/v201808'>
<filterStatement>
<query>LIMIT 500 OFFSET 0</query>
</filterStatement>
</getUsersByStatement>
</soap:Body>
</soap:Envelope>",
NETWORK_CODE, APPLICATION_NAME).Trim();
WebRequest webRequest = HttpWebRequest.Create("https://ads.google.com/apis/ads/publisher/v201808/UserService");
webRequest.Method = "POST";
webRequest.ContentType = "text/xml; charset=utf-8";
webRequest.Headers.Add("SOAPAction", "");
webRequest.Headers.Add("Authorization", string.Format("Bearer {0}", accessToken));
byte[] postBytes = Encoding.UTF8.GetBytes(requestXml);
webRequest.ContentLength = postBytes.Length;
using (Stream strmReq = webRequest.GetRequestStream()) {
strmReq.Write(postBytes, 0, postBytes.Length);
}
try {
WebResponse response = webRequest.GetResponse();
using (StreamReader reader = new StreamReader(response.GetResponseStream())) {
string responseXml = reader.ReadToEnd();
XmlDocument xDoc = new XmlDocument();
xDoc.LoadXml(responseXml);
XmlNamespaceManager xmlns = new XmlNamespaceManager(xDoc.NameTable);
xmlns.AddNamespace("soap", "http://schemas.xmlsoap.org/soap/envelope/");
xmlns.AddNamespace("v201808", "https://www.google.com/apis/ads/publisher/v201808");
XmlElement faultNode =
(XmlElement) xDoc.SelectSingleNode("soap:Envelope/soap:Body/soap:Fault", xmlns);
if (faultNode != null) {
// Something went wrong with API call. Parse faultNode for more details.
} else {
XmlElement mutateResponseNode = (XmlElement) xDoc.SelectSingleNode(
"soap:Envelope/soap:Body/v201605:getUsersByStatementResponse", xmlns);
// Parse mutateResponseNode contents to get the campaign id.
}
}
} catch (WebException ex) {
throw new ApplicationException("Could not make Api call.", ex);
}
}
This is the approach taken by most developers, given the amount of support that Microsoft .NET framework provides for making SOAP calls. However, Visual Studio doesn't generate a stub class that can readily be used by a C# program for AdWords and Google Ad Manager APIs. You need to edit the auto-generated code by hand to make it work properly with your code. A detailed discussion of the required changes and workarounds is beyond the scope of this guide.
To download reports from Google Ads servers, you should send a POST
request to https://adwords.google.com/api/adwords/reportdownload/{version}
with an authorization header that contains a valid OAuth2 access token, a developerToken
header that contains your approved developer token, and a clientCustomerId
header that contains the customerId of the client for which this report definition was generated. Also, the POST body should contain the report definition xml as rdxml=url_encoded_report_definition_xml
. The code snippet is given below.
public bool DownloadReportDefinition(string reportDefinitionXml,
string accessToken, string clientCustomerId, string developerToken,
string filePath, string version) {
Uri downloadUrl =
new Uri("https://adwords.google.com/api/adwords/reportdownload/" +
version);
WebRequest request = HttpWebRequest.Create(downloadUrl);
request.Headers.Add("clientCustomerId: " + clientCustomerId);
request.Headers.Add("developerToken: " + developerToken);
request.Headers.Add("Authorization: Bearer " + accessToken);
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
using (StreamWriter writer = new StreamWriter(request.GetRequestStream())) {
writer.Write("__rdxml=" + HttpUtility.UrlEncode(reportDefinitionXml));
}
WebResponse response = null;
bool success = false;
try {
response = request.GetResponse();
success = true;
} catch (WebException ex) {
// The server will return an error code other than 200 if something
// goes wrong. The actual reason fo failure can be found by reading
// the response.
response = ex.Response;
}
DownloadReportToFile(filePath, response);
return success;
}
private static void DownloadReportToFile(string filePath, WebResponse response) {
FileStream outputStream = File.Create(filePath);
using (Stream responseStream = response.GetResponseStream()) {
CopyStream(responseStream, outputStream);
}
outputStream.Close();
}
private static void CopyStream(Stream sourceStream, Stream targetStream) {
int bufferSize = 2 << 20;
byte[] buffer = new byte[bufferSize];
int bytesRead = 0;
while ((bytesRead = sourceStream.Read(buffer, 0, bufferSize)) != 0) {
targetStream.Write(buffer, 0, bytesRead);
}
}
The report definition xml should match the serialized form of ReportDefinition
type. You could generate a stub class for this type from https://adwords.google.com/api/adwords/reportdownload/{version}/reportDefinition.xsd