Client Links Code Example

This example demonstrates how to use agency credentials to invite a client, and use client credentials to accept the invitation. Run this sample multiple times alternating between agency and client credentials to update and observe the status change, for example from LinkPending to LinkAccepted to Active.

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 sample. 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.Globalization;
using System.Linq;
using System.ServiceModel;
using System.Threading.Tasks;
using Microsoft.BingAds.V13.CustomerManagement;
using Microsoft.BingAds;

namespace BingAdsExamplesLibrary.V13
{
    /// <summary>
    /// How to use agency credentials to invite a client, and use client credentials to accept the invitation.
    /// Run this sample multiple times alternating between agency and client credentials 
    /// to update and observe the status change, for example from LinkPending to LinkAccepted to Active. 
    /// </summary>
    public class ClientLinks : ExampleBase
    {
        // REQUIRED: The Client Account Id that you want to access.
        private long ClientAccountId = 0; 

        public override string Description
        {
            get { return "Manage Client | Customer Management V13"; }
        }

        public async override Task RunAsync(AuthorizationData authorizationData)
        {
            try
            {
                OutputStatusMessage("You must edit this example to provide the ClientAccountId for the client link." +
                    "When adding a client link, the client link's ManagingCustomerId is set to the CustomerId " +
                    "of the current authenticated user, who must be a Super Admin of the agency." +
                    "Login as an agency Super Admin user to send a client link invitation, or unlink an existing client link." +
                    "Login as a client Super Admin user to accept a client link invitation.");

                ApiEnvironment environment = ((OAuthDesktopMobileAuthCodeGrant)authorizationData.Authentication).Environment;

                CustomerManagementExampleHelper CustomerManagementExampleHelper = new CustomerManagementExampleHelper(
                    OutputStatusMessageDefault: this.OutputStatusMessage);
                CustomerManagementExampleHelper.CustomerManagementService = new ServiceClient<ICustomerManagementService>(
                    authorizationData: authorizationData,
                    environment: environment);

                UpdateClientLinksResponse updateClientLinksResponse = null;

                // Set the client link search criteria.

                var pageInfo = new Paging
                {
                    Index = 0, // The first page
                    Size = 100 // The first 100 client links for this page of results
                };

                var ordering = new OrderBy
                {
                    Field = OrderByField.Number,
                    Order = SortOrder.Ascending
                };

                var predicate = new Predicate
                {
                    Field = "ClientAccountId",
                    Operator = PredicateOperator.In,
                    Value = ClientAccountId.ToString(CultureInfo.InvariantCulture)
                };

                // Search for client links that match the criteria.

                OutputStatusMessage("-----\nSearchClientLinks:");
                var searchClientLinksResponse = (await CustomerManagementExampleHelper.SearchClientLinksAsync(
                    predicates: new[] { predicate },
                    ordering: new[] { ordering },
                    pageInfo: pageInfo));
                var clientLinks = searchClientLinksResponse?.ClientLinks;
                OutputStatusMessage("ClientLinks:");
                CustomerManagementExampleHelper.OutputArrayOfClientLink(clientLinks);

                // Determine whether the agency is already managing the specified client account. 
                // If a link exists with status either Active, LinkInProgress, LinkPending, 
                // UnlinkInProgress, or UnlinkPending, the agency may not initiate a duplicate client link.

                ClientLink clientLink;
                var newLinkRequired = true;

                if (clientLinks.Count > 0)
                {
                    clientLink = clientLinks[0];
                    OutputStatusMessage("Using the first client link as an example.");
                    OutputStatusMessage(string.Format("Current ClientLink Status: {0}.", clientLink.Status));

                    switch (clientLink.Status)
                    {
                        // The agency may choose to initiate the unlink process, 
                        // which would terminate the existing relationship with the client. 
                        case ClientLinkStatus.Active:
                            clientLink.Status = ClientLinkStatus.UnlinkRequested;
                            OutputStatusMessage("-----\nUpdateClientLinks:");
                            updateClientLinksResponse = await CustomerManagementExampleHelper.UpdateClientLinksAsync(
                                clientLinks: new[] { clientLink });
                            OutputStatusMessage("UnlinkRequested");
                            newLinkRequired = false;
                            break;
                        // Waiting on a system status transition or waiting for the StartDate.
                        case ClientLinkStatus.LinkAccepted:
                            OutputStatusMessage("The status is transitioning towards LinkInProgress");
                            newLinkRequired = false;
                            break;
                        // Waiting on a system status transition.
                        case ClientLinkStatus.LinkInProgress:
                            OutputStatusMessage("The status is transitioning towards Active");
                            newLinkRequired = false;
                            break;
                        // When the status is LinkPending, either the agency or client may update the status.
                        // The agency may choose to cancel the client link invitation; however, in this example 
                        // the client will accept the invitation. 
                        // If the client does not accept or decline the invitation within 30 days, and if the agency
                        // does not update the status to LinkCanceled, the system updates the status to LinkExpired.
                        case ClientLinkStatus.LinkPending:
                            clientLink.Status = ClientLinkStatus.LinkAccepted;
                            OutputStatusMessage("-----\nUpdateClientLinks:");
                            updateClientLinksResponse = await CustomerManagementExampleHelper.UpdateClientLinksAsync(
                                clientLinks: new[] { clientLink });
                            OutputStatusMessage("LinkAccepted");
                            newLinkRequired = false;
                            break;
                        // Waiting on a system status transition.
                        case ClientLinkStatus.UnlinkInProgress:
                            OutputStatusMessage("The status is transitioning towards Inactive");
                            newLinkRequired = false;
                            break;
                        // Waiting on a system status transition.
                        case ClientLinkStatus.UnlinkPending:
                            OutputStatusMessage("The status is transitioning towards Inactive");
                            newLinkRequired = false;
                            break;
                        // The link lifecycle has ended.  
                        default:
                            OutputStatusMessage("A new client link invitation is required");
                            break;
                    }
                    
                    // Output errors if any occurred when updating the client link.

                    if (updateClientLinksResponse != null)
                    {
                        OutputStatusMessage("OperationErrors:");
                        CustomerManagementExampleHelper.OutputArrayOfOperationError(updateClientLinksResponse.OperationErrors);
                        OutputStatusMessage("PartialErrors:");
                        foreach (List<OperationError> operationErrors in updateClientLinksResponse.PartialErrors)
                        {
                            CustomerManagementExampleHelper.OutputArrayOfOperationError(operationErrors);
                        }
                    }
                }

                // If no links exist between the agency and specified client account, or a link exists with status  
                // either Inactive, LinkCanceled, LinkDeclined, LinkExpired, or LinkFailed, then the agency must
                // initiate a new client link.

                if (newLinkRequired)
                {
                    clientLink = new ClientLink
                    {
                        ClientEntityId = ClientAccountId,
                        ManagingCustomerId = authorizationData.CustomerId,
                        IsBillToClient = true,
                        Name = "My Client Link",
                        StartDate = null,
                        SuppressNotification = true
                    };

                    OutputStatusMessage("-----\nAddClientLinks:");
                    var addClientLinksResponse = await CustomerManagementExampleHelper.AddClientLinksAsync(
                        clientLinks: new[] { clientLink });
                    OutputStatusMessage("OperationErrors:");
                    CustomerManagementExampleHelper.OutputArrayOfOperationError(addClientLinksResponse.OperationErrors);
                    OutputStatusMessage("PartialErrors:");
                    foreach (List<OperationError> operationErrors in addClientLinksResponse.PartialErrors)
                    {
                        CustomerManagementExampleHelper.OutputArrayOfOperationError(operationErrors);
                    }
                }

                // Output the client links after any status updates above.

                OutputStatusMessage("-----\nSearchClientLinks:");
                searchClientLinksResponse = (await CustomerManagementExampleHelper.SearchClientLinksAsync(
                    predicates: new[] { predicate },
                    ordering: new[] { ordering },
                    pageInfo: pageInfo));
                clientLinks = searchClientLinksResponse?.ClientLinks;
                OutputStatusMessage("ClientLinks:");
                CustomerManagementExampleHelper.OutputArrayOfClientLink(clientLinks);
            }
            // 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 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);
            }
        }
    }
}
package com.microsoft.bingads.examples.v13;

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

