ภาษา

ตัวอย่างโค้ดส่วนขยายโฆษณา

ตัวอย่างนี้แสดงวิธีการเพิ่ม รับ และลบส่วนขยายสําหรับไลบรารีส่วนขยายโฆษณาของบัญชี ตั้งค่า รับ และลบการเชื่อมโยงส่วนขยายกับแคมเปญ และระบุสาเหตุที่ส่วนขยายล้มเหลวในการตรวจสอบบรรณาธิการ

เคล็ดลับ

ใช้ตัวเลือกภาษาในส่วนหัวของเอกสารประกอบเพื่อเลือก C#, Java, PHP หรือ Python

เมื่อต้องการรับการเข้าถึงและรีเฟรชโทเค็นสําหรับผู้ใช้ Microsoft Advertising ของคุณ และทําการเรียกใช้บริการครั้งแรกของคุณโดยใช้ Bing Ads API ให้ดูคู่มือเริ่มต้นใช้งานด่วน คุณจะต้องตรวจสอบคู่มือเริ่มต้นใช้งานและคําแนะนําสําหรับภาษาที่คุณต้องการ เช่น C#, Java, PHP และ Python

ไฟล์ที่สนับสนุนสําหรับตัวอย่าง C#, Java, PHP และ Python มีอยู่ที่ GitHub คุณสามารถโคลนแต่ละที่เก็บหรือนําส่วนย่อยไปใช้ใหม่ได้ตามต้องการ

