Skip to main content

🏢 Bing Ads - Account Management

📖 Overview

Bing Ads uses a hierarchical account structure with Manager Accounts (similar to Google Ads MCC) and User Accounts. The Customer Management Service API provides SOAP-based access to account information through the GetLinkedAccountsAndCustomersInfo operation.

Source Files:

  • Controller: external/Integrations/BingAds/Controllers/Accounts/AccountsController.js
  • Model: external/Integrations/BingAds/Models/Accounts/AccountsModel.js
  • Routes: external/Integrations/BingAds/Routes/accounts.js

External API: Microsoft Advertising Customer Management Service v13

SOAP Endpoint: https://clientcenter.api.bingads.microsoft.com/Api/CustomerManagement/v13/CustomerManagementService.svc

🏗️ Account Hierarchy

graph TD
MA[Manager Account] --> C1[Customer 1]
MA --> C2[Customer 2]
C1 --> A1[Account 1]
C1 --> A2[Account 2]
C2 --> A3[Account 3]
C2 --> A4[Account 4]

style MA fill:#4CAF50
style C1 fill:#2196F3
style C2 fill:#2196F3
style A1 fill:#FF9800
style A2 fill:#FF9800
style A3 fill:#FF9800
style A4 fill:#FF9800

Hierarchy Levels:

  • Manager Account: Top-level account (agency/reseller)
  • Customer: Organization/client under manager
  • User Account: Individual advertising account under customer

🔄 Data Flow

sequenceDiagram
participant Client as API Client
participant DC as DashClicks API
participant MW as Token Middleware
participant Model as AccountsModel
participant SOAP as Bing SOAP API

Client->>DC: GET /managers or /accessible-user-accounts
DC->>MW: Check token expiration
MW->>DC: Valid access token
DC->>Model: managerAccounts() or accesibleUsersAccounts()
Model->>Model: Build SOAP XML request
Model->>SOAP: POST SOAP envelope
SOAP-->>Model: SOAP XML response
Model->>Model: Parse XML to JSON
Model-->>DC: Return JSON data
DC-->>Client: JSON response with accounts

🔧 Account Functions

Get Manager Accounts

GET /managers

Purpose: Retrieve top-level manager accounts (MCC) with parent-only filtering

Controller: AccountsController.managerAccounts()

Model Method: AccountsModel.getManagerAccounts()

SOAP Operation: GetLinkedAccountsAndCustomersInfo

SOAP Service: Customer Management Service v13

Authentication: OAuth 2.0 Bearer token (via middleware)

Request:

GET /v1/integrations/bing/ads/accounts/managers
Authorization: Bearer {jwt_token}

SOAP Request XML:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:v13="https://bingads.microsoft.com/Customer/v13">
<soapenv:Header>
<v13:DeveloperToken>{DEVELOPER_TOKEN}</v13:DeveloperToken>
<v13:AuthenticationToken>{ACCESS_TOKEN}</v13:AuthenticationToken>
</soapenv:Header>
<soapenv:Body>
<GetLinkedAccountsAndCustomersInfoRequest xmlns="https://bingads.microsoft.com/Customer/v13">
<OnlyParentAccounts>true</OnlyParentAccounts>
</GetLinkedAccountsAndCustomersInfoRequest>
</soapenv:Body>
</soapenv:Envelope>

SOAP Headers:

HeaderValueDescription
DeveloperTokenFrom env varMicrosoft Ads developer token
AuthenticationTokenFrom middlewareOAuth 2.0 access token
SOAPActionGetLinkedAccountsAndCustomersInfoSOAP operation name

Request Parameters:

ParameterTypeDescription
OnlyParentAccountsBooleantrue - Only return parent (manager) accounts

SOAP Response XML Structure:

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<GetLinkedAccountsAndCustomersInfoResponse xmlns="https://bingads.microsoft.com/Customer/v13">
<AccountInfoWithCustomerData>
<AccountInfoWithCustomerData>
<CustomerId>123456</CustomerId>
<CustomerName>Agency Name</CustomerName>
<AccountId>987654321</AccountId>
<AccountName>Manager Account</AccountName>
<AccountNumber>X123456</AccountNumber>
<AccountLifeCycleStatus>Active</AccountLifeCycleStatus>
<PauseReason>None</PauseReason>
</AccountInfoWithCustomerData>
</AccountInfoWithCustomerData>
</GetLinkedAccountsAndCustomersInfoResponse>
</s:Body>
</s:Envelope>