// How to use agency credentials to invite a client, 
// and use client credentials to accept the invitation. 
// Run this sample multiple times alternating between agency and client credentials 
// to update and observe the status change, for example from LinkPending to LinkAccepted to Active. 

public class ClientLinks extends ExampleBase {

    static AuthorizationData authorizationData; 
    
    // REQUIRED: The Client Account Id that you want to access. 
    private static long ClientAccountId = 0; 
    
    public static void main(java.lang.String[] args) {
     
        try
        {
            authorizationData = getAuthorizationData(); 
            
            CustomerManagementExampleHelper.CustomerManagementService = new ServiceClient<ICustomerManagementService>(
                    authorizationData, 
                    API_ENVIRONMENT,
                    ICustomerManagementService.class);
            
            outputStatusMessage("You must edit this example to provide the ClientAccountId for the client link." +
                    "When adding a client link, the client link's ManagingCustomerId is set to the CustomerId " +
                    "of the current authenticated user, who must be a Super Admin of the agency." +
                    "Login as an agency Super Admin user to send a client link invitation, or unlink an existing client link." +
                    "Login as a client Super Admin user to accept a client link invitation.");
 
            UpdateClientLinksResponse updateClientLinksResponse = null;

            // Set the client link search criteria.

            Paging pageInfo = new Paging();
            pageInfo.setIndex(0);    // The first page
            pageInfo.setSize(100);   // The first 100 client links for this page of results
            
            ArrayOfOrderBy ordering = new ArrayOfOrderBy();
            OrderBy orderBy = new OrderBy();
            orderBy.setField(OrderByField.NUMBER);
            orderBy.setOrder(SortOrder.ASCENDING);
            ordering.getOrderBies().add(orderBy);

            ArrayOfPredicate predicates = new ArrayOfPredicate();
            Predicate predicate = new Predicate();
            predicate.setField("ClientAccountId");
            predicate.setOperator(PredicateOperator.IN);
            predicate.setValue("" + ClientAccountId);
            predicates.getPredicates().add(predicate);
            
            // Search for client links that match the criteria.

            outputStatusMessage("-----\nSearchClientLinks:");
            ArrayOfClientLink clientLinks = CustomerManagementExampleHelper.searchClientLinks(
                predicates,
                ordering,
                pageInfo).getClientLinks();
            outputStatusMessage("ClientLinks:");
            CustomerManagementExampleHelper.outputArrayOfClientLink(clientLinks);

            // Determine whether the agency is already managing the specified client account. 
            // If a link exists with status either Active, LinkInProgress, LinkPending, 
            // UnlinkInProgress, or UnlinkPending, the agency may not initiate a duplicate client link.

            ClientLink clientLink;
            boolean newLinkRequired = true;

            if (clientLinks.getClientLinks().size() > 0)
            {
                clientLink = clientLinks.getClientLinks().get(0);
                outputStatusMessage("Using the first client link as an example.");
                outputStatusMessage(String.format("Current ClientLink Status: %s.", clientLink.getStatus()));
                
                ArrayOfClientLink updateClientLinks = new ArrayOfClientLink();                
                
                switch (clientLink.getStatus())
                {
                    // The agency may choose to initiate the unlink process, 
                    // which would terminate the existing relationship with the client. 
                    case ACTIVE:
                        clientLink.setStatus(ClientLinkStatus.UNLINK_REQUESTED);
                        updateClientLinks.getClientLinks().add(clientLink);
                        outputStatusMessage("-----\nUpdateClientLinks:");
                        updateClientLinksResponse = CustomerManagementExampleHelper.updateClientLinks(
                                updateClientLinks);
                        outputStatusMessage("UpdateClientLinks : UnlinkRequested.");
                        newLinkRequired = false;
                        break;
                    // Waiting on a system status transition or waiting for the StartDate.
                    case LINK_ACCEPTED:
                        outputStatusMessage("The status is transitioning towards LinkInProgress.");
                        newLinkRequired = false;
                        break;
                    // Waiting on a system status transition.
                    case LINK_IN_PROGRESS:
                        outputStatusMessage("The status is transitioning towards Active.");
                        newLinkRequired = false;
                        break;
                    // When the status is LinkPending, either the agency or client may update the status.
                    // The agency may choose to cancel the client link invitation; however, in this example 
                    // the client will accept the invitation. 
                    // If the client does not accept or decline the invitation within 30 days, and if the agency
                    // does not update the status to LinkCanceled, the system updates the status to LinkExpired.
                    case LINK_PENDING:
                        clientLink.setStatus(ClientLinkStatus.LINK_ACCEPTED);
                        updateClientLinks.getClientLinks().add(clientLink);
                        outputStatusMessage("-----\nUpdateClientLinks:");
                        updateClientLinksResponse = CustomerManagementExampleHelper.updateClientLinks(
                                updateClientLinks);
                        outputStatusMessage("UpdateClientLinks: LinkAccepted.");
                        newLinkRequired = false;
                        break;
                    // Waiting on a system status transition.
                    case UNLINK_IN_PROGRESS:
                        outputStatusMessage("The status is transitioning towards Inactive.");
                        newLinkRequired = false;
                        break;
                    // Waiting on a system status transition.
                    case UNLINK_PENDING:
                        outputStatusMessage("The status is transitioning towards Inactive.");
                        newLinkRequired = false;
                        break;
                    // The link lifecycle has ended.  
                    default:
                        outputStatusMessage("A new client link invitation is required.");
                        break;
                }

                // Print errors if any occurred when updating the client link.
                if (updateClientLinksResponse != null)
                {
                    outputStatusMessage("OperationErrors:");   
                    CustomerManagementExampleHelper.outputArrayOfOperationError(updateClientLinksResponse.getOperationErrors());   
                    outputStatusMessage("PartialErrors:");
                    for(ArrayOfOperationError operationErrors: updateClientLinksResponse.getPartialErrors().getArrayOfOperationErrors())
                    {
                        CustomerManagementExampleHelper.outputArrayOfOperationError(operationErrors);   
                    }
                }
            }

            // If no links exist between the agency and specified client account, or a link exists with status  
            // either Inactive, LinkCanceled, LinkDeclined, LinkExpired, or LinkFailed, then the agency must
            // initiate a new client link.

            if(newLinkRequired)
            {
                clientLink = new ClientLink();
                clientLink.setClientEntityId(ClientAccountId);
                clientLink.setManagingCustomerId(authorizationData.getCustomerId());
                clientLink.setIsBillToClient(true);
                clientLink.setName("My Client Link");
                clientLink.setStartDate(null);
                clientLink.setSuppressNotification(true);

                ArrayOfClientLink addClientLinks = new ArrayOfClientLink();
                addClientLinks.getClientLinks().add(clientLink);
                
                outputStatusMessage("-----\nAddClientLinks:");
                AddClientLinksResponse addClientLinksResponse = CustomerManagementExampleHelper.addClientLinks(
                        addClientLinks);
                outputStatusMessage("OperationErrors:");                    
                CustomerManagementExampleHelper.outputArrayOfOperationError(addClientLinksResponse.getOperationErrors());   
                outputStatusMessage("PartialErrors:");
                for(ArrayOfOperationError operationErrors: addClientLinksResponse.getPartialErrors().getArrayOfOperationErrors())
                {
                    CustomerManagementExampleHelper.outputArrayOfOperationError(operationErrors);   
                }
            }

            // Output the client links after any status updates above.

            outputStatusMessage("-----\nSearchClientLinks:");
            clientLinks = CustomerManagementExampleHelper.searchClientLinks(
                predicates,
                ordering,
                pageInfo).getClientLinks();
            outputStatusMessage("ClientLinks:");
            CustomerManagementExampleHelper.outputArrayOfClientLink(clientLinks);
        } 
        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";

require_once __DIR__ . "/CustomerManagementExampleHelper.php";

include __DIR__ . "/AuthHelper.php";

use SoapVar;
use SoapFault;
use Exception;

// Specify the Microsoft\BingAds\V13\CustomerManagement classes that will be used.
use Microsoft\BingAds\V13\CustomerManagement\Paging;
use Microsoft\BingAds\V13\CustomerManagement\Predicate;
use Microsoft\BingAds\V13\CustomerManagement\PredicateOperator;
use Microsoft\BingAds\V13\CustomerManagement\ClientLink;
use Microsoft\BingAds\V13\CustomerManagement\ClientLinkStatus;
use Microsoft\BingAds\V13\CustomerManagement\OrderBy;
use Microsoft\BingAds\V13\CustomerManagement\OrderByField;
use Microsoft\BingAds\V13\CustomerManagement\SortOrder;
use Microsoft\BingAds\V13\CustomerManagement\OperationError;

// 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\CustomerManagementExampleHelper;

// How to use agency credentials to invite a client, and use client credentials to accept the invitation. 
// Run this sample multiple times alternating between agency and client credentials 
// to update and observe the status change, for example from LinkPending to LinkAccepted to Active.

print "You must edit this example to provide the ClientAccountId for the client link. " .
    "When adding a client link, the client link's ManagingCustomerId is set to the CustomerId " .
    "of the current authenticated user, who must be a Super Admin of the agency. " .
    "Login as an agency Super Admin user to send a client link invitation, or unlink an existing client link. " .
    "Login as a client Super Admin user to accept a client link invitation.\r\n";

// REQUIRED: The Client Account Id that you want to access.
$ClientAccountId = 0; 

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

    $updateClientLinksResponse = null;

    // Set the client link search criteria.

    $pageInfo = new Paging();
    $pageInfo->Index = 0;    // The first page
    $pageInfo->Size = 100;   // The first 100 client links for this page of results

    $ordering = new OrderBy();
    $ordering->Field = OrderByField::Number;
    $ordering->Order = SortOrder::Ascending;     

    $predicate = new Predicate();
    $predicate->Field = "ClientAccountId";
    $predicate->Operator = PredicateOperator::In;
    $predicate->Value = $ClientAccountId; 

    // Search for client links that match the criteria.

    print("-----\r\nSearchClientLinks:\r\n");
    $clientLinks = CustomerManagementExampleHelper::SearchClientLinks(
        array($predicate),
        array($ordering),
        $pageInfo
    );
    print("ClientLinks:\r\n");
    CustomerManagementExampleHelper::OutputArrayOfClientLink($clientLinks);

    print "-----\r\nLast SOAP request/response:\r\n";
    printf("Fault Code: %s\r\nFault String: %s\r\n", $e->faultcode, $e->faultstring);
    print $GLOBALS['Proxy']->GetWsdl() . "\r\n";
    print $GLOBALS['Proxy']->GetService()->__getLastRequest()."\r\n";
    print $GLOBALS['Proxy']->GetService()->__getLastResponse()."\r\n";

    // Determine whether the agency is already managing the specified client account. 
    // If a link exists with status either Active, LinkInProgress, LinkPending, 
    // UnlinkInProgress, or UnlinkPending, the agency may not initiate a duplicate client link.

    $clientLink;
    $newLinkRequired = true;

    if (isset($clientLinks->ClientLink) && count((array)$clientLinks->ClientLink) > 0)
    {
        $clientLink = $clientLinks->ClientLink[0];
        printf("Current ClientLink Status: %s.\r\n", $clientLink->Status);

        switch ($clientLink->Status)
        {
            // The agency may choose to initiate the unlink process, 
            // which would terminate the existing relationship with the client. 
            case ClientLinkStatus::Active:
                $clientLink->Status = ClientLinkStatus::UnlinkRequested;
                print("-----\r\nUpdateClientLinks:\r\n");
                $updateClientLinksResponse = CustomerManagementExampleHelper::UpdateClientLinks(
                    array($clientLink)
                );
                print("UnlinkRequested\r\n");
                $newLinkRequired = false;
                break;
            // Waiting on a system status transition or waiting for the StartDate.
            case ClientLinkStatus::LinkAccepted:
                print("The status is transitioning towards LinkInProgress.\r\n");
                $newLinkRequired = false;
                break;
            // Waiting on a system status transition.
            case ClientLinkStatus::LinkInProgress:
                print("The status is transitioning towards Active.\r\n");
                $newLinkRequired = false;
                break;
            // When the status is LinkPending, either the agency or client may update the status.
            // The agency may choose to cancel the client link invitation; however, in this sample 
            // the client will accept the invitation. 
            // If the client does not accept or decline the invitation within 30 days, and if the agency
            // does not update the status to LinkCanceled, the system updates the status to LinkExpired.
            case ClientLinkStatus::LinkPending:
                $clientLink->Status = ClientLinkStatus::LinkAccepted;
                print("-----\r\nUpdateClientLinks:\r\n");
                $updateClientLinksResponse = CustomerManagementExampleHelper::UpdateClientLinks(
                    array($clientLink)
                );
                print("LinkAccepted\r\n");
                $newLinkRequired = false;
                break;
            // Waiting on a system status transition.
            case ClientLinkStatus::UnlinkInProgress:
                print("The status is transitioning towards Inactive.\r\n");
                $newLinkRequired = false;
                break;
            // Waiting on a system status transition.
            case ClientLinkStatus::UnlinkPending:
                print("The status is transitioning towards Inactive.\r\n");
                $newLinkRequired = false;
                break;
            // The link lifecycle has ended.  
            default:
                print("A new client link invitation is required.\r\n");
                break;
        }

        // Output errors if any occurred when updating the client link.
        
        if (!empty($updateClientLinksResponse))
        {
            print("OperationErrors:\r\n");
            CustomerManagementExampleHelper::OutputArrayOfOperationError($updateClientLinksResponse->OperationErrors);
            print("PartialErrors:\r\n");
            foreach ($updateClientLinksResponse->PartialErrors as $operationErrors)
            {
                CustomerManagementExampleHelper::OutputArrayOfOperationError($operationErrors);
            }
        }
    }

    // If no links exist between the agency and specified client account, or a link exists with status  
    // either Inactive, LinkCanceled, LinkDeclined, LinkExpired, or LinkFailed, then the agency must
    // initiate a new client link.

    if($newLinkRequired)
    {
        $clientLink = new ClientLink();
        $clientLink->ClientEntityId = $ClientAccountId;
        $clientLink->ManagingCustomerId = $GLOBALS['AuthorizationData']->CustomerId;
        $clientLink->IsBillToClient = true;
        $clientLink->Name = "My Client Link";
        $clientLink->StartDate = null;
        $clientLink->SuppressNotification = false;
    
        print("-----\r\nAddClientLinks:\r\n");
        $addClientLinksResponse = CustomerManagementExampleHelper::AddClientLinks(
            array($clientLink)
        );
        print("OperationErrors:\r\n");
        CustomerManagementExampleHelper::OutputArrayOfOperationError($addClientLinksResponse->OperationErrors);
        print("PartialErrors:\r\n");
        foreach ($addClientLinksResponse->PartialErrors as $operationErrors)
        {
            CustomerManagementExampleHelper::OutputArrayOfOperationError($operationErrors);
        }
    }

    // Output the client links after any status updates above.

    print("-----\r\nSearchClientLinks:\r\n");
    $clientLinks = CustomerManagementExampleHelper::SearchClientLinks(
        array($predicate),
        array($ordering),
        $pageInfo
    );
    print("ClientLinks:\r\n");
    CustomerManagementExampleHelper::OutputArrayOfClientLink($clientLinks);
}
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()."\r\n";
        print $e->getTraceAsString()."\r\n";
    }
}
import datetime