using System;
using System.Drawing;
using System.IO;
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 manage ad extensions for an account's ad extension library, 
    /// associate the extensions with a campaign, and determine why an extension failed 
    /// editorial review.
    /// </summary>
    public class AdExtensions : ExampleBase
    {
        // To run this example you'll need to provide your own image.  
        // For required aspect ratios and recommended dimensions please see 
        // Image remarks at https://go.microsoft.com/fwlink/?linkid=872754.

        private const string MediaFilePath = "c:\\dev\\media\\";
        private const string ImageAdExtensionMediaFileName = "imageadextension300x200.png";

        public override string Description
        {
            get { return "Ad Extensions | 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);

                // Add a campaign to associate with ad extensions. 

                var campaigns = new[] {
                    new Campaign
                    {
                        BudgetType = BudgetLimitType.DailyBudgetStandard,
                        DailyBudget = 50,
                        Languages = new string[] { "All" },
                        Name = "Everyone's Shoes " + DateTime.UtcNow,
                        TimeZone = "PacificTimeUSCanadaTijuana",
                    }
                };

                OutputStatusMessage("-----\nAddCampaigns:");
                AddCampaignsResponse addCampaignsResponse = await CampaignManagementExampleHelper.AddCampaignsAsync(
                    accountId: authorizationData.AccountId,
                    campaigns: campaigns);
                long?[] campaignIds = addCampaignsResponse.CampaignIds.ToArray();
                BatchError[] campaignErrors = addCampaignsResponse.PartialErrors.ToArray();
                OutputStatusMessage("CampaignIds:");
                CampaignManagementExampleHelper.OutputArrayOfLong(campaignIds);
                OutputStatusMessage("PartialErrors:");
                CampaignManagementExampleHelper.OutputArrayOfBatchError(campaignErrors);
                
                // Create media for the image ad extension that we'll add later. 

                var imageAdExtensionMedia = GetImageMedia(
                    "Image15x10",
                    MediaFilePath + ImageAdExtensionMediaFileName,
                    System.Drawing.Imaging.ImageFormat.Png);

                var media = new Media[]
                {
                    imageAdExtensionMedia
                };

                // Add the media to the account's library.

                OutputStatusMessage("-----\nAddMedia:");
                AddMediaResponse addMediaResponse = await CampaignManagementExampleHelper.AddMediaAsync(
                    accountId: authorizationData.AccountId,
                    media: media);
                long[] mediaIds = addMediaResponse.MediaIds.ToArray();
                OutputStatusMessage("MediaIds:");
                CampaignManagementExampleHelper.OutputArrayOfLong(mediaIds);

                // Add the extensions to the account's library.

                var adExtensions = new AdExtension[] {
                    new ActionAdExtension
                    {
                        ActionType = ActionAdExtensionActionType.ActNow,
                        FinalUrls = new string[]
                        {
                            "https://www.contoso.com/womenshoesale"
                        },
                        Language = "English",
                        Status = AdExtensionStatus.Active,
                    },
                    //new AppAdExtension
                    //{
                    //    AppPlatform = "Windows",
                    //    AppStoreId = "AppStoreIdGoesHere",
                    //    DestinationUrl = "DestinationUrlGoesHere",
                    //    DisplayText = "Contoso",
                    //},
                    new CallAdExtension {
                        CountryCode = "US",
                        PhoneNumber = "2065550100",
                        IsCallOnly = false,
                        // Include the call extension Monday - Friday from 9am - 9pm
                        // in the account's time zone.
                        Scheduling = new Schedule {
                            UseSearcherTimeZone = false,
                            DayTimeRanges = new[]
                            {
                                new DayTime
                                {
                                    Day = Day.Monday,
                                    StartHour = 9,
                                    StartMinute = Minute.Zero,
                                    EndHour = 21,
                                    EndMinute = Minute.Zero,
                                },
                                new DayTime
                                {
                                    Day = Day.Tuesday,
                                    StartHour = 9,
                                    StartMinute = Minute.Zero,
                                    EndHour = 21,
                                    EndMinute = Minute.Zero,
                                },
                                new DayTime
                                {
                                    Day = Day.Wednesday,
                                    StartHour = 9,
                                    StartMinute = Minute.Zero,
                                    EndHour = 21,
                                    EndMinute = Minute.Zero,
                                },
                                new DayTime
                                {
                                    Day = Day.Thursday,
                                    StartHour = 9,
                                    StartMinute = Minute.Zero,
                                    EndHour = 21,
                                    EndMinute = Minute.Zero,
                                },
                                new DayTime
                                {
                                    Day = Day.Friday,
                                    StartHour = 9,
                                    StartMinute = Minute.Zero,
                                    EndHour = 21,
                                    EndMinute = Minute.Zero,
                                },
                            },
                            StartDate = null,
                            EndDate = new Microsoft.BingAds.V13.CampaignManagement.Date {
                                Month = 12,
                                Day = 31,
                                Year = DateTime.UtcNow.Year + 1
                            },
                        }
                    },
                    new CalloutAdExtension
                    {
                        Text = "Callout Text"
                    },
                    new ImageAdExtension
                    {
                        AlternativeText = "Image Extension Alt Text",
                        ImageMediaIds = mediaIds,
                        Images = new AssetLink[]
                        {
                            new AssetLink
                            {
                                Asset = new ImageAsset
                                {
                                    Id = 12345, // 1.91 aspect ratio image id. This type of image is required for Images
                                    SubType = "LandscapeImageMedia",
                                }
                            }
                        }
                    },
                    new LocationAdExtension {
                        PhoneNumber = "206-555-0100",
                        CompanyName = "Contoso Shoes",
                        Address = new Microsoft.BingAds.V13.CampaignManagement.Address {
                            StreetAddress = "1234 Washington Place",
                            StreetAddress2 = "Suite 1210",
                            CityName = "Woodinville",
                            ProvinceName = "WA",
                            CountryCode = "US",
                            PostalCode = "98608"
                        },
                        // Include the location extension every Saturday morning
                        // in the search user's time zone.
                        Scheduling = new Schedule {
                            UseSearcherTimeZone = true,
                            DayTimeRanges = new[]
                            {
                                new DayTime
                                {
                                    Day = Day.Saturday,
                                    StartHour = 9,
                                    StartMinute = Minute.Zero,
                                    EndHour = 12,
                                    EndMinute = Minute.Zero,
                                },
                            },
                            StartDate = null,
                            EndDate = new Microsoft.BingAds.V13.CampaignManagement.Date {
                                Month = 12,
                                Day = 31,
                                Year = DateTime.UtcNow.Year + 1
                            },
                        }
                    },
                    new PriceAdExtension
                    {
                        Language = "English",
                        PriceExtensionType = PriceExtensionType.Events,
                        TableRows = new PriceTableRow[]
                        {
                            new PriceTableRow
                            {
                                CurrencyCode = "USD",
                                Description = "Come to the event",
                                FinalUrls = new string[]
                                {
                                    "https://contoso.com"
                                },
                                Header = "New Event",
                                Price = 9.99,
                                PriceQualifier = PriceQualifier.From,
                                PriceUnit = PriceUnit.PerDay,
                            },
                            new PriceTableRow
                            {
                                CurrencyCode = "USD",
                                Description = "Come to the next event",
                                FinalUrls = new string[]
                                {
                                    "https://contoso.com"
                                },
                                Header = "Next Event",
                                Price = 9.99,
                                PriceQualifier = PriceQualifier.From,
                                PriceUnit = PriceUnit.PerDay,
                            },
                            new PriceTableRow
                            {
                                CurrencyCode = "USD",
                                Description = "Come to the final event",
                                FinalUrls = new string[]
                                {
                                    "https://contoso.com"
                                },
                                Header = "Final Event",
                                Price = 9.99,
                                PriceQualifier = PriceQualifier.From,
                                PriceUnit = PriceUnit.PerDay,
                            },
                        },
                    },
                    new ReviewAdExtension
                    {
                        IsExact = true,
                        Source = "Review Source Name",
                        Text = "Review Text",
                        // The Url of the third-party review. This is not your business Url.
                        Url = "https://review.contoso.com" 
                    },
                    new SitelinkAdExtension {
                        Description1 = "Simple & Transparent.",
                        Description2 = "No Upfront Cost.",
                        DisplayText = "Everyone's Shoe Sale",
                        FinalUrls = new[] {
                            "https://www.contoso.com/womenshoesale"
                        },
                    },
                    new StructuredSnippetAdExtension
                    {
                        Header = "Brands",
                        Values = new [] { "Windows", "Xbox", "Skype"}
                    }
                };

                OutputStatusMessage("-----\nAddAdExtensions:");
                var addAdExtensionsResponse = await CampaignManagementExampleHelper.AddAdExtensionsAsync(
                    accountId: authorizationData.AccountId,
                    adExtensions: adExtensions);
                OutputStatusMessage("AdExtensionIdentities:");
                var adExtensionIdentities = addAdExtensionsResponse?.AdExtensionIdentities;
                OutputStatusMessage("NestedPartialErrors:");
                CampaignManagementExampleHelper.OutputArrayOfBatchErrorCollection(addAdExtensionsResponse?.NestedPartialErrors);
                
                // DeleteAdExtensionsAssociations, SetAdExtensionsAssociations, and GetAdExtensionsEditorialReasons 
                // operations each require a list of type AdExtensionIdToEntityIdAssociation.
                var adExtensionIdToEntityIdAssociations = new List<AdExtensionIdToEntityIdAssociation>();

                // GetAdExtensionsByIds requires a list of type long.
                var adExtensionIds = new List<long>();

                // Loop through the list of extension IDs and build any required data structures
                // for subsequent operations. 

                foreach (var adExtensionIdentity in adExtensionIdentities)
                {
                    if (adExtensionIdentity != null)
                    {
                        adExtensionIdToEntityIdAssociations.Add(new AdExtensionIdToEntityIdAssociation
                        {
                            AdExtensionId = adExtensionIdentity.Id,
                            EntityId = (long)campaignIds[0]
                        });

                        adExtensionIds.Add(adExtensionIdentity.Id);
                    }
                }

                // Associate the ad extensions with the campaign. 

                OutputStatusMessage("-----\nSetAdExtensionsAssociations:");
                var setAdExtensionsAssociationsResponse = await CampaignManagementExampleHelper.SetAdExtensionsAssociationsAsync(
                    accountId: authorizationData.AccountId,
                    adExtensionIdToEntityIdAssociations: adExtensionIdToEntityIdAssociations,
                    associationType: AssociationType.Campaign);
                OutputStatusMessage("PartialErrors:");
                CampaignManagementExampleHelper.OutputArrayOfBatchError(setAdExtensionsAssociationsResponse?.PartialErrors);

                // Get editorial rejection reasons for the ad extension and entity associations.

                OutputStatusMessage("-----\nGetAdExtensionsEditorialReasons:");
                var getAdExtensionsEditorialReasonsResponse = await CampaignManagementExampleHelper.GetAdExtensionsEditorialReasonsAsync(
                        accountId: authorizationData.AccountId,
                        adExtensionIdToEntityIdAssociations: adExtensionIdToEntityIdAssociations,
                        associationType: AssociationType.Campaign);
                OutputStatusMessage("EditorialReasons:");
                var adExtensionEditorialReasonCollection =
                    (AdExtensionEditorialReasonCollection[])getAdExtensionsEditorialReasonsResponse?.EditorialReasons;
                CampaignManagementExampleHelper.OutputArrayOfAdExtensionEditorialReasonCollection(adExtensionEditorialReasonCollection);
                OutputStatusMessage("PartialErrors:");
                CampaignManagementExampleHelper.OutputArrayOfBatchError(getAdExtensionsEditorialReasonsResponse?.PartialErrors);
                
                // Get only the location ad extensions and then remove scheduling.

                AdExtensionsTypeFilter adExtensionsTypeFilter = AdExtensionsTypeFilter.LocationAdExtension;

                // In this example partial errors will be returned for indices where the ad extensions 
                // are not location ad extensions.
                // This is an example, and ideally you would only send the required ad extension IDs.

                OutputStatusMessage("-----\nGetAdExtensionsByIds:");
                var getAdExtensionsByIdsResponse = (await CampaignManagementExampleHelper.GetAdExtensionsByIdsAsync(
                    accountId: authorizationData.AccountId,
                    adExtensionIds: adExtensionIds,
                    adExtensionType: adExtensionsTypeFilter,
                    returnAdditionalFields: AdExtensionAdditionalField.DisplayText | AdExtensionAdditionalField.Images));
                adExtensions = getAdExtensionsByIdsResponse?.AdExtensions.ToArray();
                BatchError[] getAdExtensionErrors = getAdExtensionsByIdsResponse?.PartialErrors.ToArray();
                OutputStatusMessage("AdExtensions:");
                CampaignManagementExampleHelper.OutputArrayOfAdExtension(adExtensions);
                OutputStatusMessage("PartialErrors:");
                CampaignManagementExampleHelper.OutputArrayOfBatchError(getAdExtensionErrors);
                
                var updateExtensions = new List<AdExtension>();
                var updateExtensionIds = new List<long>();

                foreach (var extension in adExtensions)
                {
                    // GetAdExtensionsByIds will return a nil element if the request conditions were not met.
                    if (extension != null && extension.Id != null)
                    {
                        // Remove read-only elements that would otherwise cause the update operation to fail.
                        var updateExtension = SetReadOnlyAdExtensionElementsToNull(extension);

                        // If you set the Scheduling element null, any existing scheduling set for the ad extension will remain unchanged. 
                        // If you set this to any non-null Schedule object, you are effectively replacing existing scheduling 
                        // for the ad extension. In this example, we will remove any existing scheduling by setting this element  
                        // to an empty Schedule object.
                        updateExtension.Scheduling = new Schedule { };
                        updateExtensions.Add(updateExtension);
                        updateExtensionIds.Add((long)updateExtension.Id);
                    }
                }

                OutputStatusMessage("-----\nUpdateAdExtensions:");                
                await CampaignManagementExampleHelper.UpdateAdExtensionsAsync(
                    accountId: authorizationData.AccountId, 
                    adExtensions: updateExtensions);
                OutputStatusMessage("Removed scheduling from the location ad extensions.");

                // Get only the location extensions to output the result.

                OutputStatusMessage("-----\nGetAdExtensionsByIds:");
                getAdExtensionsByIdsResponse = await CampaignManagementExampleHelper.GetAdExtensionsByIdsAsync(
                    accountId: authorizationData.AccountId,
                    adExtensionIds: updateExtensionIds,
                    adExtensionType: adExtensionsTypeFilter,
                    returnAdditionalFields: AdExtensionAdditionalField.DisplayText | AdExtensionAdditionalField.Images);
                adExtensions = getAdExtensionsByIdsResponse?.AdExtensions.ToArray();
                getAdExtensionErrors = getAdExtensionsByIdsResponse?.PartialErrors.ToArray();
                OutputStatusMessage("AdExtensions:");
                CampaignManagementExampleHelper.OutputArrayOfAdExtension(adExtensions);
                OutputStatusMessage("PartialErrors:");
                CampaignManagementExampleHelper.OutputArrayOfBatchError(getAdExtensionErrors);

                // Delete the ad extension associations, ad extensions, and campaign, that were previously added.  
                // At this point the ad extensions are still available in the account's ad extensions library. 

                OutputStatusMessage("-----\nDeleteAdExtensionsAssociations:");
                await CampaignManagementExampleHelper.DeleteAdExtensionsAssociationsAsync(
                    authorizationData.AccountId,
                    adExtensionIdToEntityIdAssociations,
                    AssociationType.Campaign);
                OutputStatusMessage("Deleted ad extension associations.");

                // Delete the ad extensions from the account's ad extension library.

                OutputStatusMessage("-----\nDeleteAdExtensions:");
                await CampaignManagementExampleHelper.DeleteAdExtensionsAsync(
                    authorizationData.AccountId,
                    adExtensionIds);
                OutputStatusMessage("Deleted ad extensions.");

                // Delete the account's media that was used for the image ad extension.

                OutputStatusMessage("-----\nDeleteMedia:");
                await CampaignManagementExampleHelper.DeleteMediaAsync(
                    accountId: authorizationData.AccountId,
                    mediaIds: mediaIds);

                foreach (var id in mediaIds)
                {
                    OutputStatusMessage(string.Format("Deleted Media Id {0}", id));
                }

                // Delete the campaign and everything it contains e.g., ad groups and ads.

                OutputStatusMessage("-----\nDeleteCampaigns:");
                await CampaignManagementExampleHelper.DeleteCampaignsAsync(
                    accountId: authorizationData.AccountId,
                    campaignIds: new[] { (long)campaignIds[0] });
                OutputStatusMessage(string.Format("Deleted Campaign Id {0}", campaignIds[0]));
            }
            // 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 Customer Management service exceptions
            catch (FaultException<Microsoft.BingAds.V13.CustomerManagement.AdApiFaultDetail> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Detail.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (FaultException<Microsoft.BingAds.V13.CustomerManagement.ApiFault> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Detail.OperationErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (Exception ex)
            {
                OutputStatusMessage(ex.Message);
            }
        }

        /// <summary>
        /// Get image media that can be managed with the Campaign Management API.
        /// </summary>
        /// <param name="mediaType">The media type reflects the aspect ratio.</param>
        /// <param name="imageFileName">The file name and path.</param>
        /// <param name="imageFormat">For supported image formats see <see href="https://go.microsoft.com/fwlink/?linkid=872754">Image remarks</see>.</param>
        /// <returns>A Campaign Management Image object.</returns>
        private Microsoft.BingAds.V13.CampaignManagement.Image GetImageMedia(
            string mediaType,
            string imageFileName,
            System.Drawing.Imaging.ImageFormat imageFormat)
        {
            var image = new Microsoft.BingAds.V13.CampaignManagement.Image();
            image.Data = GetBmpBase64String(imageFileName, imageFormat);
            image.MediaType = mediaType;
            image.Type = "Image";

            return image;
        }

        /// <summary>
        /// Get the image media as base64 string.
        /// </summary>
        /// <param name="imageFileName">The file name and path.</param>
        /// <param name="imageFormat">For supported image formats see <see href="https://go.microsoft.com/fwlink/?linkid=872754">Image remarks</see>.</param>
        /// <returns></returns>
        private string GetBmpBase64String(
            string imageFileName,
            System.Drawing.Imaging.ImageFormat imageFormat)
        {
            var bmp = new Bitmap(imageFileName);
            using (MemoryStream ms = new MemoryStream())
            {
                bmp.Save(ms, imageFormat);
                byte[] imageBytes = ms.ToArray();
                string base64String = Convert.ToBase64String(imageBytes);
                return base64String;
            }
        }        
    }
}
package com.microsoft.bingads.examples.v13;

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

import java.util.ArrayList;
import java.util.Calendar;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.file.Files;
import java.util.Base64;

public class AdExtensions extends ExampleBase {

    public static void main(java.lang.String[] args) {
        
    // To run this example you'll need to provide your own image.  
        // For required aspect ratios and recommended dimensions please see 
        // Image remarks at https://go.microsoft.com/fwlink/?linkid=872754.

        java.lang.String MEDIA_FILE_PATH = "c:\\dev\\media\\";
        java.lang.String IMAGE_AD_EXTENSION_MEDIA_FILE_NAME = "imageadextension300x200.png";
        
        try
        {
            authorizationData = getAuthorizationData();

            CampaignManagementExampleHelper.CampaignManagementService = new ServiceClient<ICampaignManagementService>(
                    authorizationData,
                    API_ENVIRONMENT,
                    ICampaignManagementService.class);
                        
            Calendar calendar = Calendar.getInstance();
                                      
            // Add a campaign to associate with ad extensions. 

            ArrayOfCampaign campaigns = new ArrayOfCampaign();
            Campaign campaign = new Campaign();
            campaign.setBudgetType(BudgetLimitType.DAILY_BUDGET_STANDARD);
            campaign.setDailyBudget(50.00);
            ArrayOfstring languages = new ArrayOfstring();
            languages.getStrings().add("All");
            campaign.setLanguages(languages);
            campaign.setName("Everyone's Shoes " + System.currentTimeMillis());
            campaign.setTimeZone("PacificTimeUSCanadaTijuana");
            campaigns.getCampaigns().add(campaign);

            outputStatusMessage("-----\nAddCampaigns:");
            AddCampaignsResponse addCampaignsResponse = CampaignManagementExampleHelper.addCampaigns(
                authorizationData.getAccountId(), 
                campaigns
            );            
            ArrayOfNullableOflong campaignIds = addCampaignsResponse.getCampaignIds();
            ArrayOfBatchError campaignErrors = addCampaignsResponse.getPartialErrors();
            outputStatusMessage("CampaignIds:");
            CampaignManagementExampleHelper.outputArrayOfNullableOflong(campaignIds);
            outputStatusMessage("PartialErrors:");
            CampaignManagementExampleHelper.outputArrayOfBatchError(campaignErrors);
            
            // Create media for the image ad extension that we'll add later. 
            
            Image imageAdExtensionMedia = getImageMedia(
                "Image15x10",
                MEDIA_FILE_PATH + IMAGE_AD_EXTENSION_MEDIA_FILE_NAME);

            ArrayOfMedia addMedia = new ArrayOfMedia();
            addMedia.getMedias().add(imageAdExtensionMedia);
            CampaignManagementExampleHelper.outputArrayOfMedia(addMedia);

            outputStatusMessage("-----\nAddMedia:");
            ArrayOflong mediaIds = CampaignManagementExampleHelper.addMedia(
                authorizationData.getAccountId(),
                addMedia).getMediaIds();
            outputStatusMessage("MediaIds:");
            CampaignManagementExampleHelper.outputArrayOflong(mediaIds);

            // Add the extensions to the account's library.

            ArrayOfAdExtension adExtensions = new ArrayOfAdExtension();
            
            ActionAdExtension actionAdExtension = new ActionAdExtension();
            actionAdExtension.setActionType(ActionAdExtensionActionType.ACT_NOW);
            com.microsoft.bingads.v13.campaignmanagement.ArrayOfstring finalUrls = new com.microsoft.bingads.v13.campaignmanagement.ArrayOfstring();
            finalUrls.getStrings().add("https://www.contoso.com/womenshoesale");
            actionAdExtension.setFinalUrls(finalUrls);
            actionAdExtension.setLanguage("English");
            actionAdExtension.setStatus(AdExtensionStatus.ACTIVE);
            adExtensions.getAdExtensions().add(actionAdExtension);

            AppAdExtension appAdExtension = new AppAdExtension();
            appAdExtension.setAppPlatform("Windows");
            appAdExtension.setAppStoreId("AppStoreIdGoesHere");
            appAdExtension.setDestinationUrl("DestinationUrlGoesHere");
            appAdExtension.setDisplayText("Contoso");
            // If you supply the AppAdExtension properties above, then you can add this line.
            //adExtensions.getAdExtensions().add(appAdExtension);

            CallAdExtension callAdExtension = new CallAdExtension();
            callAdExtension.setCountryCode("US");
            callAdExtension.setPhoneNumber("2065550100");
            callAdExtension.setIsCallOnly(false);
            // Include the call extension Monday - Friday from 9am - 9pm
            // in the account's time zone.
            Schedule callScheduling = new Schedule();
            ArrayOfDayTime callDayTimeRanges = new ArrayOfDayTime();
            DayTime callMonday = new DayTime();
            callMonday.setDay(Day.MONDAY);
            callMonday.setStartHour(9);
            callMonday.setStartMinute(Minute.ZERO);
            callMonday.setEndHour(21);
            callMonday.setEndMinute(Minute.ZERO);
            callDayTimeRanges.getDayTimes().add(callMonday);
            DayTime callTuesday = new DayTime();
            callTuesday.setDay(Day.TUESDAY);
            callTuesday.setStartHour(9);
            callTuesday.setStartMinute(Minute.ZERO);
            callTuesday.setEndHour(21);
            callTuesday.setEndMinute(Minute.ZERO);
            callDayTimeRanges.getDayTimes().add(callTuesday);
            DayTime callWednesday = new DayTime();
            callWednesday.setDay(Day.WEDNESDAY);
            callWednesday.setStartHour(9);
            callWednesday.setStartMinute(Minute.ZERO);
            callWednesday.setEndHour(21);
            callWednesday.setEndMinute(Minute.ZERO);
            callDayTimeRanges.getDayTimes().add(callWednesday);
            DayTime callThursday = new DayTime();
            callThursday.setDay(Day.THURSDAY);
            callThursday.setStartHour(9);
            callThursday.setStartMinute(Minute.ZERO);
            callThursday.setEndHour(21);
            callThursday.setEndMinute(Minute.ZERO);
            callDayTimeRanges.getDayTimes().add(callThursday);
            DayTime callFriday = new DayTime();
            callFriday.setDay(Day.FRIDAY);
            callFriday.setStartHour(9);
            callFriday.setStartMinute(Minute.ZERO);
            callFriday.setEndHour(21);
            callFriday.setEndMinute(Minute.ZERO);
            callDayTimeRanges.getDayTimes().add(callFriday);
            callScheduling.setDayTimeRanges(callDayTimeRanges);
            callScheduling.setEndDate(new com.microsoft.bingads.v13.campaignmanagement.Date());
            callScheduling.getEndDate().setDay(31);
            callScheduling.getEndDate().setMonth(12);
            callScheduling.getEndDate().setYear(calendar.get(Calendar.YEAR) + 1);
            callScheduling.setStartDate(null);
            callAdExtension.setScheduling(callScheduling);
            adExtensions.getAdExtensions().add(callAdExtension);

            CalloutAdExtension calloutAdExtension = new CalloutAdExtension();
            calloutAdExtension.setText("Callout text");
            adExtensions.getAdExtensions().add(calloutAdExtension);

            LocationAdExtension locationAdExtension = new LocationAdExtension();
            locationAdExtension.setPhoneNumber("206-555-0100");
            locationAdExtension.setCompanyName("Contoso Shoes");
            com.microsoft.bingads.v13.campaignmanagement.Address address = 
                    new com.microsoft.bingads.v13.campaignmanagement.Address();
            address.setStreetAddress("1234 Washington Place");
            address.setStreetAddress2("Suite 1210");
            address.setCityName("Woodinville");
            address.setProvinceName("WA"); 
            address.setCountryCode("US");
            address.setPostalCode("98608");
            locationAdExtension.setAddress(address);
            // Include the location extension every Saturday morning
            // in the search user's time zone.
            Schedule locationScheduling = new Schedule();
            ArrayOfDayTime locationDayTimeRanges = new ArrayOfDayTime();
            DayTime locationDayTime = new DayTime();
            locationDayTime.setDay(Day.SATURDAY);
            locationDayTime.setStartHour(9);
            locationDayTime.setStartMinute(Minute.ZERO);
            locationDayTime.setEndHour(12);
            locationDayTime.setEndMinute(Minute.ZERO);
            locationDayTimeRanges.getDayTimes().add(locationDayTime);
            locationScheduling.setDayTimeRanges(locationDayTimeRanges);
            locationScheduling.setEndDate(new com.microsoft.bingads.v13.campaignmanagement.Date());
            locationScheduling.getEndDate().setDay(31);
            locationScheduling.getEndDate().setMonth(12);
            locationScheduling.getEndDate().setYear(calendar.get(Calendar.YEAR) + 1);
            locationScheduling.setStartDate(null);
            locationAdExtension.setScheduling(locationScheduling);
            adExtensions.getAdExtensions().add(locationAdExtension);
            
            PriceAdExtension priceAdExtension = new PriceAdExtension();
            priceAdExtension.setLanguage("English");
            priceAdExtension.setPriceExtensionType(PriceExtensionType.EVENTS);
            ArrayOfPriceTableRow tableRows = new ArrayOfPriceTableRow();
            PriceTableRow tableRowA = new PriceTableRow();
            tableRowA.setCurrencyCode("USD");
            tableRowA.setDescription("Come to the event");
            tableRowA.setFinalUrls(finalUrls);
            tableRowA.setHeader("New Event");
            tableRowA.setPrice(9.99D);
            tableRowA.setPriceQualifier(PriceQualifier.FROM);
            tableRowA.setPriceUnit(PriceUnit.PER_DAY);
            tableRows.getPriceTableRows().add(tableRowA);
            PriceTableRow tableRowB = new PriceTableRow();
            tableRowB.setCurrencyCode("USD");
            tableRowB.setDescription("Come to the next event");
            tableRowB.setFinalUrls(finalUrls);
            tableRowB.setHeader("Next Event");
            tableRowB.setPrice(9.99D);
            tableRowB.setPriceQualifier(PriceQualifier.FROM);
            tableRowB.setPriceUnit(PriceUnit.PER_DAY);
            tableRows.getPriceTableRows().add(tableRowB);
            PriceTableRow tableRowC = new PriceTableRow();
            tableRowC.setCurrencyCode("USD");
            tableRowC.setDescription("Come to the final event");
            tableRowC.setFinalUrls(finalUrls);
            tableRowC.setHeader("Final Event");
            tableRowC.setPrice(9.99D);
            tableRowC.setPriceQualifier(PriceQualifier.FROM);
            tableRowC.setPriceUnit(PriceUnit.PER_DAY);
            tableRows.getPriceTableRows().add(tableRowC);
            priceAdExtension.setTableRows(tableRows);
            adExtensions.getAdExtensions().add(priceAdExtension);

            ReviewAdExtension reviewAdExtension = new ReviewAdExtension();
            reviewAdExtension.setIsExact(true);
            reviewAdExtension.setSource("Review Source Name");
            reviewAdExtension.setText("Review Text");
            // The Url of the third-party review. This is not your business Url.
            reviewAdExtension.setUrl("https://review.contoso.com"); 
            adExtensions.getAdExtensions().add(reviewAdExtension);
            
            SitelinkAdExtension sitelinkAdExtension = new SitelinkAdExtension();
            sitelinkAdExtension.setDescription1("Simple & Transparent.");
            sitelinkAdExtension.setDescription2("No Upfront Cost.");
            sitelinkAdExtension.setDisplayText("Everyone's Shoe Sale");
            sitelinkAdExtension.setFinalUrls(finalUrls);
            adExtensions.getAdExtensions().add(sitelinkAdExtension);
                        
            StructuredSnippetAdExtension structuredSnippetAdExtension = new StructuredSnippetAdExtension();
            structuredSnippetAdExtension.setHeader("Brands");
            com.microsoft.bingads.v13.campaignmanagement.ArrayOfstring values = new com.microsoft.bingads.v13.campaignmanagement.ArrayOfstring();
            values.getStrings().add("Windows");
            values.getStrings().add("Xbox");
            values.getStrings().add("Skype");
            structuredSnippetAdExtension.setValues(values);
            adExtensions.getAdExtensions().add(structuredSnippetAdExtension);            
            
            outputStatusMessage("-----\nAddAdExtensions:");
            AddAdExtensionsResponse addAdExtensionsResponse = CampaignManagementExampleHelper.addAdExtensions(
                authorizationData.getAccountId(),
                adExtensions);
            outputStatusMessage("AdExtensionIdentities:");
            ArrayOfAdExtensionIdentity adExtensionIdentities = addAdExtensionsResponse.getAdExtensionIdentities();
            outputStatusMessage("NestedPartialErrors:");
            CampaignManagementExampleHelper.outputArrayOfBatchErrorCollection(addAdExtensionsResponse.getNestedPartialErrors());
            
            // DeleteAdExtensionsAssociations, SetAdExtensionsAssociations, and GetAdExtensionsEditorialReasons 
            // operations each require a list of type AdExtensionIdToEntityIdAssociation.
            ArrayOfAdExtensionIdToEntityIdAssociation adExtensionIdToEntityIdAssociations = new ArrayOfAdExtensionIdToEntityIdAssociation();

            // GetAdExtensionsByIds requires a list of type long.
            ArrayOflong adExtensionIds = new ArrayOflong();

            // Loop through the list of extension IDs and build any required data structures
            // for subsequent operations. 

            for (AdExtensionIdentity adExtensionIdentity : adExtensionIdentities.getAdExtensionIdentities()) {
                AdExtensionIdToEntityIdAssociation adExtensionIdToEntityIdAssociation = new AdExtensionIdToEntityIdAssociation();
                adExtensionIdToEntityIdAssociation.setAdExtensionId(adExtensionIdentity.getId());
                adExtensionIdToEntityIdAssociation.setEntityId(campaignIds.getLongs().get(0));
                adExtensionIdToEntityIdAssociations.getAdExtensionIdToEntityIdAssociations().add(adExtensionIdToEntityIdAssociation);

                adExtensionIds.getLongs().add(adExtensionIdentity.getId());
            }

            // Associate the ad extensions with the campaign. 
            
            outputStatusMessage("-----\nSetAdExtensionsAssociations:");
            SetAdExtensionsAssociationsResponse setAdExtensionsAssociationsResponse = CampaignManagementExampleHelper.setAdExtensionsAssociations(
                authorizationData.getAccountId(), 
                adExtensionIdToEntityIdAssociations, 
                AssociationType.CAMPAIGN);
            outputStatusMessage("PartialErrors:");
            CampaignManagementExampleHelper.outputArrayOfBatchError(setAdExtensionsAssociationsResponse.getPartialErrors());
            
            // Get editorial rejection reasons for the ad extension and entity associations.
            
            outputStatusMessage("-----\nGetAdExtensionsEditorialReasons:");
            GetAdExtensionsEditorialReasonsResponse getAdExtensionsEditorialReasonsResponse = CampaignManagementExampleHelper.getAdExtensionsEditorialReasons(
                authorizationData.getAccountId(), 
                adExtensionIdToEntityIdAssociations, 
                AssociationType.CAMPAIGN);
            outputStatusMessage("EditorialReasons:");
            ArrayOfAdExtensionEditorialReasonCollection adExtensionEditorialReasonCollection = getAdExtensionsEditorialReasonsResponse.getEditorialReasons();
            CampaignManagementExampleHelper.outputArrayOfAdExtensionEditorialReasonCollection(adExtensionEditorialReasonCollection);
            outputStatusMessage("PartialErrors:");
            CampaignManagementExampleHelper.outputArrayOfBatchError(getAdExtensionsEditorialReasonsResponse.getPartialErrors());
            
            // Get only the location extensions and remove scheduling.

            ArrayList<AdExtensionsTypeFilter> adExtensionsTypeFilter = new ArrayList<AdExtensionsTypeFilter>();
            adExtensionsTypeFilter.add(AdExtensionsTypeFilter.LOCATION_AD_EXTENSION);
            
            ArrayList<AdExtensionAdditionalField> returnAdditionalFields = new ArrayList<AdExtensionAdditionalField>();
            returnAdditionalFields.add(AdExtensionAdditionalField.DISPLAY_TEXT);
            returnAdditionalFields.add(AdExtensionAdditionalField.IMAGES);

            // In this example partial errors will be returned for indices where the ad extensions 
            // are not location ad extensions.
            // This is an example, and ideally you would only send the required ad extension IDs.
            
            outputStatusMessage("-----\nGetAdExtensionsByIds:");
            GetAdExtensionsByIdsResponse getAdExtensionsByIdsResponse = CampaignManagementExampleHelper.getAdExtensionsByIds(
                authorizationData.getAccountId(),
                adExtensionIds,
                adExtensionsTypeFilter,
                returnAdditionalFields);
            adExtensions = getAdExtensionsByIdsResponse.getAdExtensions();
            outputStatusMessage("AdExtensions:");
            CampaignManagementExampleHelper.outputArrayOfAdExtension(adExtensions);
            outputStatusMessage("PartialErrors:");
            CampaignManagementExampleHelper.outputArrayOfBatchError(getAdExtensionsByIdsResponse.getPartialErrors());     

            ArrayOfAdExtension updateExtensions = new ArrayOfAdExtension();
            ArrayOflong updateExtensionIds = new ArrayOflong();

            for (AdExtension extension : adExtensions.getAdExtensions())
            {
                // GetAdExtensionsByIds will return a nil element if the request conditions were not met.
                if(extension != null && extension.getId() != null)
                {
                    // Remove read-only elements that would otherwise cause the update operation to fail.
                    AdExtension updateExtension = setReadOnlyAdExtensionElementsToNull(extension);

                    // If you set the Scheduling element null, any existing scheduling set for the ad extension will remain unchanged. 
                    // If you set this to any non-null Schedule object, you are effectively replacing existing scheduling 
                    // for the ad extension. In this example, we will remove any existing scheduling by setting this element  
                    // to an empty Schedule object.
                    updateExtension.setScheduling(new Schedule());
                    updateExtensions.getAdExtensions().add(updateExtension);
                    updateExtensionIds.getLongs().add((long)updateExtension.getId());
                }
            }

            outputStatusMessage("-----\nUpdateAdExtensions:"); 
            CampaignManagementExampleHelper.updateAdExtensions(
                    authorizationData.getAccountId(), 
                    updateExtensions);
            outputStatusMessage("Removed scheduling from the location ad extensions.");

            // Get only the location extension to output the result.
            
            outputStatusMessage("-----\nGetAdExtensionsByIds:");
            getAdExtensionsByIdsResponse = CampaignManagementExampleHelper.getAdExtensionsByIds(
                authorizationData.getAccountId(),
                adExtensionIds,
                adExtensionsTypeFilter,
                returnAdditionalFields);
            adExtensions = getAdExtensionsByIdsResponse.getAdExtensions();
            outputStatusMessage("AdExtensions:");
            CampaignManagementExampleHelper.outputArrayOfAdExtension(adExtensions);
            outputStatusMessage("PartialErrors:");
            CampaignManagementExampleHelper.outputArrayOfBatchError(getAdExtensionsByIdsResponse.getPartialErrors());  

            // Delete the ad extension associations, ad extensions, and campaign, that were previously added.  
            // At this point the ad extensions are still available in the account's ad extensions library. 
            
            outputStatusMessage("-----\nDeleteAdExtensionsAssociations:");
            CampaignManagementExampleHelper.deleteAdExtensionsAssociations(
                authorizationData.getAccountId(),
                adExtensionIdToEntityIdAssociations,
                AssociationType.CAMPAIGN);
            outputStatusMessage("Deleted ad extension associations.");

            // Delete the ad extensions from the account’s ad extension library.

            outputStatusMessage("-----\nDeleteAdExtensions:");
            CampaignManagementExampleHelper.deleteAdExtensions(
                authorizationData.getAccountId(),
                adExtensionIds);
            outputStatusMessage("Deleted ad extensions.");
            
            // Delete the account's media that was used for the image ad extension.
            
            outputStatusMessage("-----\nDeleteMedia:");
            CampaignManagementExampleHelper.deleteMedia(
                    authorizationData.getAccountId(), 
                    mediaIds);

            for (java.lang.Long id : mediaIds.getLongs())
            {
                outputStatusMessage(String.format("Deleted Media Id %s", id));
            }

            // Delete the campaign and everything it contains e.g., ad groups and ads.

            outputStatusMessage("-----\nDeleteCampaigns:");
            ArrayOflong deleteCampaignIds = new ArrayOflong();
            deleteCampaignIds.getLongs().add(campaignIds.getLongs().get(0));
            CampaignManagementExampleHelper.deleteCampaigns(
                    authorizationData.getAccountId(), 
                    deleteCampaignIds);
            outputStatusMessage(String.format("Deleted CampaignId %d", deleteCampaignIds.getLongs().get(0)));        
        } 
        catch (Exception ex) {
            String faultXml = ExampleExceptionHelper.getBingAdsExceptionFaultXml(ex, System.out);
            outputStatusMessage(faultXml);
            String message = ExampleExceptionHelper.handleBingAdsSDKException(ex, System.out);
            outputStatusMessage(message);
        }
    }        
    
    // Get image media that can be managed with the Campaign Management API.

    static Image getImageMedia(
        java.lang.String mediaType, 
        java.lang.String imageFileName) throws UnsupportedEncodingException, IOException
    {
        Image image = new Image();
        image.setData(getBmpBase64String(imageFileName));
        image.setMediaType(mediaType);
        image.setType("Image");

        return image;
    }

    // Get the image media as base64 string.

    static java.lang.String getBmpBase64String(
        java.lang.String imageFileName) throws UnsupportedEncodingException, IOException
    {
        File fi = new File(imageFileName);
        byte[] imageBytes = Files.readAllBytes(fi.toPath());
        java.lang.String base64String = new java.lang.String(Base64.getEncoder().encode(imageBytes), "UTF-8");
        return base64String;
    }
}
<?php

use Microsoft\MsAds\Rest\ApiException;
use Microsoft\MsAds\Rest\Model\CampaignManagementService\ActionAdExtension;
use Microsoft\MsAds\Rest\Model\CampaignManagementService\ActionAdExtensionActionType;
use Microsoft\MsAds\Rest\Model\CampaignManagementService\AddAdExtensionsRequest;
use Microsoft\MsAds\Rest\Model\CampaignManagementService\AddMediaRequest;
use Microsoft\MsAds\Rest\Model\CampaignManagementService\Address;
use Microsoft\MsAds\Rest\Model\CampaignManagementService\AdExtensionIdToEntityIdAssociation;
use Microsoft\MsAds\Rest\Model\CampaignManagementService\AdExtensionStatus;
use Microsoft\MsAds\Rest\Model\CampaignManagementService\AdExtensionsTypeFilter;
use Microsoft\MsAds\Rest\Model\CampaignManagementService\AppAdExtension;
use Microsoft\MsAds\Rest\Model\CampaignManagementService\AssociationType;
use Microsoft\MsAds\Rest\Model\CampaignManagementService\BudgetLimitType;
use Microsoft\MsAds\Rest\Model\CampaignManagementService\CallAdExtension;
use Microsoft\MsAds\Rest\Model\CampaignManagementService\CalloutAdExtension;
use Microsoft\MsAds\Rest\Model\CampaignManagementService\Campaign;
use Microsoft\MsAds\Rest\Model\CampaignManagementService\CampaignType;
use Microsoft\MsAds\Rest\Model\CampaignManagementService\Date;
use Microsoft\MsAds\Rest\Model\CampaignManagementService\Day;
use Microsoft\MsAds\Rest\Model\CampaignManagementService\DayTime;
use Microsoft\MsAds\Rest\Model\CampaignManagementService\DeleteAdExtensionsAssociationsRequest;
use Microsoft\MsAds\Rest\Model\CampaignManagementService\DeleteAdExtensionsRequest;
use Microsoft\MsAds\Rest\Model\CampaignManagementService\DeleteMediaRequest;
use Microsoft\MsAds\Rest\Model\CampaignManagementService\GetAdExtensionsByIdsRequest;
use Microsoft\MsAds\Rest\Model\CampaignManagementService\GetAdExtensionsEditorialReasonsRequest;
use Microsoft\MsAds\Rest\Model\CampaignManagementService\GetCampaignsByIdsRequest;
use Microsoft\MsAds\Rest\Model\CampaignManagementService\LocationAdExtension;
use Microsoft\MsAds\Rest\Model\CampaignManagementService\Minute;
use Microsoft\MsAds\Rest\Model\CampaignManagementService\PriceAdExtension;
use Microsoft\MsAds\Rest\Model\CampaignManagementService\PriceTableRow;
use Microsoft\MsAds\Rest\Model\CampaignManagementService\ReviewAdExtension;
use Microsoft\MsAds\Rest\Model\CampaignManagementService\Schedule;
use Microsoft\MsAds\Rest\Model\CampaignManagementService\SetAdExtensionsAssociationsRequest;
use Microsoft\MsAds\Rest\Model\CampaignManagementService\SitelinkAdExtension;
use Microsoft\MsAds\Rest\Model\CampaignManagementService\StructuredSnippetAdExtension;
use Microsoft\MsAds\Rest\Model\CampaignManagementService\UpdateAdExtensionsRequest;
use Microsoft\MsAds\Rest\Test\RestApiTestBase;

class AdExtensionsTest extends RestApiTestBase
{

    // To run this example you'll need to provide your own image.
    // For required aspect ratios and recommended dimensions please see
    // Image remarks at https://go.microsoft.com/fwlink/?linkid=872754.
    protected string $mediaFilePath = "c:\\dev\\media\\";
    protected string $imageAdExtensionMediaFileName = "imageadextension300x200.png";

    // Add a new search campaign.

    /**
     * @throws ApiException
     */
    public function testAddCampaigns()
    {
        $budgetLimitType = BudgetLimitType::DAILY_BUDGET_STANDARD;
        $campaignType = CampaignType::SEARCH;
        $campaign = new Campaign();
        $campaign->setName("Women's Shoes ".self::generateRandomAlphaNumeric());
        $campaign->setBudgetType($budgetLimitType);
        $campaign->setDailyBudget(50.00);
        $campaign->setLanguages(array("All"));
        $campaign->setTimeZone("PacificTimeUSCanadaTijuana");
        $campaign->setCampaignType($campaignType);

        print("-----\r\nGetAdExtensionsByIds:\r\n");
        $request = new GetAdExtensionsByIdsRequest(
            [
                'AccountId' => self::CUSTOMER_ACCOUNT_ID,
                'AdExtensionIds' => [1, 2, 3],
                'AdExtensionType' => [
                    AdExtensionsTypeFilter::LOCATION_AD_EXTENSION,
                    AdExtensionsTypeFilter::CALL_AD_EXTENSION
                ],
                'ReturnAdditionalFields' => null
            ]
        );
        $response = self::$campaignManagementServiceApi->getAdExtensionsByIds($request);

        return self::addCampaignsRequest([$campaign]);
    }

    /**
     * @depends testAddCampaigns
     * @throws ApiException
     */
    public function testGetCampaigns($campaignIds)
    {
        $budgetLimitType = BudgetLimitType::DAILY_BUDGET_STANDARD;
        $campaignType = CampaignType::SEARCH;
        $request = new GetCampaignsByIdsRequest(
            [
                'AccountId' => self::CUSTOMER_ACCOUNT_ID,
                'CampaignIds' => $campaignIds
            ]
        );
        $getCampaignsResponse = self::$campaignManagementServiceApi->getCampaignsByIds($request);
        print("GetCampaignsByIds:\r\n");
        print_r($getCampaignsResponse->getCampaigns());
        print("PartialErrors:\r\n");
        print_r($getCampaignsResponse->getPartialErrors());
        self::assertEmpty($getCampaignsResponse->getPartialErrors());
        self::assertEquals($budgetLimitType, $getCampaignsResponse->getCampaigns()[0]->getBudgetType());
        self::assertEquals($campaignType, $getCampaignsResponse->getCampaigns()[0]->getCampaignType());

        return $campaignIds;
    }

    /**
     * @depends testGetCampaigns
     * @throws ApiException
     */
    public function testAdExtensions($campaignIds)
    {
        $imageAdExtensionMedia = $this->GetImageMedia(
            "Image15x10",
            $this->mediaFilePath.$this->imageAdExtensionMediaFileName
        );

        $addMedia = array();
        $addMedia[] = $imageAdExtensionMedia;

        print("-----\r\nAddMedia:\r\n");
        $request = new AddMediaRequest(
            [
                'AccountId' => self::CUSTOMER_ACCOUNT_ID,
                'Media' => $addMedia
            ]
        );
        $response = self::$campaignManagementServiceApi->addMedia($request);
        $mediaIds = $response->getMediaIds();
        print("MediaIds:\r\n");
        print_r($mediaIds);

        // Add the extensions to the account's library.

        $adExtensions = array();

        $extension = new ActionAdExtension();
        $extension->setActionType(ActionAdExtensionActionType::ACT_NOW);
        $extension->setFinalUrls(array("http://www.contoso.com/womenshoesale"));
        $extension->setLanguage("English");
        $extension->setStatus(AdExtensionStatus::ACTIVE);

        $adExtensions[] = $extension;

        $extension = new AppAdExtension();
        $extension->setAppPlatform("Windows");
        $extension->setAppStoreId("AppStoreIdGoesHere");
        $extension->setDisplayText("Contoso");
        $extension->setDestinationUrl("DestinationUrlGoesHere");
        // If you supply the AppAdExtension properties above, then you can add this line.
        //$adExtensions[] = $encodedExtension;

        $extension = new CallAdExtension();
        $extension->setCountryCode("US");
        $extension->setPhoneNumber("2065550100");
        $extension->setIsCallOnly(false);

        // Include the call extension Monday - Friday from 9am - 9pm
        // in the account's time zone.
        $callScheduling = new Schedule();
        $callDayTimeRanges = array();
        for ($index = 0; $index < 5; $index++) {
            $dayTime = new DayTime();
            $dayTime->setStartHour(9);
            $dayTime->setStartMinute(Minute::ZERO);
            $dayTime->setEndHour(21);
            $dayTime->setEndMinute(Minute::ZERO);
            $callDayTimeRanges[] = $dayTime;
        }
        $callDayTimeRanges[0]->setDay(Day::MONDAY);
        $callDayTimeRanges[1]->setDay(Day::TUESDAY);
        $callDayTimeRanges[2]->setDay(Day::WEDNESDAY);
        $callDayTimeRanges[3]->setDay(Day::THURSDAY);
        $callDayTimeRanges[4]->setDay(Day::FRIDAY);
        $callScheduling->setDayTimeRanges($callDayTimeRanges);
        $callScheduling->setUseSearcherTimeZone(false);
        $callScheduling->setStartDate(null);

        $callSchedulingEndDate = new Date();
        $callSchedulingEndDate->setDay(31);
        $callSchedulingEndDate->setMonth(12);
        $callSchedulingEndDate->setYear(date("Y"));
        $callScheduling->setEndDate($callSchedulingEndDate);

        $extension->setScheduling($callScheduling);
        $adExtensions[] = $extension;

        $extension = new CalloutAdExtension();
        $extension->setText("Callout Text");
        $adExtensions[] = $extension;

        $extension = new LocationAdExtension();
        $extension->setPhoneNumber("206-555-0100");
        $extension->setCompanyName("Alpine Ski House");

        $address = new Address();
        $address->setStreetAddress("1234 Washington Place");
        $address->setStreetAddress2("Suite 1210");
        $address->setCityName("Woodinville");
        $address->setProvinceName("WA");
        $address->setCountryCode("US");
        $address->setPostalCode("98608");
        $extension->setAddress($address);

        // Include the location extension every Saturday morning
        // in the search user's time zone.
        $locationScheduling = new Schedule();
        $locationDayTimeRanges = array();

        $locationDayTime = new DayTime();
        $locationDayTime->setDay(Day::SATURDAY);
        $locationDayTime->setStartHour(9);
        $locationDayTime->setStartMinute(Minute::ZERO);
        $locationDayTime->setEndHour(12);
        $locationDayTime->setEndMinute(Minute::ZERO);
        $locationDayTimeRanges[] = $locationDayTime;

        $locationScheduling->setDayTimeRanges($locationDayTimeRanges);
        $locationScheduling->setUseSearcherTimeZone(false);
        $locationScheduling->setStartDate(null);

        $locationSchedulingEndDate = new Date();
        $locationSchedulingEndDate->setDay(31);
        $locationSchedulingEndDate->setMonth(12);
        $locationSchedulingEndDate->setYear(date("Y"));
        $locationScheduling->setEndDate($locationSchedulingEndDate);

        $extension->setScheduling($locationScheduling);
        $adExtensions[] = $extension;

        $extension = new PriceAdExtension();
        $extension->setLanguage("English");
        $extension->setPriceExtensionType('Events');

        $tableRows = array();

        $tableRowA = new PriceTableRow();
        $tableRowA->setCurrencyCode("USD");
        $tableRowA->setDescription("Come to the event");
        $tableRowA->setFinalUrls(array("http://www.contoso.com/womenshoesale"));
        $tableRowA->setHeader("New Event");
        $tableRowA->setPrice(9.99);
        $tableRowA->setPriceQualifier('From');
        $tableRowA->setPriceUnit('PerDay');
        $tableRows[] = $tableRowA;

        $tableRowB = new PriceTableRow();
        $tableRowB->setCurrencyCode("USD");
        $tableRowB->setDescription("Come to the next event");
        $tableRowB->setFinalUrls(array("http://www.contoso.com/womenshoesale"));
        $tableRowB->setHeader("Next Event");
        $tableRowB->setPrice(9.99);
        $tableRowB->setPriceQualifier('From');
        $tableRowB->setPriceUnit('PerDay');
        $tableRows[] = $tableRowB;

        $tableRowC = new PriceTableRow();
        $tableRowC->setCurrencyCode("USD");
        $tableRowC->setDescription("Come to the final event");
        $tableRowC->setFinalUrls(array("http://www.contoso.com/womenshoesale"));
        $tableRowC->setHeader("Final Event");
        $tableRowC->setPrice(9.99);
        $tableRowC->setPriceQualifier('From');
        $tableRowC->setPriceUnit('PerDay');
        $tableRows[] = $tableRowC;

        $extension->setTableRows($tableRows);
        $adExtensions[] = $extension;

        $extension = new ReviewAdExtension();
        $extension->setIsExact(true);
        $extension->setSource("Review Source Name");
        $extension->setText("Review Text");
        // The Url of the third-party review. This is not your business Url.
        $extension->setUrl("http://review.contoso.com");
        $adExtensions[] = $extension;

        $extension = new SitelinkAdExtension();
        $extension->setDescription1("Simple & Transparent.");
        $extension->setDescription2("No Upfront Cost.");
        $extension->setDisplayText("Women's Shoe Sale");
        $extension->setFinalUrls(array("http://www.contoso.com/womenshoesale"));
        $adExtensions[] = $extension;

        $extension = new StructuredSnippetAdExtension();
        $extension->setHeader("Brands");
        $extension->setValues(array("Windows", "Xbox", "Skype"));
        $adExtensions[] = $extension;

        // Add all extensions to the account's ad extension library

        print("-----\r\nAddAdExtensions:\r\n");
        $request = new AddAdExtensionsRequest(
            [
                'AccountId' => self::CUSTOMER_ACCOUNT_ID,
                'AdExtensions' => $adExtensions
            ]
        );
        $response = self::$campaignManagementServiceApi->addAdExtensions($request);
        $adExtensionIdentities = $response->getAdExtensionIdentities();
        print("AdExtensionIdentities:\r\n");
        print_r($adExtensionIdentities);
        print("NestedPartialErrors:\r\n");
        print_r($response->getNestedPartialErrors());

        // DeleteAdExtensionsAssociations, SetAdExtensionsAssociations, and GetAdExtensionsEditorialReasons
        // operations each require a list of type AdExtensionIdToEntityIdAssociation.

        $adExtensionIdToEntityIdAssociations = array();

        // GetAdExtensionsByIds requires a list of type long.

        $adExtensionIds = array();

        // Loop through the list of extension IDs and build any required data structures
        // for subsequent operations.

        for ($index = 0; $index < count($adExtensionIdentities); $index++) {
            if (!empty($adExtensionIdentities[$index]) && $adExtensionIdentities[$index]->getId() !== null) {
                $adExtensionIdToEntityIdAssociations[$index] = new AdExtensionIdToEntityIdAssociation();
                $adExtensionIdToEntityIdAssociations[$index]->setAdExtensionId($adExtensionIdentities[$index]->getId());
                $adExtensionIdToEntityIdAssociations[$index]->setEntityId($campaignIds[0]);

                $adExtensionIds[$index] = $adExtensionIdentities[$index]->getId();
            }
        };

        // Associate the ad extensions with the campaign.

        print("-----\r\nSetAdExtensionsAssociations:\r\n");
        $request = new SetAdExtensionsAssociationsRequest(
            [
                'AccountId' => self::CUSTOMER_ACCOUNT_ID,
                'AdExtensionIdToEntityIdAssociations' => $adExtensionIdToEntityIdAssociations,
                'AssociationType' => AssociationType::CAMPAIGN
            ]
        );
        $response = self::$campaignManagementServiceApi->setAdExtensionsAssociations($request);
        print("PartialErrors:\r\n");
        print_r($response->getPartialErrors());
        self::assertEmpty($response->getPartialErrors());

        // Get editorial rejection reasons for the respective ad extension and entity associations.

        print("-----\r\nGetAdExtensionsEditorialReasons:\r\n");
        $request = new GetAdExtensionsEditorialReasonsRequest(
            [
                'AccountId' => self::CUSTOMER_ACCOUNT_ID,
                'AdExtensionIdToEntityIdAssociations' => $adExtensionIdToEntityIdAssociations,
                'AssociationType' => AssociationType::CAMPAIGN
            ]
        );
        $response = self::$campaignManagementServiceApi->getAdExtensionsEditorialReasons($request);
        $adExtensionEditorialReasonCollection = $response->getEditorialReasons();
        print("EditorialReasons:\r\n");
        print_r($adExtensionEditorialReasonCollection);
        print("PartialErrors:\r\n");
        print_r($response->getPartialErrors());
        self::assertEmpty($response->getPartialErrors());

        // Get only the location extensions and remove scheduling.

        $adExtensionsTypeFilter = array(
            AdExtensionsTypeFilter::LOCATION_AD_EXTENSION,
            AdExtensionsTypeFilter::CALL_AD_EXTENSION
        );

        // In this example partial errors will be returned for indices where the ad extensions
        // are not location ad extensions.
        // This is an example, and ideally you would only send the required ad extension IDs.

        print("-----\r\nGetAdExtensionsByIds:\r\n");
        $request = new GetAdExtensionsByIdsRequest(
            [
                'AccountId' => self::CUSTOMER_ACCOUNT_ID,
                'AdExtensionIds' => $adExtensionIds,
                'AdExtensionType' => $adExtensionsTypeFilter,
                'ReturnAdditionalFields' => null
            ]
        );
        $response = self::$campaignManagementServiceApi->getAdExtensionsByIds($request);
        $adExtensions = $response->getAdExtensions();
        print("AdExtensions:\r\n");
        print_r($adExtensions);
        print("PartialErrors:\r\n");
        print_r($response->getPartialErrors());
        self::assertNotEmpty($response->getPartialErrors());

        $updateExtensions = array();

        foreach ($adExtensions as $extension) {
            // GetAdExtensionsByIds will return a nil element if the request filters / conditions were not met.
            if (!empty($extension) && $extension->getId() !== null) {
                // Remove read-only elements that would otherwise cause the update operation to fail.
                $updateExtension = $extension;
                $updateExtension->offsetUnset('Version');
                $updateExtension->offsetUnset('GeoCodeStatus');

                // If you set the Scheduling element null, any existing scheduling set for the ad extension will remain unchanged.
                // If you set this to any non-null Schedule object, you are effectively replacing existing scheduling
                // for the ad extension. In this example, we will remove any existing scheduling by setting this element
                // to an empty Schedule object.
                $updateExtension->setScheduling(new Schedule());

                $updateExtensions[] = $updateExtension;
            }
        }

        print("-----\r\nUpdateAdExtensions:\r\n");
        $request = new UpdateAdExtensionsRequest(
            [
                'AccountId' => self::CUSTOMER_ACCOUNT_ID,
                'AdExtensions' => $updateExtensions
            ]
        );
        $response = self::$campaignManagementServiceApi->updateAdExtensions($request);
        print_r($request);
        print("NestedPartialErrors:\r\n");
        print_r($response->getNestedPartialErrors());
        self::assertEmpty($response->getNestedPartialErrors());
        print("Removed scheduling from the location ad extensions.\r\n");

        // Get only the location extension to output the result.

        print("-----\r\nGetAdExtensionsByIds:\r\n");
        $request = new GetAdExtensionsByIdsRequest(
            [
                'AccountId' => self::CUSTOMER_ACCOUNT_ID,
                'AdExtensionIds' => $adExtensionIds,
                'AdExtensionType' => $adExtensionsTypeFilter,
                'ReturnAdditionalFields' => null
            ]
        );
        $response = self::$campaignManagementServiceApi->getAdExtensionsByIds($request);
        print("AdExtensions:\r\n");
        print_r($response->getAdExtensions());
        print("PartialErrors:\r\n");
        print_r($response->getPartialErrors());
        self::assertNotEmpty($response->getPartialErrors());
        self::assertNotEmpty($response->getAdExtensions());
        foreach ($response->getAdExtensions() as $adExtension) {
            if (!empty($adExtension) && $adExtension->getId() !== null) {
                self::assertNull($adExtension->getScheduling());
            }
        }

        // Delete the ad extension associations, ad extensions, and campaign, that were previously added.
        // At this point the ad extensions are still available in the account's ad extensions library.

        print("-----\r\nDeleteAdExtensionsAssociations:\r\n");
        $request = new DeleteAdExtensionsAssociationsRequest(
            [
                'AccountId' => self::CUSTOMER_ACCOUNT_ID,
                'AdExtensionIdToEntityIdAssociations' => $adExtensionIdToEntityIdAssociations,
                'AssociationType' => AssociationType::CAMPAIGN
            ]
        );
        $response = self::$campaignManagementServiceApi->deleteAdExtensionsAssociations($request);
        print("PartialErrors:\r\n");
        print_r($response->getPartialErrors());
        self::assertEmpty($response->getPartialErrors());

        // Deletes the ad extensions from the account's ad extension library.

        print("-----\r\nDeleteAdExtensions:\r\n");
        $request = new DeleteAdExtensionsRequest(
            [
                'AccountId' => self::CUSTOMER_ACCOUNT_ID,
                'AdExtensionIds' => $adExtensionIds
            ]
        );
        $response = self::$campaignManagementServiceApi->deleteAdExtensions($request);
        print("PartialErrors:\r\n");
        print_r($response->getPartialErrors());
        self::assertEmpty($response->getPartialErrors());

        print("Deleted ad extensions.\r\n");

        // Delete the account's media that was used for the image ad extension.

        print("-----\r\nDeleteMedia:\r\n");
        $request = new DeleteMediaRequest(
            [
                'AccountId' => self::CUSTOMER_ACCOUNT_ID,
                'MediaIds' => $mediaIds
            ]
        );
        $response = self::$campaignManagementServiceApi->deleteMedia($request);
        print("PartialErrors:\r\n");
        print_r($response->getPartialErrors());
        self::assertEmpty($response->getPartialErrors());

        foreach ($mediaIds as $id) {
            printf("Deleted Media Id %s\r\n", $id);
        }

        // Delete the campaign and everything it contains e.g., ad groups and ads.

        self::deleteCampaignsRequest($campaignIds);
    }
}
import uuid
from auth_helper import *
from openapi_client.models.campaign import *

# Media file path - update with your own image
MEDIA_FILE_PATH = "c:\\dev\\media\\"
IMAGE_AD_EXTENSION_FILE_NAME = "imageadextension300x200.png"

def main(authorization_data):
    try:
        # Create a search campaign
        print("Creating campaign...")
        
        campaign = Campaign(
            name="Women's Shoes " + str(uuid.uuid4()),
            budget_type=BudgetLimitType.DAILYBUDGETSTANDARD,
            daily_budget=50.00,
            languages=['All'],
            time_zone='PacificTimeUSCanadaTijuana',
            campaign_type=CampaignType.SEARCH
        )
        
        add_campaigns_request = AddCampaignsRequest(
            account_id=authorization_data.account_id,
            campaigns=[campaign]
        )
        
        add_campaigns_response = campaign_service.add_campaigns(
            add_campaigns_request=add_campaigns_request
        )
        
        campaign_ids = add_campaigns_response.CampaignIds
        print(f"Created Campaign ID: {campaign_ids[0]}")
        
        # Create ad extensions
        print("\nCreating ad extensions...")
        
        ad_extensions = []
        
        # Action Ad Extension
        action_extension = ActionAdExtension(
            action_type=ActionAdExtensionActionType.ACTNOW,
            final_urls=["http://www.contoso.com/womenshoesale"],
            language="English",
            status=AdExtensionStatus.ACTIVE
        )
        ad_extensions.append(action_extension)
        
        # Call Ad Extension with scheduling
        call_extension = CallAdExtension(
            country_code="US",
            phone_number="2065550100",
            is_call_only=False
        )
        
        # Schedule for Monday-Friday 9am-9pm
        call_day_time_ranges = []
        for day in [Day.MONDAY, Day.TUESDAY, Day.WEDNESDAY, Day.THURSDAY, Day.FRIDAY]:
            day_time = DayTime(
                day=day,
                start_hour=9,
                start_minute=Minute.ZERO,
                end_hour=21,
                end_minute=Minute.ZERO
            )
            call_day_time_ranges.append(day_time)
        
        from datetime import datetime
        current_year = datetime.now().year
        
        call_scheduling = Schedule(
            day_time_ranges=call_day_time_ranges,
            use_searcher_time_zone=False,
            start_date=None,
            end_date=Date(day=31, month=12, year=current_year)
        )
        call_extension.Scheduling = call_scheduling
        ad_extensions.append(call_extension)
        
        # Callout Ad Extension
        callout_extension = CalloutAdExtension(
            text="Callout Text"
        )
        ad_extensions.append(callout_extension)
        
        # Location Ad Extension
        location_extension = LocationAdExtension(
            phone_number="206-555-0100",
            company_name="Alpine Ski House",
            address=Address(
                street_address="1234 Washington Place",
                street_address2="Suite 1210",
                city_name="Woodinville",
                province_name="WA",
                country_code="US",
                postal_code="98608"
            )
        )
        
        # Schedule for Saturday morning
        location_day_time = DayTime(
            day=Day.SATURDAY,
            start_hour=9,
            start_minute=Minute.ZERO,
            end_hour=12,
            end_minute=Minute.ZERO
        )
        
        location_scheduling = Schedule(
            day_time_ranges=[location_day_time],
            use_searcher_time_zone=False,
            start_date=None,
            end_date=Date(day=31, month=12, year=current_year)
        )
        location_extension.Scheduling = location_scheduling
        ad_extensions.append(location_extension)
        
        # Price Ad Extension
        price_extension = PriceAdExtension(
            language="English",
            price_extension_type="Events",
            table_rows=[
                PriceTableRow(
                    currency_code="USD",
                    description="Come to the event",
                    final_urls=["http://www.contoso.com/womenshoesale"],
                    header="New Event",
                    price=9.99,
                    price_qualifier="From",
                    price_unit="PerDay"
                ),
                PriceTableRow(
                    currency_code="USD",
                    description="Come to the next event",
                    final_urls=["http://www.contoso.com/womenshoesale"],
                    header="Next Event",
                    price=9.99,
                    price_qualifier="From",
                    price_unit="PerDay"
                ),
                PriceTableRow(
                    currency_code="USD",
                    description="Come to the final event",
                    final_urls=["http://www.contoso.com/womenshoesale"],
                    header="Final Event",
                    price=9.99,
                    price_qualifier="From",
                    price_unit="PerDay"
                )
            ]
        )
        ad_extensions.append(price_extension)
        
        # Review Ad Extension
        review_extension = ReviewAdExtension(
            is_exact=True,
            source="Review Source Name",
            text="Review Text",
            url="http://review.contoso.com"
        )
        ad_extensions.append(review_extension)
        
        # Sitelink Ad Extension
        sitelink_extension = SitelinkAdExtension(
            description1="Simple & Transparent.",
            description2="No Upfront Cost.",
            display_text="Women's Shoe Sale",
            final_urls=["http://www.contoso.com/womenshoesale"]
        )
        ad_extensions.append(sitelink_extension)
        
        # Structured Snippet Ad Extension
        structured_snippet_extension = StructuredSnippetAdExtension(
            header="Brands",
            values=["Windows", "Xbox", "Skype"]
        )
        ad_extensions.append(structured_snippet_extension)
        
        # Add all extensions to the account's ad extension library
        add_extensions_request = AddAdExtensionsRequest(
            account_id=authorization_data.account_id,
            ad_extensions=ad_extensions
        )
        
        add_extensions_response = campaign_service.add_ad_extensions(
            add_ad_extensions_request=add_extensions_request
        )
        
        ad_extension_identities = add_extensions_response.AdExtensionIdentities
        print(f"Added {len(ad_extension_identities)} ad extensions")
        
        if add_extensions_response.NestedPartialErrors:
            print(f"Nested Partial Errors: {add_extensions_response.NestedPartialErrors}")
        
        # Build associations
        ad_extension_id_to_entity_id_associations = []
        ad_extension_ids = []
        
        for identity in ad_extension_identities:
            if identity and identity.Id:
                association = AdExtensionIdToEntityIdAssociation(
                    ad_extension_id=identity.Id,
                    entity_id=campaign_ids[0]
                )
                ad_extension_id_to_entity_id_associations.append(association)
                ad_extension_ids.append(identity.Id)
        
        # Associate the ad extensions with the campaign
        print("\nAssociating ad extensions with campaign...")
        
        set_associations_request = SetAdExtensionsAssociationsRequest(
            account_id=authorization_data.account_id,
            ad_extension_id_to_entity_id_associations=ad_extension_id_to_entity_id_associations,
            association_type=AssociationType.CAMPAIGN
        )
        
        set_associations_response = campaign_service.set_ad_extensions_associations(
            set_ad_extensions_associations_request=set_associations_request
        )
        
        if set_associations_response.PartialErrors:
            print(f"Partial Errors: {set_associations_response.PartialErrors}")
        else:
            print("Ad extensions successfully associated with campaign")
        
        # Get editorial rejection reasons
        print("\nGetting editorial reasons...")
        
        get_editorial_request = GetAdExtensionsEditorialReasonsRequest(
            account_id=authorization_data.account_id,
            ad_extension_id_to_entity_id_associations=ad_extension_id_to_entity_id_associations,
            association_type=AssociationType.CAMPAIGN
        )
        
        editorial_response = campaign_service.get_ad_extensions_editorial_reasons(
            get_ad_extensions_editorial_reasons_request=get_editorial_request
        )
        
        if editorial_response.EditorialReasons:
            print(f"Editorial Reasons: {editorial_response.EditorialReasons}")
        
        # Get location and call extensions
        print("\nGetting location and call extensions...")
        
        get_extensions_request = GetAdExtensionsByIdsRequest(
            account_id=authorization_data.account_id,
            ad_extension_ids=ad_extension_ids,
            ad_extension_type= AdExtensionsTypeFilter.LOCATIONADEXTENSION | AdExtensionsTypeFilter.CALLADEXTENSION
            ,
            return_additional_fields=None
        )
        
        get_extensions_response = campaign_service.get_ad_extensions_by_ids(
            get_ad_extensions_by_ids_request=get_extensions_request
        )
        
        extensions_to_update = []
        
        for extension in get_extensions_response.AdExtensions:
            if extension and extension.Id:
                # Remove scheduling
                extension.Scheduling = Schedule()
                extensions_to_update.append(extension)
        
        # Update extensions to remove scheduling
        if extensions_to_update:
            print("\nUpdating extensions to remove scheduling...")
            
            update_request = UpdateAdExtensionsRequest(
                account_id=authorization_data.account_id,
                ad_extensions=extensions_to_update
            )
            
            update_response = campaign_service.update_ad_extensions(
                update_ad_extensions_request=update_request
            )
            
            if update_response.NestedPartialErrors:
                print(f"Nested Partial Errors: {update_response.NestedPartialErrors}")
            else:
                print("Removed scheduling from extensions")
        
        # Clean up - delete associations
        print("\nDeleting ad extension associations...")
        
        delete_associations_request = DeleteAdExtensionsAssociationsRequest(
            account_id=authorization_data.account_id,
            ad_extension_id_to_entity_id_associations=ad_extension_id_to_entity_id_associations,
            association_type=AssociationType.CAMPAIGN
        )
        
        delete_associations_response = campaign_service.delete_ad_extensions_associations(
            delete_ad_extensions_associations_request=delete_associations_request
        )
        
        if delete_associations_response.PartialErrors:
            print(f"Partial Errors: {delete_associations_response.PartialErrors}")
        
        # Delete ad extensions
        print("Deleting ad extensions...")
        
        delete_extensions_request = DeleteAdExtensionsRequest(
            account_id=authorization_data.account_id,
            ad_extension_ids=ad_extension_ids
        )
        
        delete_extensions_response = campaign_service.delete_ad_extensions(
            delete_ad_extensions_request=delete_extensions_request
        )
        
        if delete_extensions_response.PartialErrors:
            print(f"Partial Errors: {delete_extensions_response.PartialErrors}")
        else:
            print("Deleted ad extensions")
        
        # Delete campaign
        print("Deleting campaign...")
        
        delete_campaigns_request = DeleteCampaignsRequest(
            account_id=authorization_data.account_id,
            campaign_ids=campaign_ids
        )
        
        campaign_service.delete_campaigns(
            delete_campaigns_request=delete_campaigns_request
        )
        
        print(f"Deleted Campaign ID {campaign_ids[0]}")
        
    except Exception as ex:
        print(f"Error occurred: {str(ex)}")

if __name__ == '__main__':
    print("Loading the web service client...")
    
    authorization_data = AuthorizationData(
        account_id=None,
        customer_id=None,
        developer_token=DEVELOPER_TOKEN,
        authentication=None,
    )
    
    authenticate(authorization_data)
    
    campaign_service = ServiceClient(
        service='CampaignManagementService',
        version=13,
        authorization_data=authorization_data,
        environment=ENVIRONMENT,
    )
    
    main(authorization_data)

ดูเพิ่มเติม

เริ่มต้นใช้งาน Bing Ads API