Microsoft Ads REST API: GetBillingDocumentsInfo Returns Empty Results

PIO 0 Reputation points
2025-11-05T21:40:49.76+00:00

Hi, I think I found a bug or an undocumented permissions issue when I try to query for billing-docs via the microsoft-ads rest api. below is a claude generated summary walking through the EXACT curl commands I used and their various responses. As a precaution I've redacted the environment variables but I can give you the exact ones if it matters (I imagine a dev on you guys' side-of-the-fence could easily cross-reference the "Information deleted by moderator" username and impute the dev-token, etc.)

edit: somewhat painful to redact a lot of the IDs by hand, hopefully I get to hear back from you guys on this bug/permissions hiccup. My guess is that my immediate user/api-token is getting hung up asking for billing-docs belong to other people's "accounts" that don't immediately belong to "me" despite being a "Super Admin" in this situation.

Microsoft Ads REST API: GetBillingDocumentsInfo Returns Empty Results

Summary

The GetBillingDocumentsInfo REST API endpoint returns an empty array {"BillingDocumentsInfo":[]} despite valid authentication, Super Admin permissions, and an active account with billing documents visible in the Microsoft Ads UI.

Environment

  • API Version: v13
  • Endpoint: https://clientcenter.api.bingads.microsoft.com/CustomerBilling/v13/BillingDocumentsInfo/Query
  • Date: November 5, 2025
  • Account Region: Brazil (BRL currency)
  • Account Timezone: Brasilia
  • Customer ID: 12....34
  • Account ID: 24.....64

Reproduction Steps

Step 1: Set Environment Variables


export BING_ADS_ACCESS_TOKEN='eyJhb...redacted...9V1l0Us'

export BING_ADS_DEV_TOKEN='119...redacted..19'

export BING_ADS_CUSTOMER_ID='12.....34'


Step 2: Verify User Has Super Admin Permissions ✅

API Call:


curl -X POST "https://clientcenter.api.bingads.microsoft.com/CustomerManagement/v13/User/Query" \

  -H "Authorization: Bearer $BING_ADS_ACCESS_TOKEN" \

  -H "DeveloperToken: $BING_ADS_DEV_TOKEN" \

  -H "CustomerId: $BING_ADS_CUSTOMER_ID" \

  -H "Content-Type: application/json" \

  -d '{"UserId": null}'

Response (formatted):


{

  "User": {

    "ContactInfo": {

      "Email": 
"Information deleted by moderator"

    },

    "CustomerId": "25.....9",

    "Id": "13.....47",

    "Name": {

      "FirstName": "Placements.io",

      "LastName": "Administrator"

    },

    "UserLifeCycleStatus": "Active",

    "UserName": 
"Information deleted by moderator"


  },

  "CustomerRoles": [

    {

      "RoleId": 41,

      "CustomerId": "2...redated...9",

      "AccountIds": null

    },

    {

      "RoleId": 41,

      "CustomerId": "12....4",

      "AccountIds": null

    },

    {

      "RoleId": 41,

      "CustomerId": "2.....1",

      "AccountIds": null

    }

  ]

}

Key Findings:

  • ✅ User ID: 13....47
  • ✅ RoleId: 41 (Super Admin)
  • ✅ Has Super Admin access to CustomerId 12........34
  • AccountIds: null indicates access to all accounts under this customer

Step 3: Verify Account Exists and Is Active ✅

API Call:


curl -X POST "https://clientcenter.api.bingads.microsoft.com/CustomerManagement/v13/AccountsInfo/Query" \

  -H "Authorization: Bearer $BING_ADS_ACCESS_TOKEN" \

  -H "DeveloperToken: $BING_ADS_DEV_TOKEN" \

  -H "CustomerId: $BING_ADS_CUSTOMER_ID" \

  -H "Content-Type: application/json" \

  -d '{"CustomerId": 12......34, "OnlyParentAccounts": false}'

