Offline Conversions Code Example

This example demonstrates how to send Microsoft Advertising your offline conversions using the Campaign Management service.

Tip

Use the language selector in the documentation header to choose C#, Java, Php, or Python.

To get access and refresh tokens for your Microsoft Advertising user and make your first service call using the Bing Ads API, see the Quick Start guide. You'll want to review the Get Started guide and walkthroughs for your preferred language e.g., C#, Java, Php, and Python.

Supporting files for C#, Java, Php, and Python examples are available at GitHub. You can clone each repository or repurpose snippets as needed.

using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.Threading.Tasks;
using Microsoft.BingAds.V13.CampaignManagement;
using Microsoft.BingAds;

namespace BingAdsExamplesLibrary.V13
{
    /// <summary>
    /// How to send Microsoft Advertising your offline conversions using the Campaign Management service.
    /// </summary>
    public class OfflineConversions : ExampleBase
    {
        public static ServiceClient<ICampaignManagementService> Service;

        public override string Description
        {
            get { return "Offline Conversions | Campaign Management V13"; }
        }

        public async override Task RunAsync(AuthorizationData authorizationData)
        {
            try
            {
                ApiEnvironment environment = ((OAuthDesktopMobileAuthCodeGrant)authorizationData.Authentication).Environment;

                CampaignManagementExampleHelper CampaignManagementExampleHelper = new CampaignManagementExampleHelper(
                    OutputStatusMessageDefault: this.OutputStatusMessage);
                CampaignManagementExampleHelper.CampaignManagementService = new ServiceClient<ICampaignManagementService>(
                    authorizationData: authorizationData,
                    environment: environment);

                // A conversion goal cannot be deleted, so even if this is a test
                // please choose an appropriate name accordingly. 
                var offlineConversionGoalName = "My Offline Conversion Goal";

                var conversionGoals = new ConversionGoal[]
                {
                    new OfflineConversionGoal
                    {
                        GoalCategory = ConversionGoalCategory.Purchase,
                        // Determines how long after a click that you want to count offline conversions. 
                        ConversionWindowInMinutes = 43200,

                        // If the count type is 'Unique' then only the first offline conversion will be counted.
                        // By setting the count type to 'All', then all offline conversions for the same
                        // MicrosoftClickId with different conversion times will be added cumulatively. 
                        CountType = ConversionGoalCountType.All,

                        Name = offlineConversionGoalName,

                        // The default conversion currency code and value. Each offline conversion can override it.
                        Revenue = new ConversionGoalRevenue
                        {
                            CurrencyCode = null,
                            Type = ConversionGoalRevenueType.FixedValue,
                            Value = 5.00m,
                        },
                        Scope = EntityScope.Account,
                        Status = ConversionGoalStatus.Active,
                        TagId = null
                    },
                };

                OutputStatusMessage("-----\nAddConversionGoals:");
                var addConversionGoalsResponse = await CampaignManagementExampleHelper.AddConversionGoalsAsync(
                    conversionGoals: conversionGoals);
                var conversionGoalIds = addConversionGoalsResponse.ConversionGoalIds.ToArray();
                BatchError[] conversionGoalErrors = addConversionGoalsResponse.PartialErrors.ToArray();
                OutputStatusMessage("ConversionGoalIds:");
                CampaignManagementExampleHelper.OutputArrayOfLong(conversionGoalIds);
                OutputStatusMessage("PartialErrors:");
                CampaignManagementExampleHelper.OutputArrayOfBatchError(conversionGoalErrors);
                
                List<long> goalIds = GetNonNullableIds(conversionGoalIds);
                
                var conversionGoalTypes = ConversionGoalType.OfflineConversion;

                OutputStatusMessage("-----\nGetConversionGoalsByIds:");
                var getConversionGoalsResponse = (await CampaignManagementExampleHelper.GetConversionGoalsByIdsAsync(
                        conversionGoalIds: goalIds,
                        conversionGoalTypes: conversionGoalTypes,
                        returnAdditionalFields: ConversionGoalAdditionalField.ViewThroughConversionWindowInMinutes));
                var getConversionGoals = getConversionGoalsResponse.ConversionGoals;
                conversionGoalErrors = getConversionGoalsResponse.PartialErrors.ToArray();
                OutputStatusMessage("ConversionGoals:");
                CampaignManagementExampleHelper.OutputArrayOfConversionGoal(getConversionGoals);
                OutputStatusMessage("PartialErrors:");
                CampaignManagementExampleHelper.OutputArrayOfBatchError(conversionGoalErrors);

                // Every time you create a new OfflineConversionGoal via either the Microsoft Advertising web application or Campaign Management API, 
                // the MSCLKIDAutoTaggingEnabled value of the corresponding AccountProperty is set to 'true' automatically.
                // We can confirm the setting now.

                var accountPropertyNames = new List<AccountPropertyName>();
                accountPropertyNames.Add(AccountPropertyName.MSCLKIDAutoTaggingEnabled);

                OutputStatusMessage("-----\nGetAccountProperties:");
                var getAccountPropertiesResponse = await CampaignManagementExampleHelper.GetAccountPropertiesAsync(
                    accountPropertyNames: accountPropertyNames);
                var accountProperties = getAccountPropertiesResponse.AccountProperties;
                BatchError[] accountPropertiesErrors = getAccountPropertiesResponse.PartialErrors.ToArray();
                OutputStatusMessage("AccountProperties:");
                CampaignManagementExampleHelper.OutputArrayOfAccountProperty(accountProperties);
                OutputStatusMessage("PartialErrors:");
                CampaignManagementExampleHelper.OutputArrayOfBatchError(accountPropertiesErrors);
                
                var offlineConversions = new[]
                {
                    new OfflineConversion
                    {
                        // If you do not specify an offline conversion currency code, 
                        // then the 'CurrencyCode' element of the goal's 'ConversionGoalRevenue' is used.
                        ConversionCurrencyCode = "USD",

                        // The conversion name must match the 'Name' of the 'OfflineConversionGoal'.
                        // If it does not match you won't observe any error, although the offline
                        // conversion will not be counted.
                        ConversionName = offlineConversionGoalName,

                        // The date and time must be in UTC, should align to the date and time of the 
                        // recorded click (MicrosoftClickId), and cannot be in the future.
                        ConversionTime = DateTime.UtcNow,

                        // If you do not specify an offline conversion value, 
                        // then the 'Value' element of the goal's 'ConversionGoalRevenue' is used.
                        ConversionValue = 10,

                        MicrosoftClickId = "f894f652ea334e739002f7167ab8f8e3"
                    }
                };

                // After the OfflineConversionGoal is set up, wait two hours before submitting the offline conversions. 
                // This example would not succeed in production because we created the goal very recently i.e., 
                // please see above call to AddConversionGoalsAsync. 

                OutputStatusMessage("-----\nApplyOfflineConversions:");
                var applyOfflineConversionsResponse = await CampaignManagementExampleHelper.ApplyOfflineConversionsAsync(
                    offlineConversions: offlineConversions);
                OutputStatusMessage("PartialErrors:");
                CampaignManagementExampleHelper.OutputArrayOfBatchError(applyOfflineConversionsResponse.PartialErrors);
            }
            // Catch authentication exceptions
            catch (OAuthTokenRequestException ex)
            {
                OutputStatusMessage(string.Format("Couldn't get OAuth tokens. Error: {0}. Description: {1}", ex.Details.Error, ex.Details.Description));
            }
            // Catch Campaign Management service exceptions
            catch (FaultException<Microsoft.BingAds.V13.CampaignManagement.AdApiFaultDetail> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Detail.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (FaultException<Microsoft.BingAds.V13.CampaignManagement.ApiFaultDetail> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Detail.OperationErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
                OutputStatusMessage(string.Join("; ", ex.Detail.BatchErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (FaultException<Microsoft.BingAds.V13.CampaignManagement.EditorialApiFaultDetail> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Detail.OperationErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
                OutputStatusMessage(string.Join("; ", ex.Detail.BatchErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (Exception ex)
            {
                OutputStatusMessage(ex.Message);
            }
        }

    }
}
package com.microsoft.bingads.examples.v13;

import java.util.ArrayList;

import java.util.Calendar;
import java.util.TimeZone;

import com.microsoft.bingads.*;
import com.microsoft.bingads.v13.campaignmanagement.*;

public class OfflineConversions extends ExampleBase {

    public static void main(java.lang.String[] args) {
     
        try
        {
            authorizationData = getAuthorizationData();
             
            CampaignManagementExampleHelper.CampaignManagementService = new ServiceClient<ICampaignManagementService>(
                        authorizationData, 
                        API_ENVIRONMENT,
                        ICampaignManagementService.class);

            // A conversion goal cannot be deleted, so even if this is a test
            // please choose an appropriate name accordingly. 
            java.lang.String offlineConversionGoalName = "My Offline Conversion Goal";
            
            ArrayOfConversionGoal conversionGoals = new ArrayOfConversionGoal();
            
            OfflineConversionGoal offlineConversionGoal = new OfflineConversionGoal();
            offlineConversionGoal.setGoalCategory(ConversionGoalCategory.PURCHASE);
            // Determines how long after a click that you want to count offline conversions. 
            offlineConversionGoal.setConversionWindowInMinutes(43200);
            // If the count type is 'Unique' then only the first offline conversion will be counted.
            // By setting the count type to 'All', then all offline conversions for the same
            // MicrosoftClickId with different conversion times will be added cumulatively. 
            offlineConversionGoal.setCountType(ConversionGoalCountType.ALL);
            offlineConversionGoal.setName(offlineConversionGoalName);
            // The default conversion currency code and value. Each offline conversion can override it.
            ConversionGoalRevenue offlineConversionGoalRevenue = new ConversionGoalRevenue();
            offlineConversionGoalRevenue.setType(ConversionGoalRevenueType.FIXED_VALUE);
            offlineConversionGoalRevenue.setValue(new java.math.BigDecimal(5.00));
            offlineConversionGoalRevenue.setCurrencyCode(null);
            offlineConversionGoal.setRevenue(offlineConversionGoalRevenue);
            offlineConversionGoal.setScope(EntityScope.ACCOUNT);
            offlineConversionGoal.setStatus(ConversionGoalStatus.ACTIVE);
            offlineConversionGoal.setTagId(null);
            conversionGoals.getConversionGoals().add(offlineConversionGoal);
            
            outputStatusMessage("-----\nAddConversionGoals:");
            AddConversionGoalsResponse addConversionGoalsResponse = CampaignManagementExampleHelper.addConversionGoals(
                    conversionGoals);
            ArrayOfNullableOflong conversionGoalIds = addConversionGoalsResponse.getConversionGoalIds();
            ArrayOfBatchError goalErrors = addConversionGoalsResponse.getPartialErrors();
            outputStatusMessage("ConversionGoalIds:");
            CampaignManagementExampleHelper.outputArrayOfNullableOflong(conversionGoalIds);
            outputStatusMessage("PartialErrors:");
            CampaignManagementExampleHelper.outputArrayOfBatchError(goalErrors);

            ArrayOflong goalIds = new ArrayOflong();
            for (java.lang.Long goalId : conversionGoalIds.getLongs())
            {
                if (goalId != null)
                {
                    goalIds.getLongs().add((long)goalId);
                }
            }
            
            ArrayList<ConversionGoalType> conversionGoalTypes = new ArrayList<ConversionGoalType>();
            conversionGoalTypes.add(ConversionGoalType.OFFLINE_CONVERSION);
            
            ArrayList<ConversionGoalAdditionalField> returnAdditionalFields = new ArrayList<ConversionGoalAdditionalField>();
            returnAdditionalFields.add(ConversionGoalAdditionalField.VIEW_THROUGH_CONVERSION_WINDOW_IN_MINUTES);
            
            outputStatusMessage("-----\nGetConversionGoalsByIds:");
            GetConversionGoalsByIdsResponse getConversionGoalsByIdsResponse = CampaignManagementExampleHelper.getConversionGoalsByIds(
                    goalIds, 
                    conversionGoalTypes,
                    returnAdditionalFields);
            ArrayOfConversionGoal getConversionGoals = getConversionGoalsByIdsResponse.getConversionGoals();
            goalErrors = getConversionGoalsByIdsResponse.getPartialErrors();
            outputStatusMessage("ConversionGoals:");
            CampaignManagementExampleHelper.outputArrayOfConversionGoal(getConversionGoals);
            outputStatusMessage("PartialErrors:");
            CampaignManagementExampleHelper.outputArrayOfBatchError(goalErrors);
            
            // Every time you create a new OfflineConversionGoal via either the Bing Ads web application or Campaign Management API, 
            // the MSCLKIDAutoTaggingEnabled value of the corresponding AccountProperty is set to 'true' automatically.
            // We can confirm the setting now.
            
            ArrayOfAccountPropertyName accountPropertyNames = new ArrayOfAccountPropertyName();
            accountPropertyNames.getAccountPropertyNames().add(AccountPropertyName.MSCLKID_AUTO_TAGGING_ENABLED);

            outputStatusMessage("-----\nGetAccountProperties:");
            GetAccountPropertiesResponse getAccountPropertiesResponse = CampaignManagementExampleHelper.getAccountProperties(
                    accountPropertyNames);
            outputStatusMessage("AccountProperties:");
            CampaignManagementExampleHelper.outputArrayOfAccountProperty(getAccountPropertiesResponse.getAccountProperties());
            outputStatusMessage("PartialErrors:");
            CampaignManagementExampleHelper.outputArrayOfBatchError(getAccountPropertiesResponse.getPartialErrors());
            
            ArrayOfOfflineConversion offlineConversions = new ArrayOfOfflineConversion();
            OfflineConversion offlineConversion = new OfflineConversion();             
            // If you do not specify an offline conversion currency code, 
            // then the 'CurrencyCode' element of the goal's 'ConversionGoalRevenue' is used.
            offlineConversion.setConversionCurrencyCode("USD");
            // The conversion name must match the 'Name' of the 'OfflineConversionGoal'.
            // If it does not match you won't observe any error, although the offline
            // conversion will not be counted.
            offlineConversion.setConversionName(offlineConversionGoalName);
            // The date and time must be in UTC, should align to the date and time of the 
            // recorded click (MicrosoftClickId), and cannot be in the future.
            Calendar calendar = Calendar.getInstance();
            calendar.setTimeZone(TimeZone.getTimeZone("GMT"));
            calendar.set(2018, 4, 26, 0, 0, 0);
            offlineConversion.setConversionTime(calendar);
            // If you do not specify an offline conversion value, 
            // then the 'Value' element of the goal's 'ConversionGoalRevenue' is used.
            offlineConversion.setConversionValue(10D);
            offlineConversion.setMicrosoftClickId("f894f652ea334e739002f7167ab8f8e3");
            
            offlineConversions.getOfflineConversions().add(offlineConversion);

            // After the OfflineConversionGoal is set up, wait two hours before sending Bing Ads the offline conversions. 
            // This example would not succeed in production because we created the goal very recently i.e., 
            // please see above call to AddConversionGoalsAsync. 

            outputStatusMessage("-----\nApplyOfflineConversions:");
            ApplyOfflineConversionsResponse applyOfflineConversionsResponse = CampaignManagementExampleHelper.applyOfflineConversions(
                    offlineConversions);
            outputStatusMessage("PartialErrors:");
            CampaignManagementExampleHelper.outputArrayOfBatchError(applyOfflineConversionsResponse.getPartialErrors());
        } 
        catch (Exception ex) {
            String faultXml = ExampleExceptionHelper.getBingAdsExceptionFaultXml(ex, System.out);
            outputStatusMessage(faultXml);
            String message = ExampleExceptionHelper.handleBingAdsSDKException(ex, System.out);
            outputStatusMessage(message);
        }
    }
 }
<?php

namespace Microsoft\BingAds\Samples\V13;

// For more information about installing and using the Bing Ads PHP SDK, 
// see https://go.microsoft.com/fwlink/?linkid=838593.

require_once __DIR__ . "/../vendor/autoload.php";

include __DIR__ . "/AuthHelper.php";
include __DIR__ . "/CampaignManagementExampleHelper.php";

use SoapVar;
use SoapFault;
use Exception;

// Specify the Microsoft\BingAds\V13\CampaignManagement classes that will be used.
use Microsoft\BingAds\V13\CampaignManagement\AccountPropertyName;
use Microsoft\BingAds\V13\CampaignManagement\ConversionGoal;
use Microsoft\BingAds\V13\CampaignManagement\OfflineConversionGoal;
use Microsoft\BingAds\V13\CampaignManagement\OfflineConversion;
use Microsoft\BingAds\V13\CampaignManagement\ConversionGoalRevenue;
use Microsoft\BingAds\V13\CampaignManagement\ConversionGoalType;
use Microsoft\BingAds\V13\CampaignManagement\ConversionGoalRevenueType;
use Microsoft\BingAds\V13\CampaignManagement\ConversionGoalCountType;
use Microsoft\BingAds\V13\CampaignManagement\ConversionGoalStatus;
use Microsoft\BingAds\V13\CampaignManagement\EntityScope;

// Specify the Microsoft\BingAds\Auth classes that will be used.
use Microsoft\BingAds\Auth\ServiceClient;
use Microsoft\BingAds\Auth\ServiceClientType;

// Specify the Microsoft\BingAds\Samples classes that will be used.
use Microsoft\BingAds\Samples\V13\AuthHelper;
use Microsoft\BingAds\Samples\V13\CampaignManagementExampleHelper;

try
{
    // Authenticate user credentials and set the account ID for the sample.  
    AuthHelper::Authenticate();

    // A conversion goal cannot be deleted, so even if this is a test
    // please choose an appropriate name accordingly. 
    $offlineConversionGoalName = "My Offline Conversion Goal";
    
    $conversionGoals = array();
    $offlineConversionGoal = new OfflineConversionGoal();
    $offlineConversionGoal->GoalCategory = ConversionGoalCategory::Purchase;
    // Determines how long after a click that you want to count offline conversions.
    $offlineConversionGoal->ConversionWindowInMinutes = 43200;
    // If the count type is 'Unique' then only the first offline conversion will be counted.
    // By setting the count type to 'All', then all offline conversions for the same
    // MicrosoftClickId with different conversion times will be added cumulatively. 
    $offlineConversionGoal->CountType = ConversionGoalCountType::All;
    $offlineConversionGoal->Name = $offlineConversionGoalName;
    // The default conversion currency code and value. Each offline conversion can override it.
    $offlineConversionGoalRevenue = new ConversionGoalRevenue();
    $offlineConversionGoalRevenue->Type = ConversionGoalRevenueType::FixedValue;
    $offlineConversionGoalRevenue->Value = 5.00;
    $offlineConversionGoalRevenue->CurrencyCode = null;
    $offlineConversionGoal->Revenue = $offlineConversionGoalRevenue;
    $offlineConversionGoal->Scope = EntityScope::Account;
    $offlineConversionGoal->Status = ConversionGoalStatus::Active;
    $offlineConversionGoal->TagId = null;
    $encodedOfflineConversionGoal = new SoapVar(
        $offlineConversionGoal, 
        SOAP_ENC_OBJECT, 
        'OfflineConversionGoal', 
        $GLOBALS['CampaignManagementProxy']->GetNamespace()
    );
    $conversionGoals[] = $encodedOfflineConversionGoal;

    print("-----\r\nAddConversionGoals:\r\n");
    $addConversionGoalsResponse = CampaignManagementExampleHelper::AddConversionGoals(
        $conversionGoals
    );
    $conversionGoalIds = $addConversionGoalsResponse->ConversionGoalIds;
    print("ConversionGoalIds:\r\n");
    CampaignManagementExampleHelper::OutputArrayOfLong($conversionGoalIds);
    print("PartialErrors:\r\n");
    CampaignManagementExampleHelper::OutputArrayOfBatchError($addConversionGoalsResponse->PartialErrors);

    $conversionGoalTypes = array(ConversionGoalType::OfflineConversion);

    print("-----\r\nGetConversionGoalsByIds:\r\n");
    $getConversionGoalsResponse = CampaignManagementExampleHelper::GetConversionGoalsByIds(
        $conversionGoalIds, 
        $conversionGoalTypes
    );
    $getConversionGoals = $getConversionGoalsResponse->ConversionGoals;
    print("ConversionGoals:\r\n");
    CampaignManagementExampleHelper::OutputArrayOfConversionGoal($getConversionGoals);
    print("PartialErrors:\r\n");
    CampaignManagementExampleHelper::OutputArrayOfBatchError($getConversionGoalsResponse->PartialErrors);

    // Every time you create a new OfflineConversionGoal via either the Bing Ads web application or Campaign Management API, 
    // the MSCLKIDAutoTaggingEnabled value of the corresponding AccountProperty is set to 'true' automatically.
    // We can confirm the setting now.

    $accountPropertyNames = array(AccountPropertyName::MSCLKIDAutoTaggingEnabled);

    print("-----\r\nGetAccountProperties:\r\n");
    $getAccountPropertiesResponse = CampaignManagementExampleHelper::GetAccountProperties(
        $accountPropertyNames
    );
    print("AccountProperties:\r\n");
    CampaignManagementExampleHelper::OutputArrayOfAccountProperty($getAccountPropertiesResponse->AccountProperties);
    print("PartialErrors:\r\n");
    CampaignManagementExampleHelper::OutputArrayOfBatchError($getAccountPropertiesResponse->PartialErrors);
    
    $offlineConversions = array();
    $offlineConversion = new OfflineConversion();
    // If you do not specify an offline conversion currency code, 
    // then the 'CurrencyCode' element of the goal's 'ConversionGoalRevenue' is used.
    $offlineConversion->ConversionCurrencyCode = "USD";
    // The conversion name must match the 'Name' of the 'OfflineConversionGoal'.
    // If it does not match you won't observe any error, although the offline
    // conversion will not be counted.
    $offlineConversion->ConversionName = $offlineConversionGoalName;
    // The date and time must be in UTC, should align to the date and time of the 
    // recorded click (MicrosoftClickId), and cannot be in the future.
    $offlineConversion->ConversionTime = $_SERVER['REQUEST_TIME'];
    // If you do not specify an offline conversion value, 
    // then the 'Value' element of the goal's 'ConversionGoalRevenue' is used.
    $offlineConversion->ConversionValue = 10;
    $offlineConversion->MicrosoftClickId = "f894f652ea334e739002f7167ab8f8e3";
    $offlineConversions[] = $offlineConversion;

    // After the OfflineConversionGoal is set up, wait two hours before sending Bing Ads the offline conversions. 
    // This example would not succeed in production because we created the goal very recently i.e., 
    // please see above call to AddConversionGoalsAsync. 

    print("-----\r\nApplyOfflineConversions:\r\n");
    $applyOfflineConversionsResponse = CampaignManagementExampleHelper::ApplyOfflineConversions(
        $offlineConversions
    );
    print("PartialErrors:\r\n");
    CampaignManagementExampleHelper::OutputArrayOfBatchError($applyOfflineConversionsResponse->PartialErrors);
}
catch (SoapFault $e)
{
    printf("-----\r\nFault Code: %s\r\nFault String: %s\r\nFault Detail: \r\n", $e->faultcode, $e->faultstring);
    var_dump($e->detail);
    print "-----\r\nLast SOAP request/response:\r\n";
    print $GLOBALS['Proxy']->GetWsdl() . "\r\n";
    print $GLOBALS['Proxy']->GetService()->__getLastRequest()."\r\n";
    print $GLOBALS['Proxy']->GetService()->__getLastResponse()."\r\n";
}
catch (Exception $e)
{
    // Ignore fault exceptions that we already caught.
    if ($e->getPrevious())
    { ; }
    else
    {
        print $e->getCode()." ".$e->getMessage()."\n\n";
        print $e->getTraceAsString()."\n\n";
    }
}
from datetime import datetime, timedelta

from auth_helper import *
from campaignmanagement_example_helper import *

# You must provide credentials in auth_helper.py.

def main(authorization_data):

    try:
        # A conversion goal cannot be deleted, so even if this is a test
        # please choose an appropriate name accordingly.
        offline_conversion_goal_name = "My Offline Conversion Goal"

        conversion_goals=campaign_service.factory.create('ArrayOfConversionGoal')

        offline_conversion_goal=set_elements_to_none(campaign_service.factory.create('OfflineConversionGoal'))
        offline_conversion_goal.GoalCategory = "Purchase"
        # Determines how long after a click that you want to count offline conversions. 
        offline_conversion_goal.ConversionWindowInMinutes = 43200
        # If the count type is 'Unique' then only the first offline conversion will be counted.
        # By setting the count type to 'All', then all offline conversions for the same
        # MicrosoftClickId with different conversion times will be added cumulatively. 
        offline_conversion_goal.CountType = 'All'
        offline_conversion_goal.Name = offline_conversion_goal_name
        # The default conversion currency code and value. Each offline conversion can override it.
        offline_conversion_goal_revenue=set_elements_to_none(campaign_service.factory.create('ConversionGoalRevenue'))
        offline_conversion_goal_revenue.CurrencyCode=None
        offline_conversion_goal_revenue.Type='FixedValue'
        offline_conversion_goal_revenue.Value=5.00
        offline_conversion_goal.Revenue = offline_conversion_goal_revenue
        offline_conversion_goal.Scope = 'Account'
        offline_conversion_goal.Status = 'Active'
        # The TagId is inherited from the ConversionGoal base class,
        # however, Offline Conversion goals do not use a UET tag.
        offline_conversion_goal.TagId = None
        conversion_goals.ConversionGoal.append(offline_conversion_goal)

        output_status_message("-----\nAddConversionGoals:")
        add_conversion_goals_response=campaign_service.AddConversionGoals(
            ConversionGoals=conversion_goals)
        output_status_message("ConversionGoalIds:")
        output_array_of_long(add_conversion_goals_response.ConversionGoalIds)
        output_status_message("PartialErrors:")
        output_array_of_batcherror(add_conversion_goals_response.PartialErrors)
        
        # Find the conversion goals that were added successfully. 

        conversion_goal_ids = []
        for goal_id in add_conversion_goals_response.ConversionGoalIds['long']:
            if goal_id is not None:
                conversion_goal_ids.append(goal_id)
        
        conversion_goal_types='OfflineConversion'
        
        return_additional_fields = 'ViewThroughConversionWindowInMinutes'
        
        output_status_message("-----\nGetConversionGoalsByIds:")
        get_conversion_goals_by_ids_response = campaign_service.GetConversionGoalsByIds(
            ConversionGoalIds={'long': conversion_goal_ids}, 
            ConversionGoalTypes=conversion_goal_types,
            ReturnAdditionalFields=return_additional_fields
        )
        output_status_message("ConversionGoals:")
        output_array_of_conversiongoal(get_conversion_goals_by_ids_response.ConversionGoals)
        output_status_message("PartialErrors:")
        output_array_of_batcherror(get_conversion_goals_by_ids_response.PartialErrors)

        # Every time you create a new OfflineConversionGoal via either the Bing Ads web application or Campaign Management API, 
        # the MSCLKIDAutoTaggingEnabled value of the corresponding AccountProperty is set to 'true' automatically.
        # We can confirm the setting now.

        account_property_names=campaign_service.factory.create('ArrayOfAccountPropertyName')
        account_property_names.AccountPropertyName.append([
            'MSCLKIDAutoTaggingEnabled'
        ])

        output_status_message("-----\nGetAccountProperties:")
        get_account_properties_response = campaign_service.GetAccountProperties(
            AccountPropertyNames=account_property_names)
        output_status_message("AccountProperties:")
        output_array_of_accountproperty(get_account_properties_response.AccountProperties)
        output_status_message("PartialErrors:")
        output_array_of_batcherror(get_account_properties_response.PartialErrors)

        offline_conversions=campaign_service.factory.create('ArrayOfOfflineConversion')

        offline_conversion=set_elements_to_none(campaign_service.factory.create('OfflineConversion'))
        # If you do not specify an offline conversion currency code, 
        # then the 'CurrencyCode' element of the goal's 'ConversionGoalRevenue' is used.
        offline_conversion.ConversionCurrencyCode = "USD"
        # The conversion name must match the 'Name' of the 'OfflineConversionGoal'.
        # If it does not match you won't observe any error, although the offline
        # conversion will not be counted.
        offline_conversion.ConversionName = offline_conversion_goal_name
        # The date and time must be in UTC, should align to the date and time of the 
        # recorded click (MicrosoftClickId), and cannot be in the future.
        offline_conversion.ConversionTime = datetime.utcnow()
        # If you do not specify an offline conversion value, 
        # then the 'Value' element of the goal's 'ConversionGoalRevenue' is used.
        offline_conversion.ConversionValue = 10
        offline_conversion.MicrosoftClickId = "f894f652ea334e739002f7167ab8f8e3"
        offline_conversions.OfflineConversion.append(offline_conversion)

        # After the OfflineConversionGoal is set up, wait two hours before sending Bing Ads the offline conversions. 
        # This example would not succeed in production because we created the goal very recently i.e., 
        # please see above call to AddConversionGoals. 

        output_status_message("-----\nApplyOfflineConversions:")
        apply_offline_conversions_response = campaign_service.ApplyOfflineConversions(
            OfflineConversions=offline_conversions)
        output_status_message("PartialErrors:")
        output_array_of_batcherror(apply_offline_conversions_response)

    except WebFault as ex:
        output_webfault_errors(ex)
    except Exception as ex:
        output_status_message(ex)

# Main execution
if __name__ == '__main__':

    print("Loading the web service client proxies...")
    
    authorization_data=AuthorizationData(
        account_id=None,
        customer_id=None,
        developer_token=DEVELOPER_TOKEN,
        authentication=None,
    )

    campaign_service=ServiceClient(
        service='CampaignManagementService', 
        version=13,
        authorization_data=authorization_data, 
        environment=ENVIRONMENT,
    )
        
    authenticate(authorization_data)
        
    main(authorization_data)

See Also

Get Started with the Bing Ads API