Microsoft Advertising
Overview
Configuring an integration between Redpoint Data Management (DM) and Microsoft Advertising (Bing Ads) APIs allows you to create and populate customer match lists. This document contains instructions for generating and refreshing authentication tokens, getting a file upload location from Bing, and creating/populating a customer match list by posting to that file upload location. Bing provides a combination of SOAP and REST endpoints to enable this functionality.
Basic requirements
Each task contained in this document has the following requirements:
A Microsoft Azure Application (steps to register https://learn.microsoft.com/en-us/advertising/guides/authentication-oauth-register?view=bingads-13 )
A Bing Advertising Manager Account and ID (set as
CustomerId
in API calls)A Bing Advertising Ad Account and ID (managed by the Manager Account and set as
CustomerAccountId
andAccountId
in API calls)A Developer Token (see https://learn.microsoft.com/en-us/advertising/guides/get-started?view=bingads-13#get-developer-token for instructions on how to request one)
An
AuthenticationToken
An audience file for upload. Refer to Cloud storage providers and Define file exports for details
Basic authentication flow
All requests to the Bing APIs must include an authentication token and a developer token. The developer token is granted by Microsoft. Per Microsoft, “The universal developer token can be used to authenticate with any Microsoft Advertising user credentials. You can use the same universal developer token whether your application will be used by one or multiple Microsoft Advertising users.” Follow these steps (https://learn.microsoft.com/en-us/advertising/guides/get-started?view=bingads-13#get-developer-token ) to request a developer token:
Sign in with Super Admin credentials at the Microsoft Advertising Developer Portal account tab.
Choose the user that you want associated with the developer token. Typically an application only needs one universal token, regardless how many users will be supported.
Select the Request Token button.
The required authentication token is a short-lived token that must accompany every request to the Bing APIs. Bing APIs employ the OAuth 2.0 flow to generate tokens. Each user must be prompted and provide consent through a web browser control at least once for your application to manage their Microsoft Advertising accounts. The PowerShell script below will…
Make a request for user access.
Redeem the returned code for authentication and refresh tokens.
Use the refresh token to to generate new authentication and refresh tokens.
You can get your client id when you register the application or from your list of applications https://portal.azure.com/#view/Microsoft_AAD_RegisteredApps/ApplicationsListBlade.
# Replace the Tutorial Sample App ID with your registered application ID.
$clientId = "f3fa9b54-9035-46a6-95f5-87410a74c3fc"
Start-Process "https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id=$clientId&scope=openid%20profile%20https://ads.microsoft.com/msads.manage%20offline_access&response_type=code&redirect_uri=https://login.microsoftonline.com/common/oauth2/nativeclient&state=ClientStateGoesHere&prompt=login"
$code = Read-Host "Grant consent in the browser, and then enter the response URI here:"
$code = $code -match 'code=(.*)\&'
$code = $Matches[1]
# Get the initial access and refresh tokens.
$response = Invoke-WebRequest https://login.microsoftonline.com/common/oauth2/v2.0/token -ContentType application/x-www-form-urlencoded -Method POST -Body "client_id=$clientId&scope=https://ads.microsoft.com/msads.manage%20offline_access&code=$code&grant_type=authorization_code&redirect_uri=https%3A%2F%2Flogin.microsoftonline.com%2Fcommon%2Foauth2%2Fnativeclient"
$oauthTokens = ($response.Content | ConvertFrom-Json)
Write-Output "Access token: " $oauthTokens.access_token
Write-Output "Access token expires in: " $oauthTokens.expires_in
Write-Output "Refresh token: " $oauthTokens.refresh_token
# The access token will expire e.g., after one hour.
# Use the refresh token to get new access and refresh tokens.
$response = Invoke-WebRequest https://login.microsoftonline.com/common/oauth2/v2.0/token -ContentType application/x-www-form-urlencoded -Method POST -Body "client_id=$clientId&scope=https://ads.microsoft.com/msads.manage%20offline_access&code=$code&grant_type=refresh_token&refresh_token=$($oauthTokens.refresh_token)"
$oauthTokens = ($response.Content | ConvertFrom-Json)
Write-Output "Access token: " $oauthTokens.access_token
Write-Output "Access token expires in: " $oauthTokens.expires_in
Write-Output "Refresh token: " $oauthTokens.refresh_token
The authentication and refresh tokens can be stored in DM and refreshed when needed.
Refresh token
Each call to refresh the authentication token will return both a new authentication token as well as a new refresh token to be used in future refresh requests.
Endpoint
https://login.microsoftonline.com/common/oauth2/v2.0/token
Method
POST
Header
Field | Data type | Description |
---|---|---|
|
| (Required) |
Parameters
Field | Data type | Description |
---|---|---|
|
| (Required) The application (client) ID that the Azure portal - App registrations portal assigned your app. |
|
| (Required for web apps) The application secret that you created in the app registration portal for your app. It should not be used in a native app, because |
|
| (Required) |
|
| (Required) The |
|
| (Required) A space-separated list of scopes. The scopes requested in this leg must be equivalent to or a subset of the scopes included when you requested user consent. If the scopes specified in this request span multiple resource servers, then the Microsoft identity platform endpoint will return a token for the resource specified in the first scope. For a more detailed explanation of scopes, refer to permissions, consent, and scopes. |
DM caveat
The requirement for application/x-www-form-urlencoded
means that the field is not created as a JSON object, but as a simple string. The request must be created manually using a Calculate function. See below:
Example DM Field:
"client_id=" + global.appIDSandbox + " &scope=https://api.ads.microsoft.com/msads.manage%20offline_access&grant_type=refresh_token&refresh_token=" + global.refreshTokenSandbox
Request
// Line breaks for legibility only
POST /common/oauth2/v2.0/token HTTP/1.1
Host: https://login.microsoftonline.com
Content-Type: application/x-www-form-urlencoded
client_id=6731de76-14a6-49ae-97bc-6eba6914391e
&scope=https%3A%2F%2Fads.microsoft.com%2Fmsads.manage
&refresh_token=OAAABAAAAiL9Kn2Z27UubvWFPbm0gLWQJVzCTE9UkP3pSx1aXxUjq...
&grant_type=refresh_token
&client_secret=JqQX2PNo9bpM0uEihUPzyrh // NOTE: Only applicable for web apps
Response
{
"token_type": "Bearer",
"scope": "https://api.ads.microsoft.com/msads.manage",
"expires_in": 4104,
"ext_expires_in": 4104,
"access_token": "eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhDQkMtSFMyNTYiLCJ4NXQiOiJlWDZfN25KcHNWTEh0LTAxSkRFaWFWNHpBamMiLCJ6aXAiOiJERUYifQ.OtEpr6G0vy_ToDDUpAvhSz2yeyUKoFyaYhjK_Y8p_HGa5dYnm6BR8bp72sVM_NendS-xb_IkNxuVb0WhQWrNFML_4GllP9fL6bla5K8HLi4R5ZCrxrQ7ud26hyFZvevKpJpL9R4WGsjta14rbREcxuUewyoGEYXa_9JVOv68u9EP7VMVrQAAxeCVZGtkAkySYahZzAsteYhN-GwwSWpJjGAtbo77eiUQpk50LusUlrgsnUDrClzfrI42nY1YtmNn3TlaWVEtuWppbQA7gijl6Qjuxix5nftO2DLIZvzvQmS-fo69Ou9z1BgO2SqI6ExU-GPVTygPHb0xRuGSAc44Xg.UWCKVhQoLYYBdJR3mou9pg.Iyi0DRaw7Z4rs3fw9cdQA0NAFVFfsYi5ej6v5qBA78U9Lh76VfrcAufzjibnLi19KSbKdawAMZh4CytEZqY68RJsVe6siKJm_FiIcG6cuIEBEqGIrf0jt2KlEvOUn3H6Bnz9MmN5hTb24wi-w7QewCpCped4ktTcvjL4A_c9JW-IHL5qblXIHOv6HpNCI24GBwteRD3OzlTxj4IOcSo7dAv8b0PgT9OcpQqz9adkNO9X3hrayTGSPSQjQSr21WI0S5N26jxAiIBtM7VGL_nNqXTSnsDCQMl4M5G1BtieHzpHpOfunArlaEIQcgUVHObSnYZkxMAli2x5MQb369wiZEUzXeABbx-jnAeItsnwQlWSHIJHA99ogZdf1QFYN3wLDSF2XgI1Qs4GKxUw6cvOSgW_tHOXntg6jNoi7224bSuIsJT-WkhxaCrVAcMKEzr8y6E-21gKKWOsoaTFRHmFYZG_VNaUHYRdWs2PC9uovU5nKR29eB2oil0rPU5rp1YA8xiK5g6GWrkI85zhl9zV9hUMpILCSjhlgyKMlAk-cN4hKjhWXU65xu7lsvjtqkBOLHvzudy2FViByLf1dJo0i8W-qZWj1G1Z6DVDozdfI4Yjjiqb_1lony_wxftbKz41UPXJFXMxTWay-7Hc5Jb8jzLQuzltXtT8Xx20u6EngWM92G0K0Uba1LdHxawkprsRzk67xs_75-O-gJ0plrQnJgSaV7RXF8p7YA2I3xbkMEeou3tc6DodfZ8yRmbHS-Rg7eXcJm0X4BVtKn4CrlGpMDqljBsNp6JV5xqQkI6AvpO6jk3-NFKTlrcFxVdmRL8TFCqwLZjCA_qhyYYP7INfYBbE1VPcfMyYP-1leTz23DMZgyWvfUX5ObP7z984tHF0h3kGqJPJR_tVaExFa7k24mHOhc2-zOp9qR0NiWelLkq32xgOU8i60ETlTBT8Tw8QNGcSLGTtSj4IvWm4OWSWuJwBpO7d_1LHYOmRiGWMFczb-Z-3GwQpGwRajJ-tcxK6zoE62KvUly3iXIxkPNTbROXofwOdZKqAeFThfAbDbUddCfyuvYF4rzancCsNMmdOFllYA6CjRUflAmoF8GiKgulnl263ODm1edDmjAajbaWnBGAte1dEzA_WixbB3JwSOieIVn6kLIMYzg7GsxAgwUqwHjWCJ-IzohBE7pm7Qz9Po0XHUcMcIhPHt8LsovQi3wszrdORtkpotdckm2EramRMZiYlfzBbZSUiceNND4NkZb__fUGJKrIMeFizcIAHpt6Lldox5o_EA0zdaqrZkb-W5sjgu_mqMKQaOrU7JLxgz_dpSSudPRlP2Iki89QY.GTyut6DXV2fLKnNeoyVWsg",
"refresh_token": "M.C100_SN1.-AoQq82eMerUJGGt7fqfJQiO0HzkYe7PkmeDpqZtoX0tgtK3e7Mp0XcGbbSNd1ke3TOQ0wMp6m5vLeJrtKw6yVZ3qY961LMecKx7tzA6LUr3AxizgcGrmRjul!ubmQGJkwbcQOoenbpud633CLzSK1oy1*ZJ6h0XR3dS7ufW8T0klPfp1aJ*Vvd5wxEiUNbzDkzQCMOCFly7TVQJin8u*SMAjdyxJpA*Oh8dNJqujUn3ULvkjD25kMhPMMVTt2Og09NGsFpPXGuAgSfroWcH6qoXt2SEwVNW!D3hG7GIQyYRb0BrqLGsU9qHxxMu09dS*Lzg3j7Wrw8rnvTRXDELmR2vvvBBqi9N8tS4fYGIPU26OEWfhHSaP1blZITKheOhogzCpZ3eQE8Bzx6iMWDVDsRShYAubgCbYv1IdpnutQy*E"
}
Create a customer match list
To create a customer match list:
First call the Bing API to retrieve a file upload location.
Once you have that, you must then post the CSV file to the file upload location.
Bing will then return a
RequestId
that can be used to query the status of the file upload until completion.
Get file upload URL
In order to get the file upload URL, you must make use of Bing’s Bulk Service API Webservice. This webservice utilizes the SOAP protocol, which requires you to manually create the SOAP envelope within DM. The order of the parameters in the SOAP Header and Body must match those below.
Endpoint
https://bulk.api.bingads.microsoft.com/Api/Advertiser/CampaignManagement/v13/BulkService.svc
Method
POST
Header
Field | Data type | Description |
---|---|---|
|
| (Required) |
|
| (Required) |
SOAP parameters header
Field | Data type | Description |
---|---|---|
|
| (Required) |
|
| (Required) The |
|
| (Required) The identifier of the ad account that owns or is associated with the entities in the request. This header element must have the same value as the |
|
| (Required) The identifier of the manager account (customer) the user is accessing or operating from. A user can have access to multiple manager accounts. |
|
| (Required) The developer token used to access the Bing Ads API. |
SOAP parameters body
Field | Data type | Description |
---|---|---|
|
| (Required) The identifier of the ad account that owns or is associated with the entities in the request. This body element must have the same value as the |
|
| (Required) Specify whether to return errors and their corresponding data, or only the errors in the results file. The default is |
DM caveat
The requirement for a SOAP envelope means that the field is not created as a JSON object, but as a simple string containing XML. The request must be created manually using a Calculate function. See below:
Example DM Field:
"<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/CampaignManagement/v13\">
<Action mustUnderstand=\"1\">GetBulkUploadUrl</Action>
<AuthenticationToken i:nil=\"false\">"+global.authToken+"</AuthenticationToken>
<CustomerAccountId i:nil=\"false\">"+global.accountID+"</CustomerAccountId>
<CustomerId i:nil=\"false\">"+global.custID+"</CustomerId>
<DeveloperToken i:nil=\"false\">"+global.devToken+"</DeveloperToken>
</s:Header>
<s:Body>
<GetBulkUploadUrlRequest xmlns=\"https://bingads.microsoft.com/CampaignManagement/v13\">
<ResponseMode>ErrorsOnly</ResponseMode>
<AccountId>"+global.accountID+"</AccountId>
</GetBulkUploadUrlRequest>
</s:Body>
</s:Envelope>"
Request
POST /Api/Advertiser/CampaignManagement/v13/BulkService.svc HTTP/1.1
Host: bulk.api.sandbox.bingads.microsoft.com:443
Content-Type: text/xml
SOAPAction: GetBulkUploadUrl
Content-Length: 2614
<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/CampaignManagement/v13">
<Action mustUnderstand="1">GetBulkUploadUrl</Action>
<AuthenticationToken i:nil="false">eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhDQkMtSFMyNTYiLCJ4NXQiOiJlWDZfN25KcHNWTEh0LTAxSkRFaWFWNHpBamMiLCJ6aXAiOiJERUYifQ.If6F1UbXA1UU9r3KEzXpz919mYx959h_K0CT14srSUAabvLfYhZvUDpJWExQOyU4O8PFW8XfcJmOkc_vVxdUc0RGqbbwplxDYh1sWFUyvzsMX5eKiaBStnC-guEiqVKt90v6LxeKchPraZq7ViM6ho51FEt44FbocZzdW4McsJvNhMSbgSqhHvEH_INaDqkyxyV-R0J1M_QLzWA3na462owNq382GCoGIPrPFqSm4HkK6fTGylvGXy_A8eQIFxMsh2uBCBVPAqtxRBGnGQPLGNkLGKmrzhlL8fGv1dZaVJx-nt67b2Qk81boM1kb1NE-0MoPeF9Fip_VB0I90XTWFw.efog0xI714NkE2JDiTLTjA.RDZCfEmwvg40PtN3epjxC1ptmGNrytZWHPxZ89-gnsBgRGzVf8fJb2fyK6rgh6zE0CLDOMmZarn7xgVKg_wHbgSg3h4jK0_Ad5pLgrEvqXVund1-YkYvjYQ7kEJYNXQEnsYsQc4-ssnG3MNcVy_6KllgVOEeAPh-mvTErF4xe9o8p6qY11qHHG-e3WnwI3ZbDJ_WEKN9Nyyq5HoM6i8UOtXeF4uwrQqIyA5v3jDhwUIXvywjJAdclPaMONxRNNYzbIh_Oc80ZMghHBwEtkuWuLKXR4_-u_0uDvf6VlZ8MoUALzGiAfvEpJEo1qlhkv_A9J8rOWNqbtvyycB-rCrUZo0RnZVx-2WP5MmRQ9p4EJ9rX1je2bK3NNQvEv0x3nLkFNc3lCXaIF_4k3JQOEwqF7i17vtEYTsTO07S7CuXMehsx8a_hzLZNqfPtSpJcLGCffDiA_OmAHTcAUobK6urWATZjcIdWocKPyV2asJ-iFqejVn6FBxaoG4HSwCx3eZr_yE-cprLbz9VFXsMy3AehVjMviOzuNN9EY9jBox3bocSiy8uw6FsYD3sejGPMPRArnN9LNjXquvWzcSiY0UbY__mQOHbKrpApux_hluaRzLDtjWb-2sJfzFatUieHImZpBIA8e9jcQxFcSg9ZqzEr_c5lX1PtYVEuIrTc9DTi9d_xxSr0mws0MElO2-6xutTHPnCQZOZGkMwuj9hWd4D4iUzifDUVz6G0gKGwl5oD0LJnlD5YCklv9HeD05nuphLz7stWZqmNWPWkLZ267eThFiuxI6SqRuQe_7stNz9P2HVfB9d5C0LBL9UAVAUco9eSF7K5wwFgXlAFGl2_qufjUG_iy2xkukQ2oJKsj2ueazvEkkACnefgyUcDfPAtJiXNPW2uYbmgLXcLfLZ1m5YM5ytOfduSYYgsGijtazU_l9YSa3xRfBlwF7r9ICC4s3EFoy7Z_0iOWHa0QxNMyfu-LRvmTv1N08YCXaAD7FA3XN3vbrvhrLCp5EBt1GX-F7R6Cz5x2WcVPdynkSlg9dEH8EQ2cYU9OfhoVBMcW84zaoxMWiqykAF8c0--1hK0_0EK9PDRwojvLD5OKAUnqDFhBSRfFSlcNadmbyyEwurbNZxsD9fidfxgggLnlhM-w389tNaWum-K3x1Oi3oOpB0HaSELigKfNUKUbXSbCK31H_ehyVjgXjaceZNqph9WU-HdyxsP05zuD3GPSwYXL3GzyBZG0Jr3AWXozavJKT-KJ42Nug2HSe8zt5tiVLdnWaL8bGmHzagBFx5LV5CWURgOQxvcfp3bL5Nl7HgMyGTMH1w8Uu8YhJwnkoZwosuk4uE.2k1fGeI4Q8YUzFXe-rVCPw</AuthenticationToken>
<CustomerAccountId i:nil="false">279426368</CustomerAccountId>
<CustomerId i:nil="false">330031209</CustomerId>
<DeveloperToken i:nil="false">BBD37VB98</DeveloperToken>
</s:Header>
<s:Body>
<GetBulkUploadUrlRequest xmlns="https://bingads.microsoft.com/CampaignManagement/v13">
<ResponseMode>ErrorsOnly</ResponseMode>
<AccountId>279426368</AccountId>
</GetBulkUploadUrlRequest>
</s:Body>
</s:Envelope>
Response
<Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<Header>
<TrackingId xmlns:h="https://bingads.microsoft.com/CampaignManagement/v13">
4e66a06c-a95d-478d-b86c-4bdd2e734f24
</TrackingId>
</Header>
<Body>
<GetBulkUploadUrlResponse xmlns="https://bingads.microsoft.com/CampaignManagement/v13">
<RequestId>
e19e4ef3-20f3-4f2e-944c-a20e8b399a3f
</RequestId>
<UploadUrl>
https://fileupload.api.sandbox.bingads.microsoft.com/Api/Advertiser/CampaignManagement/FileUpload/File/UploadBulkFile/e19e4ef3-20f3-4f2e-944c-a20e8b399a3f?Ver=13
</UploadUrl>
</GetBulkUploadUrlResponse>
</Body>
</Envelope>
Upload customer match list file
Once obtained, you can post a customer match list file to the UploadUrl
. Note that the UploadUrl
is not a SOAP endpoint, but it does contain multipart/form-data that must be manually created.
Endpoint
UploadUrl
Method
POST
Header
Field | Data type | Description |
---|---|---|
|
| (Required) The |
|
| (Required) The identifier of the ad account that owns or is associated with the entities in the request. |
|
| (Required) The identifier of the manager account (customer) the user is accessing or operating from. A user can have access to multiple manager accounts. |
|
| (Required) The developer token used to access the Bing Ads API. |
|
|
|
Parameters
The following parameters must be included in the request body in the form-data
format.
Field | Data type | Description |
---|---|---|
|
| (Required) The |
DM caveat
The requirement for multipart/form-data
and a file upload presents a difficulty for DM. The request must be created manually using a Calculate function after consuming the customer file. We must define a form-data boundary, the request content type, including the boundary, and the request itself. See below:
Field: boundary
Expression:
"0ebd3"
Field: contentType
Expression:
"multipart/form-data; boundary=" + boundary
Field: request
Expression:
"--" + boundary + "
Content-Disposition: form-data; name=\"file\"; filename=\"file:///C:/Dev/bing ads/new to customer list.csv\"
Content-Type: text/plain
"+ DecodeTextBytes(contents,"UTF8") +"
--" + boundary + "--"
When run through a DM web service with the request field assigned to the Body field, this will produce a payload that contains contents of the file located at filename.
Request
POST /Api/Advertiser/CampaignManagement/FileUpload/File/UploadBulkFile/e19e4ef3-20f3-4f2e-944c-a20e8b399a3f?Ver=13 HTTP/1.1
Host: fileupload.api.sandbox.bingads.microsoft.com:443
AuthenticationToken: eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhDQkMtSFMyNTYiLCJ4NXQiOiJlWDZfN25KcHNWTEh0LTAxSkRFaWFWNHpBamMiLCJ6aXAiOiJERUYifQ.If6F1UbXA1UU9r3KEzXpz919mYx959h_K0CT14srSUAabvLfYhZvUDpJWExQOyU4O8PFW8XfcJmOkc_vVxdUc0RGqbbwplxDYh1sWFUyvzsMX5eKiaBStnC-guEiqVKt90v6LxeKchPraZq7ViM6ho51FEt44FbocZzdW4McsJvNhMSbgSqhHvEH_INaDqkyxyV-R0J1M_QLzWA3na462owNq382GCoGIPrPFqSm4HkK6fTGylvGXy_A8eQIFxMsh2uBCBVPAqtxRBGnGQPLGNkLGKmrzhlL8fGv1dZaVJx-nt67b2Qk81boM1kb1NE-0MoPeF9Fip_VB0I90XTWFw.efog0xI714NkE2JDiTLTjA.RDZCfEmwvg40PtN3epjxC1ptmGNrytZWHPxZ89-gnsBgRGzVf8fJb2fyK6rgh6zE0CLDOMmZarn7xgVKg_wHbgSg3h4jK0_Ad5pLgrEvqXVund1-YkYvjYQ7kEJYNXQEnsYsQc4-ssnG3MNcVy_6KllgVOEeAPh-mvTErF4xe9o8p6qY11qHHG-e3WnwI3ZbDJ_WEKN9Nyyq5HoM6i8UOtXeF4uwrQqIyA5v3jDhwUIXvywjJAdclPaMONxRNNYzbIh_Oc80ZMghHBwEtkuWuLKXR4_-u_0uDvf6VlZ8MoUALzGiAfvEpJEo1qlhkv_A9J8rOWNqbtvyycB-rCrUZo0RnZVx-2WP5MmRQ9p4EJ9rX1je2bK3NNQvEv0x3nLkFNc3lCXaIF_4k3JQOEwqF7i17vtEYTsTO07S7CuXMehsx8a_hzLZNqfPtSpJcLGCffDiA_OmAHTcAUobK6urWATZjcIdWocKPyV2asJ-iFqejVn6FBxaoG4HSwCx3eZr_yE-cprLbz9VFXsMy3AehVjMviOzuNN9EY9jBox3bocSiy8uw6FsYD3sejGPMPRArnN9LNjXquvWzcSiY0UbY__mQOHbKrpApux_hluaRzLDtjWb-2sJfzFatUieHImZpBIA8e9jcQxFcSg9ZqzEr_c5lX1PtYVEuIrTc9DTi9d_xxSr0mws0MElO2-6xutTHPnCQZOZGkMwuj9hWd4D4iUzifDUVz6G0gKGwl5oD0LJnlD5YCklv9HeD05nuphLz7stWZqmNWPWkLZ267eThFiuxI6SqRuQe_7stNz9P2HVfB9d5C0LBL9UAVAUco9eSF7K5wwFgXlAFGl2_qufjUG_iy2xkukQ2oJKsj2ueazvEkkACnefgyUcDfPAtJiXNPW2uYbmgLXcLfLZ1m5YM5ytOfduSYYgsGijtazU_l9YSa3xRfBlwF7r9ICC4s3EFoy7Z_0iOWHa0QxNMyfu-LRvmTv1N08YCXaAD7FA3XN3vbrvhrLCp5EBt1GX-F7R6Cz5x2WcVPdynkSlg9dEH8EQ2cYU9OfhoVBMcW84zaoxMWiqykAF8c0--1hK0_0EK9PDRwojvLD5OKAUnqDFhBSRfFSlcNadmbyyEwurbNZxsD9fidfxgggLnlhM-w389tNaWum-K3x1Oi3oOpB0HaSELigKfNUKUbXSbCK31H_ehyVjgXjaceZNqph9WU-HdyxsP05zuD3GPSwYXL3GzyBZG0Jr3AWXozavJKT-KJ42Nug2HSe8zt5tiVLdnWaL8bGmHzagBFx5LV5CWURgOQxvcfp3bL5Nl7HgMyGTMH1w8Uu8YhJwnkoZwosuk4uE.2k1fGeI4Q8YUzFXe-rVCPw
DeveloperToken: BBD37VB98
CustomerId: 330031209
AccountId: 279426368
Content-Type: multipart/form-data; boundary=0ebd3
Content-Length: 56207
--0ebd3
Content-Disposition: form-data; name="file"; filename="file:///C:/Dev/bing ads/new to customer list.csv"
Content-Type: text/plain
Type,Status,Id,Parent Id,Client Id,Modified Time,Name,Description,Scope,Audience,Action Type,Sub Type,Text
Format Version,,,,,,6,,,,,,
Customer List,Active,-10,,ClientIdGoesHere,,,An audience created with a demo with Dan,Customer,Demo with Dan,Add,,
Customer List Item,,,-10,ClientIdGoesHere,,,,,,,Email,2A9A9F735262755E1A3B6DADD35F8D6ED7FE971D9F38D788D52802AD2BA3645A
Customer List Item,,,-10,ClientIdGoesHere,,,,,,,Email,1AAC4498AC887EA12E1A5E8090206726138D7C0648D503002BC04DB50D23C099
Customer List Item,,,-10,ClientIdGoesHere,,,,,,,Email,5EC35D133C6149707AA5EC6940CCC2623783AC8479F0098070A11502EABB8C2A
Customer List Item,,,-10,ClientIdGoesHere,,,,,,,Email,2BDC4DC9F113FD9D1CB1E4FD7E45E602279F2E0EA5FF7F613978471DEB98DB03
--0ebd3--
A successful response will include a body containing a RequestId
. This RequestId
can be used in subsequent queries to check on the status of the file upload.
Response
{
"TrackingId":"3debbca9-3175-408d-8ec8-592fb05eb23a",
"RequestId":"e19e4ef3-20f3-4f2e-944c-a20e8b399a3f"
}
Get Upload Status
If you want to monitor the progress of a customer match list file upload, you can use the RequestId
to query the Bing API for the upload status. Once again, this is a SOAP endpoint, so the SOAP envelope must be generated manually.
For further reading, see https://learn.microsoft.com/en-us/advertising/bulk-service/getbulkuploadstatus?view=bingads-13.
Endpoint
https://bulk.api.bingads.microsoft.com/Api/Advertiser/CampaignManagement/v13/BulkService.svc
Method
POST
Header
Field | Data type | Description |
---|---|---|
|
| (Required) |
|
| (Required) |
SOAP parameters header
Field | Data type | Description |
---|---|---|
|
| (Required) |
|
| (Required) The |
|
| (Required) The identifier of the ad account that owns or is associated with the entities in the request. This header element must have the same value as the |
|
| (Required) The identifier of the manager account (customer) the user is accessing or operating from. A user can have access to multiple manager accounts. |
|
| The developer token used to access the Bing Ads API. |
SOAP parameters body
Field | Data type | Description |
---|---|---|
|
| (Required) The identifier returned from the |
Example DM field
"<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/CampaignManagement/v13\">
<Action mustUnderstand=\"1\">GetBulkUploadStatus</Action>
<AuthenticationToken i:nil=\"false\">"+global.authToken+"</AuthenticationToken>
<CustomerAccountId i:nil=\"false\">"+global.accountIDSandbox+"</CustomerAccountId>
<CustomerId i:nil=\"false\">"+global.custID+"</CustomerId>
<DeveloperToken i:nil=\"false\">"+global.devToken+"</DeveloperToken>
</s:Header>
<s:Body>
<GetBulkUploadStatusRequest xmlns=\"https://bingads.microsoft.com/CampaignManagement/v13\">
<RequestId i:nil=\"false\">"+global.uploadStatusRequestID+"</RequestId>
</GetBulkUploadStatusRequest>
</s:Body>
</s:Envelope>"
Request
POST /Api/Advertiser/CampaignManagement/v13/BulkService.svc HTTP/1.1
Host: bulk.api.sandbox.bingads.microsoft.com:443
Content-Type: text/xml
SOAPAction: GetBulkUploadStatus
Content-Length: 2617
<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/CampaignManagement/v13">
<Action mustUnderstand="1">GetBulkUploadStatus</Action>
<AuthenticationToken i:nil="false">eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhDQkMtSFMyNTYiLCJ4NXQiOiJlWDZfN25KcHNWTEh0LTAxSkRFaWFWNHpBamMiLCJ6aXAiOiJERUYifQ.If6F1UbXA1UU9r3KEzXpz919mYx959h_K0CT14srSUAabvLfYhZvUDpJWExQOyU4O8PFW8XfcJmOkc_vVxdUc0RGqbbwplxDYh1sWFUyvzsMX5eKiaBStnC-guEiqVKt90v6LxeKchPraZq7ViM6ho51FEt44FbocZzdW4McsJvNhMSbgSqhHvEH_INaDqkyxyV-R0J1M_QLzWA3na462owNq382GCoGIPrPFqSm4HkK6fTGylvGXy_A8eQIFxMsh2uBCBVPAqtxRBGnGQPLGNkLGKmrzhlL8fGv1dZaVJx-nt67b2Qk81boM1kb1NE-0MoPeF9Fip_VB0I90XTWFw.efog0xI714NkE2JDiTLTjA.RDZCfEmwvg40PtN3epjxC1ptmGNrytZWHPxZ89-gnsBgRGzVf8fJb2fyK6rgh6zE0CLDOMmZarn7xgVKg_wHbgSg3h4jK0_Ad5pLgrEvqXVund1-YkYvjYQ7kEJYNXQEnsYsQc4-ssnG3MNcVy_6KllgVOEeAPh-mvTErF4xe9o8p6qY11qHHG-e3WnwI3ZbDJ_WEKN9Nyyq5HoM6i8UOtXeF4uwrQqIyA5v3jDhwUIXvywjJAdclPaMONxRNNYzbIh_Oc80ZMghHBwEtkuWuLKXR4_-u_0uDvf6VlZ8MoUALzGiAfvEpJEo1qlhkv_A9J8rOWNqbtvyycB-rCrUZo0RnZVx-2WP5MmRQ9p4EJ9rX1je2bK3NNQvEv0x3nLkFNc3lCXaIF_4k3JQOEwqF7i17vtEYTsTO07S7CuXMehsx8a_hzLZNqfPtSpJcLGCffDiA_OmAHTcAUobK6urWATZjcIdWocKPyV2asJ-iFqejVn6FBxaoG4HSwCx3eZr_yE-cprLbz9VFXsMy3AehVjMviOzuNN9EY9jBox3bocSiy8uw6FsYD3sejGPMPRArnN9LNjXquvWzcSiY0UbY__mQOHbKrpApux_hluaRzLDtjWb-2sJfzFatUieHImZpBIA8e9jcQxFcSg9ZqzEr_c5lX1PtYVEuIrTc9DTi9d_xxSr0mws0MElO2-6xutTHPnCQZOZGkMwuj9hWd4D4iUzifDUVz6G0gKGwl5oD0LJnlD5YCklv9HeD05nuphLz7stWZqmNWPWkLZ267eThFiuxI6SqRuQe_7stNz9P2HVfB9d5C0LBL9UAVAUco9eSF7K5wwFgXlAFGl2_qufjUG_iy2xkukQ2oJKsj2ueazvEkkACnefgyUcDfPAtJiXNPW2uYbmgLXcLfLZ1m5YM5ytOfduSYYgsGijtazU_l9YSa3xRfBlwF7r9ICC4s3EFoy7Z_0iOWHa0QxNMyfu-LRvmTv1N08YCXaAD7FA3XN3vbrvhrLCp5EBt1GX-F7R6Cz5x2WcVPdynkSlg9dEH8EQ2cYU9OfhoVBMcW84zaoxMWiqykAF8c0--1hK0_0EK9PDRwojvLD5OKAUnqDFhBSRfFSlcNadmbyyEwurbNZxsD9fidfxgggLnlhM-w389tNaWum-K3x1Oi3oOpB0HaSELigKfNUKUbXSbCK31H_ehyVjgXjaceZNqph9WU-HdyxsP05zuD3GPSwYXL3GzyBZG0Jr3AWXozavJKT-KJ42Nug2HSe8zt5tiVLdnWaL8bGmHzagBFx5LV5CWURgOQxvcfp3bL5Nl7HgMyGTMH1w8Uu8YhJwnkoZwosuk4uE.2k1fGeI4Q8YUzFXe-rVCPw</AuthenticationToken>
<CustomerAccountId i:nil="false">279426368</CustomerAccountId>
<CustomerId i:nil="false">330031209</CustomerId>
<DeveloperToken i:nil="false">BBD37VB98</DeveloperToken>
</s:Header>
<s:Body>
<GetBulkUploadStatusRequest xmlns="https://bingads.microsoft.com/CampaignManagement/v13">
<RequestId i:nil="false">e19e4ef3-20f3-4f2e-944c-a20e8b399a3f</RequestId>
</GetBulkUploadStatusRequest>
</s:Body>
</s:Envelope>
Response
<Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<Header>
<TrackingId xmlns:h="https://bingads.microsoft.com/CampaignManagement/v13">
9ce078d4-52fe-4b9e-b559-440bb5e860f6
</TrackingId>
</Header>
<Body>
<GetBulkUploadStatusResponse xmlns="https://bingads.microsoft.com/CampaignManagement/v13">
<Errors i:nil="true" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" />
<ForwardCompatibilityMap xmlns:a="http://schemas.datacontract.org/2004/07/System.Collections.Generic" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" />
<PercentComplete>
100
</PercentComplete>
<RequestStatus>
Completed
</RequestStatus>
<ResultFileUrl>
https://bingadsappsstoragesi.blob.core.windows.net:443/bulkuploadresultfiles/d1c80c9c-0e75-440d-a58e-33f97eb8af6e.zip?sv=2018-03-28&sr=b&sig=Bsj9UC8zb5%2BUZyS%2B8wj3mLYmt7pDWQ3pkIrUVKd3wdE%3D&st=2023-11-13T19%3A57%3A16Z&se=2023-11-13T20%3A22%3A16Z&sp=rl
</ResultFileUrl>
</GetBulkUploadStatusResponse>
</Body>
</Envelope>
Customer match list file
Bing relies on the use of customer match list files to both create new Customer Match Lists and to add emails to the lists (which Bing refers to as Customer Match List items). A single file can both create a new list as well as add emails to it. The list is sent to the same File Upload URL endpoint referenced earlier. Due to this, the format of the file is confusing.
The first row of the file contains the column headers. Subsequent rows populate a subset of these columns.
The second row declares the Format Version of the file. This tells Bing which API version to parse the file with. At this point, the only valid value is 6.0.
The third row defines the Customer List to be acted upon. The ID column must either match an existing Customer Match List, or contain a negative number (which indicates the API should create a new Customer Match List).
All subsequent rows contain hashed emails and indicate which Customer List they should be added to by setting the Parent Id column.
See below for an example CSV with headers and first three defining rows:
Type,Status,Id,Parent Id,Client Id,Modified Time,Name,Description,Scope,Audience,Action Type,Sub Type,Text
Format Version,,,,,,6.0,,,,,,
Customer List,Active,-10,,ClientIdGoesHere,,,New customer list description,Customer,New Customer List,Add,,
Customer List Item,,,-10,ClientIdGoesHere,,,,,,,Email,HashedValue
See below for example CSV files that…
Define a new customer list and add emails to it
Define a new empty customer list
Add emails to an existing customer list
new customer list.csv new customer list empty.csv add to customer list.csv
File column headers
Type
Determines what object the given row is defining. For our purposes, this will be one of the following:
Format Version
Customer List
Customer List Item
Add: required.
Update: required.
Delete: required.
Status
The customer list status. Possible values are Active
or Deleted
.
Add: optional. The default value is Active
.
Update: read-only.
Delete: required. The Status must be set to Deleted
.
Id
The system-generated identifier of the customer list.
Add: optional. You must either leave this field empty, or specify a negative identifier. A negative identifier set for the customer list can then be referenced in the Parent Id field of dependent record types such as customer list item. This is required if you are adding a new customer list and new customer list items in the same Bulk file. For more information, see Bulk File Schema Reference Keys.
Update: read-only and required.
Delete: read-only and required.
Parent Id
The identifier of the parent customer list audience. You must specify either the Parent Id or Audience field.
Add: read-only and required. You must either specify an existing customer list identifier, or specify a negative identifier that is equal to the Id field of the parent Customer List record. This is required if you are adding new customer list items to a new customer list in the same Bulk file. For more information, see Bulk File Schema Reference Keys.
Delete: required.
Client Id
Used to associate records in the bulk upload file with records in the results file. The value of this field is not used or stored by the server; it is simply copied from the uploaded record to the corresponding result record. It may be any valid string to up 100 in length.
Add: optional.
Update: optional.
Delete: read-only.
Modified Time
The date and time that the entity was last updated. The value is in Coordinated Universal Time (UTC).
The date and time value reflects the date and time at the server, not the client. For information about the format of the date and time, see the dateTime
entry in Primitive XML Data Types.
Add: read-only.
Update: read-only.
Delete: read-only.
Name
Used to define the Format Version. Only supports 6.0.
Add: required.
Update: required.
Delete: required.
Description
The description of the customer list. Use a description to help you remember what audience you are targeting with this customer list. The description can contain a maximum of 1,024 characters.
Add: optional.
Update: optional. If no value is set for the update, this setting is not changed. If you set this field to the delete_value
string, the prior setting is removed.
Delete: read-only.
Scope
Scope defines what accounts can use this customer list. For a customer list the only supported scope is Customer
, and the customer list can be associated with any campaigns and ad groups across all of the customer's accounts.
Add: required.
Update: read-only. You cannot change the scope.
Delete: read-only.
Audience
The name of the customer list. The name can contain a maximum of 128 characters.
Add: required.
Update: optional. If no value is set for the update, this setting is not changed.
Delete: read-only.
Action type
Determines whether to add, remove, or replace the Customer List Item records that you include in the same Bulk upload file.
Add: the service will attempt to add the Customer List Item records that you include in the same Bulk upload file.
Remove: the service will attempt to remove the Customer List Item records that you include in the same Bulk upload file.
Replace: all previous customer match data for this list will be removed, and the service will attempt to add the Customer List Item records that you include in the same Bulk upload file.
Add: optional. By default the Add action type is used for new customer lists. Whether or not you set a value, this field is ignored for new customer lists.
Update: required if you are also including Customer List Item records for an existing audience in the same Bulk upload file; otherwise, this field is optional.
Delete: read-only.
Sub type
Determines whether the Text field represents a hashed Email value. Currently the only supported value is Email.
Add: required.
Delete: required.
Text
The hashed Email as text.
If the Sub Type is Email, this field cannot contain plain text. The string must be hashed using the SHA-256 algorithm. The hashed Email must be a hexadecimal string of length 64. For example, you must upload a hashed string such as f25ad364d33972379a7a4f4df33db142205f5c40eb19cfdb2fc5aaf117e10101
instead of test@contoso.com
.
Add: required.
Delete: required.
Notes on customer list file
Before you can upload customer list data via Bulk API, you must first create one customer list audience and accept the terms and conditions in the Microsoft Advertising UI. The initial customer list doesn't need to contain any customer data, but you must select I ACCEPT. By selecting I ACCEPT you (1) agree that you are able to lawfully disclose audience details, which is personal data, to Microsoft and (2) accept the Customer Match Terms, the Microsoft Advertising Agreement, and the Microsoft Advertising policies. Microsoft will use the data that you upload in accordance with the Customer Match Terms.
Upload best practices
Large files can degrade the upload performance. It is optional, but recommended that the file be compressed for upload. If compressed, it must be formatted as ZIP with the corresponding extension. The file size limit for upload in production is 100MB and up to 4 million rows. For Sandbox the limit is 20K rows. If you can limit concurrent uploads per customer below 5 or 6, then consider splitting the file rather than approaching the file size limit.
The list should have at least 300 active email users if being used for targeting across both the Microsoft Search Network and Microsoft Audience Network.
Limit concurrent uploads to 5 or 6 per customer to upload files in parallel. Wait on each thread until the previous file was processed, and then you can reuse the thread to upload another file. For example, one thread can upload a file and after the upload status is either
Completed
,CompletedWithErrors
, orFailed
that thread can upload another file.Upload only the entities and fields that you are adding or updating. If supplied, read-only fields such as bid suggestions and quality score data will be ignored.
Upload one entity type per file to maximize performance. There are some exceptions; for example, when creating new campaigns, ads, and keywords, it can be more efficient to upload them together with reference keys. As another example, if you are only updating 10 campaigns, 500 ads, and 800 keywords, then you can include them in one upload rather than splitting uploads per type.
Consider whether you need to request errors and results (
ResponseMode
=ErrorsAndResults
) in the upload results file, or whether errors only (ResponseMode
=ErrorsOnly
) will suffice. Consider whether or not you should synchronize the results with your local data. For example, if you are updating entities, you might only need to know whether any errors occurred, and in that case you can specifyResponseMode
=ErrorsOnly
in the GetBulkUploadUrl request. If you are adding new entities, then you can specifyResponseMode
=ErrorsAndResults
in the GetBulkUploadUrl request to receive the resulting entity identifiers.For partial retry attempts, do not upload the entire file if only a subset of the records resulted in errors. Only upload the records that you want to retry.
Do not retry until the upload status is either
Completed
,CompletedWithErrors
, orFailed
. If by chance performance does not meet expectations, please wait for the result anyway.Poll for upload results at reasonable intervals. Initially you should wait one minute for every 10K rows uploaded. After the initial wait time, consider polling in one minute intervals.