from auth_helper import *
from customermanagement_example_helper import *

# You must provide credentials in auth_helper.py.

# REQUIRED: The Client Account Id that you want to access.
CLIENT_ACCOUNT_ID='ClientAccountIdGoesHere'

def main(authorization_data):

    try:
        output_status_message(
            "You must edit this example to provide the ClientAccountId for the client link." \
            "When adding a client link, the client link's ManagingCustomerId is set to the CustomerId " \
            "of the current authenticated user, who must be a Super Admin of the agency." \
            "Login as an agency Super Admin user to send a client link invitation, or unlink an existing client link." \
            "Login as a client Super Admin user to accept a client link invitation."
        )

        update_client_links_response=None

        # Set the client link search criteria.

        page_info=customer_service.factory.create('ns5:Paging')
        page_info.Index=0  # The first page
        page_info.Size=100 # The first 100 client links for this page of results

        ordering=customer_service.factory.create('ns5:ArrayOfOrderBy')
        order_by=customer_service.factory.create('ns5:OrderBy')
        order_by.Field='Number'
        order_by.Order='Ascending'
        ordering.OrderBy.append(order_by)

        predicates=customer_service.factory.create('ns5:ArrayOfPredicate')
        predicate=customer_service.factory.create('ns5:Predicate')
        predicate.Field='ClientAccountId'
        predicate.Operator='In'
        predicate.Value=CLIENT_ACCOUNT_ID
        predicates.Predicate.append(predicate)

        # Search for client links that match the criteria.

        output_status_message("-----\nSearchClientLinks:")
        client_links=customer_service.SearchClientLinks(
            Ordering=ordering,
            PageInfo=page_info,
            Predicates=predicates
        )
        output_status_message("ClientLinks:")
        output_array_of_clientlink(client_links)

        # Determine whether the agency is already managing the specified client account. 
        # If a link exists with status either Active, LinkInProgress, LinkPending, 
        # UnlinkInProgress, or UnlinkPending, the agency may not initiate a duplicate client link.

        client_link=None
        new_link_required=True

        if len(client_links['ClientLink']) > 0:
            client_link=client_links['ClientLink'][0]
            output_status_message("Using the first client link as an example.")
            output_status_message("Current ClientLink Status: {0}.".format(client_link.Status))
            
            # Reformat the start date to trim tzinfo. This workaround is temporarily required because
            # Customer Management service does not accept signed utc offset e.g. +00:00
            start_date=client_links['ClientLink'][0].StartDate
            reformatted_start_date=(datetime.datetime(
                year=start_date.year, 
                month=start_date.month, 
                day=start_date.day, 
                hour=start_date.hour,
                minute=start_date.minute,
                second=start_date.second,
                microsecond=start_date.microsecond,
                tzinfo=None).isoformat('T'))
            client_link.StartDate=reformatted_start_date            
            client_links=customer_service.factory.create('ns5:ArrayOfClientLink')
            
            # The agency may choose to initiate the unlink process, 
            # which would terminate the existing relationship with the client. 
            if client_link.Status == 'Active':
                client_link.Status='UnlinkRequested'
                client_links.ClientLink.append(client_link)
                output_status_message("-----\nUpdateClientLinks:")
                update_client_links_response=customer_service.UpdateClientLinks(
                    ClientLinks=client_links)
                output_status_message("UpdateClientLinks : UnlinkRequested.")
                new_link_required=False
            # Waiting on a system status transition or waiting for the StartDate.
            elif client_link.Status == 'LinkAccepted':
                output_status_message("The status is transitioning towards LinkInProgress.")
                new_link_required=False
            # Waiting on a system status transition.
            elif client_link.Status == 'LinkInProgress':
                output_status_message("The status is transitioning towards Active.")
                new_link_required=False
            # When the status is LinkPending, either the agency or client may update the status.
            # The agency may choose to cancel the client link invitation; however, in this example 
            # the client will accept the invitation. 
            # If the client does not accept or decline the invitation within 30 days, and if the agency
            # does not update the status to LinkCanceled, the system updates the status to LinkExpired.
            elif client_link.Status == 'LinkPending':
                client_link.Status='LinkAccepted'
                client_links.ClientLink.append(client_link)
                output_status_message("-----\nUpdateClientLinks:")
                update_client_links_response=customer_service.UpdateClientLinks(
                    ClientLinks=client_links)
                output_status_message("UpdateClientLinks: LinkAccepted.")
                new_link_required=False
            # Waiting on a system status transition.
            elif client_link.Status == 'UnlinkInProgress':
                output_status_message("The status is transitioning towards Inactive.")
                new_link_required=False
            # Waiting on a system status transition.
            elif client_link.Status == 'UnlinkPending':
                output_status_message("The status is transitioning towards Inactive.")
                new_link_required=False
            # The link lifecycle has ended.  
            else:
                output_status_message("A new client link invitation is required.")
            
            # Print errors if any occurred when updating the client link.
            if update_client_links_response is not None:
                output_status_message("OperationErrors:")
                output_array_of_operationerror(update_client_links_response.OperationErrors)
                output_status_message("PartialErrors:")  
                for arrayofoperationerror in update_client_links_response.PartialErrors['ArrayOfOperationError']:
                    output_array_of_operationerror(arrayofoperationerror)

        # If no links exist between the agency and specified client account, or a link exists with status  
        # either Inactive, LinkCanceled, LinkDeclined, LinkExpired, or LinkFailed, then the agency must
        # initiate a new client link.

        if new_link_required:
            client_links=customer_service.factory.create('ns5:ArrayOfClientLink')
            client_link=customer_service.factory.create('ns5:ClientLink')
            client_link.ClientEntityId=CLIENT_ACCOUNT_ID
            client_link.ManagingCustomerId=authorization_data.customer_id
            client_link.IsBillToClient=True
            client_link.Name="My Client Link"
            client_link.StartDate=None
            client_link.SuppressNotification=True
            client_link.Status=None
            client_links.ClientLink.append(client_link)
            
            output_status_message("-----\nAddClientLinks:")
            add_client_links_response=customer_service.AddClientLinks(
                ClientLinks=client_links)
            output_status_message("OperationErrors:")
            output_array_of_operationerror(add_client_links_response.OperationErrors)
            output_status_message("PartialErrors:")            
            for arrayofoperationerror in add_client_links_response.PartialErrors['ArrayOfOperationError']:
                output_array_of_operationerror(arrayofoperationerror)
        
        # Output the client links after any status updates above.

        output_status_message("-----\nSearchClientLinks:")
        client_links=customer_service.SearchClientLinks(
            Ordering=ordering,
            PageInfo=page_info,
            Predicates=predicates
        )
        output_status_message("ClientLinks:")
        output_array_of_clientlink(client_links)

    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,
    )

    customer_service=ServiceClient(
        service='CustomerManagementService', 
        version=13,
        authorization_data=authorization_data, 
        environment=ENVIRONMENT,
    )
        
    authenticate(authorization_data)
        
    main(authorization_data)

See Also

Get Started with the Bing Ads API