Response (formatted):


{

  "AccountsInfo": [

    {

      "Id": "24.....64",

      "Name": "REDACTED",

      "Number": "X7......05",

      "AccountLifeCycleStatus": "Active",

      "PauseReason": null

    },

    ... REDACTED....

    

  ]

}

Key Findings:

  • ✅ Account ID 24.....64 exists
  • ✅ Account status is Active
  • ✅ Account number: X7.....05
  • 5 other accounts are paused

Step 4: Verify Account Details and BillToCustomerId ✅

API Call:


curl -X POST "https://clientcenter.api.bingads.microsoft.com/CustomerManagement/v13/Account/Query" \

  -H "Authorization: Bearer $BING_ADS_ACCESS_TOKEN" \

  -H "DeveloperToken: $BING_ADS_DEV_TOKEN" \

  -H "Content-Type: application/json" \

  -d '{"AccountId": 24.....4}'

Response (formatted):


{

  "Account": {

    "BillToCustomerId": "12......4",

    "CurrencyCode": "BRL",

    "AccountFinancialStatus": "ClearFinancialStatus",

    "Id": "24.....64",

    "Language": "Portuguese",

    "LastModifiedTime": "2025-10-08T17:50:48.843",

    "Name": "REDACTED",

    "Number": "X7......5",

    "ParentCustomerId": "12......4",

    "PaymentMethodId": "41.......9",

    "AccountLifeCycleStatus": "Active",

    "TimeZone": "Brasilia",

    "PauseReason": null,

    "TaxInformation": [

      {

        "Key": "CNPJ",

        "Value": "72......0"

      }

    ],

    "BusinessAddress": {

      ....REDACTED...

    },

    "AutoTagType": "Preserve",

    "SoldToPaymentInstrumentId": "41.....59"

  }

}

Key Findings:

  • BillToCustomerId: "12......34" (matches our CustomerId)
  • ParentCustomerId: "12.....34" (matches our CustomerId)
  • AccountLifeCycleStatus: "Active"
  • CurrencyCode: "BRL" (Brazilian Real)
  • TimeZone: "Brasilia"
  • CountryCode: "BR" (Brazil)
  • AccountFinancialStatus: "ClearFinancialStatus"
  • ✅ Has payment method configured (PaymentMethodId: "41....59")

Step 5: Attempt to Retrieve Billing Documents ❌

API Call:


curl -X POST "https://clientcenter.api.bingads.microsoft.com/CustomerBilling/v13/BillingDocumentsInfo/Query" \

  -H "Authorization: Bearer $BING_ADS_ACCESS_TOKEN" \

  -H "DeveloperToken: $BING_ADS_DEV_TOKEN" \

  -H "CustomerId: 12.....4" \

  -H "Content-Type: application/json" \

  -d '{

    "AccountIds": [24........64],

    "StartDate": "2024-01-01T00:00:00.000",

    "EndDate": "2025-12-31T23:59:59.999",

    "ReturnInvoiceNumber": true

  }'

Response:


{"BillingDocumentsInfo":[]}

Issue:

  • ❌ Returns empty array despite valid authentication and permissions
  • ❌ Date range spans 2 full years (2024-2025)
  • ❌ HTTP status: 200 OK (no error message)

API Documentation Comparison

The curl command matches the official Microsoft documentation requirements:

https://learn.microsoft.com/en-us/advertising/customer-billing-service/getbillingdocumentsinfo?view=bingads-13&tabs=prod&pivots=rest

Request Structure Analysis

| Element | Documentation Requirement | Our Implementation | Match |

|---------|--------------------------|-------------------|--------|

| Endpoint URL | CustomerBilling/v13/BillingDocumentsInfo/Query | CustomerBilling/v13/BillingDocumentsInfo/Query | ✅ |

| HTTP Method | POST | POST | ✅ |

