0

I've been able to get this far without knowing about XML since the Savon gem translates Ruby code into XML, but now I'm stuck. I'm requesting a CampaignPerformanceReport from the API and I'm able to successfully retrieve the data I need, but now I need to add a filter to only get 'Paused' campaigns.

Following this documentation I sent this message to the API:

<env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tns="https://bingads.microsoft.com/Reporting/v13" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns="https://bingads.microsoft.com/Reporting/v13">
  <env:Header>
    <AuthenticationToken>foo</AuthenticationToken>
    <CustomerAccountId>foo</CustomerAccountId>
    <CustomerId>foo</CustomerId>
    <DeveloperToken>foo</DeveloperToken>
  </env:Header>
  <env:Body>
    <tns:SubmitGenerateReportRequest>
      <ReportRequest xsi:nil="false" xsi:type="CampaignPerformanceReportRequest">
        <ExcludeColumnHeaders>true</ExcludeColumnHeaders>
        <ExcludeReportFooter>true</ExcludeReportFooter>
        <ExcludeReportHeader>true</ExcludeReportHeader>
        <Format>Csv</Format>
        <Language>English</Language>
        <ReportName>CampaignPerformanceReportRequest</ReportName>
        <ReturnOnlyCompleteData>false</ReturnOnlyCompleteData>
        <Aggregation>Summary</Aggregation>
        <Columns>
          <CampaignPerformanceReportColumn>CampaignName</CampaignPerformanceReportColumn>
          <CampaignPerformanceReportColumn>CampaignStatus</CampaignPerformanceReportColumn>
          <CampaignPerformanceReportColumn>Spend</CampaignPerformanceReportColumn>
          <CampaignPerformanceReportColumn>Impressions</CampaignPerformanceReportColumn>
          <CampaignPerformanceReportColumn>Clicks</CampaignPerformanceReportColumn>
          <CampaignPerformanceReportColumn>Conversions</CampaignPerformanceReportColumn>
          <CampaignPerformanceReportColumn>Revenue</CampaignPerformanceReportColumn>
          <CampaignPerformanceReportColumn>PhoneCalls</CampaignPerformanceReportColumn>
        </Columns>
        <Filter>
          <CampaignStatusReportFilter>Paused</CampaignStatusReportFilter>
        </Filter>
        <Scope>
          <AccountIds xmlns:a1="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
            <a1:long>foo</a1:long>
          </AccountIds>
        </Scope>
        <Time>
          <CustomDateRangeEnd>
            <Day>31</Day>
            <Month>01</Month>
            <Year>2019</Year>
          </CustomDateRangeEnd>
          <CustomDateRangeStart>
            <Day>01</Day>
            <Month>01</Month>
            <Year>2019</Year>
          </CustomDateRangeStart>
          <PredefinedTime xsi:nil="true"/>
          <ReportTimeZone>EasternTimeUSCanada</ReportTimeZone>
        </Time>
      </ReportRequest>
    </tns:SubmitGenerateReportRequest>
  </env:Body>
</env:Envelope>

The request is accepted and processed, but the data that is returned shows only 'Active' campaigns. I'm sure there is an issue with the way I'm filtering. Here is the Ruby code I'm using to generate the request.

report_request = {
      '@xsi:nil' => false,
      '@xsi:type' => 'CampaignPerformanceReportRequest',
      'ExcludeColumnHeaders' => true,
      'ExcludeReportFooter' => true,
      'ExcludeReportHeader' => true,
      'Format' => 'Csv',
      'Language' => 'English',
      'ReportName' => 'CampaignPerformanceReportRequest',
      'ReturnOnlyCompleteData' => false,
      'Aggregation' => 'Summary',
      'Columns' => {
         'CampaignPerformanceReportColumn' => [
           'CampaignName',
           'CampaignStatus',
           'Spend',
           'Impressions',
           'Clicks',
           'Conversions',
           'Revenue',
           'PhoneCalls'
         ]
      },
      'Filter' => { 'CampaignStatusReportFilter' => 'Paused' },
      'Scope' => {
        'AccountIds' => {
          '@xmlns:a1' => 'http://schemas.microsoft.com/2003/10/Serialization/Arrays',
          'a1:long' => account_id,
        }
      },
   etc...
}