JSON Response (Parsed from SOAP XML):

{
"success": true,
"message": "SUCCESS",
"data": {
"GetLinkedAccountsAndCustomersInfoResponse": {
"AccountInfoWithCustomerData": {
"AccountInfoWithCustomerData": [
{
"CustomerId": 123456,
"CustomerName": "Agency Name",
"AccountId": 987654321,
"AccountName": "Manager Account",
"AccountNumber": "X123456",
"AccountLifeCycleStatus": "Active",
"PauseReason": "None"
}
]
}
}
}
}

Response Fields:

FieldTypeDescription
CustomerIdIntegerCustomer identifier
CustomerNameStringCustomer name
AccountIdIntegerAccount identifier (used in other API calls)
AccountNameStringAccount name
AccountNumberStringAccount number (X-prefixed)
AccountLifeCycleStatusStringActive, Inactive, Pause
PauseReasonStringReason if paused

Error Response:

{
"success": false,
"error": "SOAP Fault: Invalid authentication token"
}

Side Effects:

  • None (read-only operation)

Get Accessible User Accounts

GET /accessible-user-accounts

Purpose: Retrieve all user accounts accessible under a specific customer ID

Controller: AccountsController.accesibleUsersAccounts()

Model Method: AccountsModel.getAccesibleUsersAccounts(customerID)

SOAP Operation: GetLinkedAccountsAndCustomersInfo

SOAP Service: Customer Management Service v13

Authentication: OAuth 2.0 Bearer token (via middleware)

Request:

GET /v1/integrations/bing/ads/accounts/accessible-user-accounts?customerID=123456
Authorization: Bearer {jwt_token}

Query Parameters:

ParameterTypeRequiredDescription
customerIDIntegerCustomer ID from manager accounts

Validation:

  • If customerID missing, returns error: "Please provide customerID"

SOAP Request XML:

<s:Envelope xmlns:i="http://www.w3.org/2001/XMLSchema-instance"
xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header xmlns="https://bingads.microsoft.com/Customer/v13">
<Action mustUnderstand="1">GetLinkedAccountsAndCustomersInfo</Action>
<AuthenticationToken i:nil="false">{ACCESS_TOKEN}</AuthenticationToken>
<DeveloperToken i:nil="false">{DEVELOPER_TOKEN}</DeveloperToken>
</s:Header>
<s:Body>
<GetLinkedAccountsAndCustomersInfoRequest xmlns="https://bingads.microsoft.com/Customer/v13">
<CustomerId i:nil="false">123456</CustomerId>
<OnlyParentAccounts>true</OnlyParentAccounts>
</GetLinkedAccountsAndCustomersInfoRequest>
</s:Body>
</s:Envelope>

SOAP Headers:

HeaderValueDescription
ActionGetLinkedAccountsAndCustomersInfoSOAP action with mustUnderstand="1"
AuthenticationTokenFrom middlewareOAuth 2.0 access token
DeveloperTokenFrom env varMicrosoft Ads developer token

Request Parameters:

ParameterTypeDescription
CustomerIdIntegerSpecific customer ID to filter accounts
OnlyParentAccountsBooleantrue - Only return parent accounts under customer

SOAP Response XML Structure:

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<GetLinkedAccountsAndCustomersInfoResponse xmlns="https://bingads.microsoft.com/Customer/v13">
<AccountInfoWithCustomerData>
<AccountInfoWithCustomerData>
<CustomerId>123456</CustomerId>
<CustomerName>Client Company</CustomerName>
<AccountId>111222333</AccountId>
<AccountName>Search Campaign Account</AccountName>
<AccountNumber>Y987654</AccountNumber>
<AccountLifeCycleStatus>Active</AccountLifeCycleStatus>
<PauseReason i:nil="true"/>
</AccountInfoWithCustomerData>
<AccountInfoWithCustomerData>
<CustomerId>123456</CustomerId>
<CustomerName>Client Company</CustomerName>
<AccountId>444555666</AccountId>
<AccountName>Shopping Campaign Account</AccountName>
<AccountNumber>Y123456</AccountNumber>
<AccountLifeCycleStatus>Active</AccountLifeCycleStatus>
<PauseReason i:nil="true"/>
</AccountInfoWithCustomerData>
</AccountInfoWithCustomerData>
</GetLinkedAccountsAndCustomersInfoResponse>
</s:Body>
</s:Envelope>

JSON Response (Parsed from SOAP XML):