| Authorization Header | Authorization: Bearer {token} | Authorization: Bearer $BING_ADS_ACCESS_TOKEN | ✅ |

| DeveloperToken Header | DeveloperToken: {token} | DeveloperToken: $BING_ADS_DEV_TOKEN | ✅ |

| AccountIds (required) | Array of long values | [24......64] | ✅ |

| StartDate (required) | dateTime in UTC | "2024-01-01T00:00:00.000" | ✅ |

| EndDate (optional) | dateTime in UTC | "2025-12-31T23:59:59.999" | ✅ |

| ReturnInvoiceNumber (optional) | boolean | true | ✅ |

| Date Range Logic | StartDate ≤ EndDate | 2024-01-01 < 2025-12-31 | ✅ |

🚨 GOTCHA: Undocumented CustomerId Header

The request includes a header not mentioned in the official API documentation:


-H "CustomerId: 12.......34"

Important Context:

  • This is an undocumented requirement for Microsoft Ads REST APIs
  • Many other Microsoft Ads endpoints require this header despite not documenting it
  • The API accepts the request (returns 200 OK, not 400 Bad Request)
  • This header specifies which customer context to operate under

Why This Matters: Developers following only the official documentation would not know to include this header, potentially causing unexpected behavior or authorization issues.


Expected vs. Actual Behavior

Expected Behavior

The API should return billing document information for account 24.....64 during the specified date range (2024-2025), including document IDs, dates, amounts, and other metadata as documented.

Actual Behavior

The API returns an empty array {"BillingDocumentsInfo":[]} with HTTP status 200 OK.


Summary of Verified Facts

✅ Working Correctly

  • OAuth token is valid (User/Query succeeded)
  • User ID 13......47 has Super Admin permissions (RoleId: 41)
  • User has access to CustomerId 12.....34 with no account restrictions
  • Account ID 24.....64 exists and is Active
  • BillToCustomerId is "12........34" (matches query)
  • ParentCustomerId is "12........34" (matches query)
  • Account has clear financial status
  • Account has payment method configured
  • Request structure matches official API documentation
  • Authentication verified through 3 other working endpoints

❌ Not Working

  • GetBillingDocumentsInfo returns empty array
  • Date range spans 2 full years (2024-2025)
  • Other API endpoints work correctly with same authentication

Observations

  1. HTTP Status: Returns 200 OK (not an authorization error like 401 or 403)
  2. Response Structure: Valid JSON with expected field name BillingDocumentsInfo
  3. Response Content: Empty array (no billing documents returned)
  4. Authentication: Proven working through User/Query, AccountsInfo/Query, and Account/Query
  5. Permissions: Super Admin with unrestricted account access
  6. Account Configuration: Active account with Brazilian locale (BRL currency, Brasilia timezone, BR country code)

Possible Root Causes

  1. Regional/Currency Limitations: The API may have incomplete support for Brazilian accounts (BRL currency, Brasilia timezone)
  2. Undocumented Requirements: Additional configuration or prerequisites not mentioned in documentation
  3. API Implementation Gap: REST API may differ from SOAP API implementation for this endpoint
  4. Data Access Restriction: Billing documents may require additional permissions or account settings beyond Super Admin
  5. Date Handling: Potential timezone conversion issue despite using ISO 8601 format

Additional Information

  • OAuth Scope: https://ads.microsoft.com/msads.manage
  • User Email: "Information deleted by moderator"
  • User ID: 13.......47
  • Customer ID: 12......34
  • Account ID: 24......64
  • Account Number: X7......05
  • Account Currency: BRL (Brazilian Real)
  • Account Timezone: Brasilia
  • Account Country: BR (Brazil)

Report Generated: November 5, 2025

Microsoft Advertising API
Microsoft Advertising API
A Microsoft API that provides programmatic access to Microsoft Advertising to manage large campaigns or to integrate your marketing with other in-house systems.
{count} votes

Your answer

Answers can be marked as 'Accepted' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.