I've tried matching the syntax in the documentation linked to above exactly, but it still returns only 'Active' campaigns, which leads me to believe that that is the default setting and the API just ignores my improper filtering.

If anyone could help me figure out what I'm doing wrong here it would be greatly appreciated.

Jordan Lagan
  • 222
  • 2
  • 13
  • the usual first question: Have you tried to model your request in SoapUI? If it works there as expected we can analyze your Ruby code. – Steffen Roller May 10 '19 at 15:51
  • I'm not sure what SoapUI is. What are you asking me to test? I know exactly what the problem is, I'm just not sure how to read the syntax listed in the Bing Ads API documentation. If I knew what format they wanted the request in then I could do it by myself. – Jordan Lagan May 10 '19 at 15:54
  • http://www.soapui.com. But it seems your question is mislabelled? It has nothing to do with Savon, XML or Ruby but everything with Bing? – Steffen Roller May 10 '19 at 16:22
  • I didn't label my question as relating to Ruby, only xml, savon and bing-ads-api. I labelled it as such because I think someone who understands xml will be able to tell me how to understand the syntax in the documentation that I linked to. I've already spent a few hours on it, and am still researching as we speak, but I can't figure it out. I'm not being lazy or simply trying to get others to do my work for me, I've just reached the limit of my understanding and am actively trying to find the problems in my code. Your comment isn't very helpful as it doesn't point me in any useful direction. – Jordan Lagan May 10 '19 at 16:32
  • 1
    No worries, that wasn't meant as a criticism. I've been there :-). It seems you need somebody with a good insight of the Bing API. Unfortunately that isn't me, sorry. – Steffen Roller May 10 '19 at 20:12

1 Answers1

1

Please note that multiple sub filter types are available e.g., AccountStatus, AdDistribution, DeviceOS, DeviceType, and Status.

You can use the following syntax (I tested and confirmed it today) to only include report data where the device type is Tablet and campaign status is Paused. You can remove the device tablet filter, as I only added it to show how to add multiple filters.

<Filter>
    <AccountStatus i:nil="true"/>
    <AdDistribution i:nil="true"/>
    <DeviceOS i:nil="true"/>
    <DeviceType>Tablet</DeviceType>
    <Status>Paused</Status>
</Filter>

Sorry that I don't have a Ruby sample on hand, but here is a C# snippet that helps generate the above XML within the SOAP request:

Filter = new CampaignPerformanceReportFilter {
    DeviceType = DeviceTypeReportFilter.Tablet,
    Status = CampaignStatusReportFilter.Active
},

TIP: Each Bing Ads API service operation includes a syntax template e.g., SubmitGenerateReport. You'll just need to carve out the portions applicable to your request e.g., only one report request type at a time.

Please also feel free to reach our team via the Bing Ads API Development forum and contact support links.

I hope this helps!

Eric Urban
  • 582
  • 2
  • 7
  • Thanks for the answer and for the tip! I had forgotten about the syntax template. It's very helpful to see that syntax. I'm still a little confused though. I tried your exact syntax and I can't get any paused campaigns to return. ``` Paused ``` This returns nothing (at least it filters out Active campaigns), but I have paused campaigns on my account so I'm not sure why it wouldn't return anything. – Jordan Lagan May 15 '19 at 14:48
  • 1
    @JordanLagan were the (currently) paused campaigns active during the date(s) that you specified in the report request? If you run a similar report via https://ads.microsoft.com can you successfully filter by paused campaigns? If the API is not returning the same data as the UI, please do contact support with details and our team will investigate. – Eric Urban May 17 '19 at 13:50
  • Okay, thank you! You answered my initial question and confirmed it's working on your end so there must be a problem with my config. I really appreciate the assistance. – Jordan Lagan May 17 '19 at 14:10