{
"success": true,
"message": "SUCCESS",
"data": {
"GetLinkedAccountsAndCustomersInfoResponse": {
"AccountInfoWithCustomerData": {
"AccountInfoWithCustomerData": [
{
"CustomerId": 123456,
"CustomerName": "Client Company",
"AccountId": 111222333,
"AccountName": "Search Campaign Account",
"AccountNumber": "Y987654",
"AccountLifeCycleStatus": "Active",
"PauseReason": null
},
{
"CustomerId": 123456,
"CustomerName": "Client Company",
"AccountId": 444555666,
"AccountName": "Shopping Campaign Account",
"AccountNumber": "Y123456",
"AccountLifeCycleStatus": "Active",
"PauseReason": null
}
]
}
}
}
}

Response Fields:

FieldTypeDescription
CustomerIdIntegerCustomer identifier (same for all accounts)
CustomerNameStringCustomer name
AccountIdIntegerAccount identifier (use in campaigns, ads API)
AccountNameStringDescriptive account name
AccountNumberStringAccount number (Y-prefixed for user accounts)
AccountLifeCycleStatusStringActive, Inactive, Pause
PauseReasonString/NullReason if paused

Error Response (Missing customerID):

{
"success": false,
"error": "Please provide customerID"
}

Error Response (SOAP Fault):

{
"success": false,
"error": "Invalid customer ID"
}

SOAP Fault Handling:

  • Checks for response.Envelope.Body.Fault
  • Throws error with faultstring message
  • Common faults: Invalid credentials, unauthorized access, invalid customer ID

Side Effects:

  • None (read-only operation)

📊 Account Status Values

AccountLifeCycleStatus:

StatusDescription
ActiveAccount is active and can serve ads
InactiveAccount is inactive (billing issues, suspended)
PauseAccount is manually paused
PendingAccount setup in progress

PauseReason (when status is Pause):

ReasonDescription
NoneNot paused
UserInitiatedUser manually paused
BillingIssuePayment method problem
PolicyViolationAds policy violation

🔗 Integration Flow

Step 1: Get Manager Accounts

GET /v1/integrations/bing/ads/accounts/managers

Returns top-level manager accounts with CustomerId values.

Step 2: Get User Accounts

GET /v1/integrations/bing/ads/accounts/accessible-user-accounts?customerID={CustomerId}

Returns all user accounts under the specific customer.

Step 3: Use Account IDs

Use AccountId from user accounts in other API calls:

  • Campaigns: /campaigns?customerAccountID={AccountId}&customerID={CustomerId}
  • Ad Groups: /adgroups?customerAccountID={AccountId}&customerID={CustomerId}
  • Ads: /ads?customerAccountID={AccountId}&customerID={CustomerId}

🔐 Required Parameters

All Bing Ads API calls require:

  • customerAccountID - The AccountId from user accounts
  • customerID - The CustomerId from manager accounts

Example:

GET /campaigns?customerAccountID=111222333&customerID=123456

🧩 SOAP vs REST

Why SOAP for Accounts?

  • Microsoft Advertising uses SOAP protocol for Customer Management Service
  • XML-based requests and responses
  • Custom SOAP client with fast-xml-parser

XML Parsing:

  • SOAP XML → JavaScript Object (via SoapClient.parse())
  • Nested structure: Envelope.Body.{ResponseName}
  • Fault handling: Envelope.Body.Fault.faultstring

⚠️ Important Notes

  • 🏢 Manager Account Required: Top-level manager account needed for hierarchy
  • 🔢 CustomerID Required: Must provide customerID for user accounts endpoint
  • 📊 Account Selection: Frontend should let users select specific account
  • 🔑 AccountId Critical: Use AccountId (not AccountNumber) in API calls
  • 📝 OnlyParentAccounts: Always true to get parent-level accounts
  • 🔄 Token Auto-Refresh: Middleware handles token expiration automatically
  • SOAP Protocol: Uses XML instead of JSON
  • 🧰 Custom Parser: Uses fast-xml-parser library
  • 🔐 Developer Token: Required in addition to OAuth token
  • 📋 Multiple Accounts: Users may have access to multiple accounts under single customer
💬

Documentation Assistant

Ask me anything about the docs

Hi! I'm your documentation assistant. Ask me anything about the docs!

I can help you with:
- Code examples
- Configuration details
- Troubleshooting
- Best practices

Try asking: How do I configure the API?
09:30 AM