Summary and recommendation
Microsoft Advertising exposes user management through its Customer Management Service, a SOAP-based API (not REST) at a single endpoint: https://clientcenter.api.bingads.microsoft.com/Api/CustomerManagement/v13/CustomerManagementService.svc.
Every request requires two credentials simultaneously: an OAuth 2.0 Bearer token obtained via the Microsoft Identity Platform, and a separately issued developer token passed in the SOAP header.
Missing either causes an authentication fault.
There is no SCIM 2.0 endpoint and no webhook support;
all user state changes must be detected by polling.
This API is the integration layer used by Stitchflow's identity graph to map Microsoft Advertising user records including roles, account scopes, and lifecycle status
against authoritative identity sources across your connected app portfolio.
API quick reference
| Has user API | Yes |
| Auth method | OAuth 2.0 (Microsoft Identity Platform / Azure AD) with developer token |
| Base URL | Official docs |
| SCIM available | No |
| SCIM plan required | N/A |
Authentication
Auth method: OAuth 2.0 (Microsoft Identity Platform / Azure AD) with developer token
Setup steps
- Register an application in Azure Active Directory (Azure portal) to obtain a client_id and optionally a client_secret.
- Request OAuth 2.0 authorization using the Microsoft Identity Platform endpoint: https://login.microsoftonline.com/common/oauth2/v2.0/authorize with scope https://ads.microsoft.com/msads.manage offline_access.
- Exchange the authorization code for an access token and refresh token via https://login.microsoftonline.com/common/oauth2/v2.0/token.
- Obtain a Microsoft Advertising developer token from the Microsoft Advertising Developer Portal (https://developers.ads.microsoft.com).
- Include both the OAuth Bearer access token (Authorization header) and the developer token (DeveloperToken SOAP header) in every API request.
Required scopes
| Scope | Description | Required for |
|---|---|---|
| https://ads.microsoft.com/msads.manage | Full read/write access to Microsoft Advertising accounts and user management operations. | All Customer Management Service operations including user CRUD |
| offline_access | Allows obtaining a refresh token for long-lived access without repeated user interaction. | Maintaining persistent API access via refresh tokens |
User object / data model
| Field | Type | Description | On create | On update | Notes |
|---|---|---|---|---|---|
| Id | long | Unique system-assigned identifier for the user. | ignored (system-assigned) | required | Read-only on create. |
| UserName | string | The Microsoft account email address used to sign in. | required | read-only | Cannot be changed after creation. |
| Name.FirstName | string | User's first name. | required | optional | Part of the PersonName complex type. |
| Name.LastName | string | User's last name. | required | optional | Part of the PersonName complex type. |
| Name.MiddleInitial | string | User's middle initial. | optional | optional | Part of the PersonName complex type. |
| ContactInfo.Email | string | Contact email address for the user. | required | optional | Part of the ContactInfo complex type. |
| ContactInfo.Phone | string | Contact phone number. | optional | optional | |
| ContactInfo.Address | Address | Mailing address of the user. | optional | optional | Complex type with Street, City, StateOrProvince, CountryCode, PostalCode. |
| Lcid | LCID (enum) | Locale/language preference for the user interface. | required | optional | E.g., EnglishUS = 1033. |
| TimeStamp | base64Binary | Concurrency control timestamp; must be included on update. | ignored | required | Returned by GetUser; must be passed back unchanged on UpdateUser. |
| UserLifeCycleStatus | UserLifeCycleStatus (enum) | Current status of the user account (Active, Inactive, Pending). | system-assigned | read-only | Use DeleteUser to deactivate. |
| IsMigratedToMicrosoftAccount | boolean | Indicates whether the user has been migrated to a Microsoft account. | system-assigned | read-only | |
| ForwardCompatibilityMap | KeyValuePairOfstringstring[] | Reserved for forward compatibility; key-value pairs for future fields. | optional | optional | Do not depend on undocumented keys. |
Core endpoints
GetUser
- Method: POST
- URL:
https://clientcenter.api.bingads.microsoft.com/Api/CustomerManagement/v13/CustomerManagementService.svc - Watch out for: Passing nil UserId returns the authenticated user's own record. To retrieve another user, you must have Super Admin or Aggregator role.
Request example
<GetUserRequest xmlns="https://bingads.microsoft.com/Customer/v13">
<UserId i:nil="true" />
</GetUserRequest>
Response example
<GetUserResponse>
<User><Id>123456</Id><UserName>user@example.com</UserName>
<Name><FirstName>Jane</FirstName><LastName>Doe</LastName></Name>
<UserLifeCycleStatus>Active</UserLifeCycleStatus>
</User>
</GetUserResponse>
GetUsersInfo
- Method: POST
- URL:
https://clientcenter.api.bingads.microsoft.com/Api/CustomerManagement/v13/CustomerManagementService.svc - Watch out for: Returns lightweight UserInfo objects (Id + UserName only), not full User objects. Call GetUser per Id for full details.
Request example
<GetUsersInfoRequest xmlns="https://bingads.microsoft.com/Customer/v13">
<CustomerId>987654</CustomerId>
<StatusFilter>Active</StatusFilter>
</GetUsersInfoRequest>
Response example
<GetUsersInfoResponse>
<UsersInfo>
<UserInfo><Id>111</Id><UserName>a@example.com</UserName></UserInfo>
<UserInfo><Id>222</Id><UserName>b@example.com</UserName></UserInfo>
</UsersInfo>
</GetUsersInfoResponse>
SendUserInvitation
- Method: POST
- URL:
https://clientcenter.api.bingads.microsoft.com/Api/CustomerManagement/v13/CustomerManagementService.svc - Watch out for: User creation is invitation-based; the invitee must accept via email before the account is active. RoleId values: 16=Advertiser Campaign Manager, 41=Super Admin, 100=Viewer, 203=Standard User.
Request example
<SendUserInvitationRequest xmlns="https://bingads.microsoft.com/Customer/v13">
<UserInvitation>
<FirstName>John</FirstName><LastName>Smith</LastName>
<Email>john@example.com</Email>
<CustomerId>987654</CustomerId>
<RoleId>16</RoleId>
<Lcid>1033</Lcid>
</UserInvitation>
</SendUserInvitationRequest>
Response example
<SendUserInvitationResponse>
<UserInvitationId>99887766</UserInvitationId>
</SendUserInvitationResponse>
UpdateUser
- Method: POST
- URL:
https://clientcenter.api.bingads.microsoft.com/Api/CustomerManagement/v13/CustomerManagementService.svc - Watch out for: TimeStamp from the prior GetUser call is mandatory; omitting it causes a concurrency fault. UserName cannot be updated.
Request example
<UpdateUserRequest xmlns="https://bingads.microsoft.com/Customer/v13">
<User>
<Id>123456</Id>
<Name><FirstName>Jane</FirstName><LastName>Updated</LastName></Name>
<TimeStamp>AAAAAAB...</TimeStamp>
</User>
</UpdateUserRequest>
Response example
<UpdateUserResponse>
<LastModifiedTime>2024-01-15T10:30:00</LastModifiedTime>
</UpdateUserResponse>
DeleteUser
- Method: POST
- URL:
https://clientcenter.api.bingads.microsoft.com/Api/CustomerManagement/v13/CustomerManagementService.svc - Watch out for: Sets UserLifeCycleStatus to Inactive; does not permanently remove the record. TimeStamp is required.
Request example
<DeleteUserRequest xmlns="https://bingads.microsoft.com/Customer/v13">
<UserId>123456</UserId>
<TimeStamp>AAAAAAB...</TimeStamp>
</DeleteUserRequest>
Response example
<DeleteUserResponse xmlns="https://bingads.microsoft.com/Customer/v13" />
GetCustomerPilotFeatures
- Method: POST
- URL:
https://clientcenter.api.bingads.microsoft.com/Api/CustomerManagement/v13/CustomerManagementService.svc - Watch out for: Useful for checking feature availability before calling newer operations; pilot flag integers are not fully documented publicly.
Request example
<GetCustomerPilotFeaturesRequest xmlns="https://bingads.microsoft.com/Customer/v13">
<CustomerId>987654</CustomerId>
</GetCustomerPilotFeaturesRequest>
Response example
<GetCustomerPilotFeaturesResponse>
<FeaturePilotFlags><int>78</int><int>212</int></FeaturePilotFlags>
</GetCustomerPilotFeaturesResponse>
UpdateUserRoles
- Method: POST
- URL:
https://clientcenter.api.bingads.microsoft.com/Api/CustomerManagement/v13/CustomerManagementService.svc - Watch out for: Role changes apply at the account level. Passing DeleteRoleId removes the user's role from specified accounts. Super Admin role applies at customer level, not account level.
Request example
<UpdateUserRolesRequest xmlns="https://bingads.microsoft.com/Customer/v13">
<CustomerId>987654</CustomerId>
<UserId>123456</UserId>
<NewRoleId>41</NewRoleId>
<NewAccountIds><long>111222</long></NewAccountIds>
</UpdateUserRolesRequest>
Response example
<UpdateUserRolesResponse>
<LastModifiedTime>2024-01-15T11:00:00</LastModifiedTime>
</UpdateUserRolesResponse>
GetUserInvitations
- Method: POST
- URL:
https://clientcenter.api.bingads.microsoft.com/Api/CustomerManagement/v13/CustomerManagementService.svc - Watch out for: Only returns pending (not yet accepted) invitations. Accepted invitations appear as active users via GetUsersInfo.
Request example
<GetUserInvitationsRequest xmlns="https://bingads.microsoft.com/Customer/v13">
<CustomerId>987654</CustomerId>
<RoleId i:nil="true" />
</GetUserInvitationsRequest>
Response example
<GetUserInvitationsResponse>
<UserInvitations>
<UserInvitation><Id>99887766</Id><Email>john@example.com</Email>
<RoleId>16</RoleId><ExpirationDate>2024-02-01</ExpirationDate>
</UserInvitation>
</UserInvitations>
</GetUserInvitationsResponse>
Rate limits, pagination, and events
- Rate limits: Microsoft Advertising API enforces service call limits per developer token and per customer. Limits are documented per service operation but specific numeric thresholds are not publicly published in a single rate-limit table.
- Rate-limit headers: No
- Retry-After header: No
- Rate-limit notes: The API returns SOAP fault codes (e.g., CallRateExceeded) when limits are hit. Microsoft recommends exponential back-off retry logic. Specific numeric limits are not documented publicly.
- Pagination method: offset
- Default page size: 1000
- Max page size: 1000
- Pagination pointer: PageInfo (Index + Size elements in SOAP request)
| Plan | Limit | Concurrent |
|---|---|---|
| Standard developer token | Not publicly specified; subject to per-operation throttling | 0 |
- Webhooks available: No
- Webhook notes: Microsoft Advertising API does not offer webhooks or push notifications for user management events.
- Alternative event strategy: Poll GetUsersInfo and GetUserInvitations on a schedule to detect user state changes.
SCIM API status
- SCIM available: No
- SCIM version: Not documented
- Plan required: N/A
- Endpoint: Not documented
Limitations:
- Microsoft Advertising does not expose a SCIM 2.0 endpoint.
- User provisioning is managed exclusively through the Customer Management SOAP API via invitation flow.
- No IdP (Okta, Entra, Google Workspace) SCIM connector is officially supported for Microsoft Advertising.
Common scenarios
User creation is invitation-only via SendUserInvitation.
There is no direct CreateUser operation;
the invitee must accept the emailed link before their UserLifeCycleStatus transitions to Active and they appear in GetUsersInfo results.
Invitations expire (typically 30 days), and pending invitations are only visible via GetUserInvitations - accepted invitations do not appear there.
Role assignments are a separate operation from profile updates.
UpdateUserRoles handles role and account-scope changes;
UpdateUser handles profile fields (name, contact info).
These cannot be combined in a single call.
Note that UserName (the Microsoft account email) is immutable and cannot be changed via the API after account creation.
DeleteUser does not permanently remove a record - it sets UserLifeCycleStatus to Inactive.
Both UpdateUser and DeleteUser require the TimeStamp concurrency token returned by a prior GetUser call;
a stale or omitted timestamp causes a concurrency fault.
Super Admin (RoleId=41) is scoped at the customer level, while all other roles apply per account.
Invite a new user and assign account-level role
- Authenticate via OAuth 2.0 and obtain access token with https://ads.microsoft.com/msads.manage scope.
- Call SendUserInvitation with the user's email, FirstName, LastName, CustomerId, RoleId (e.g., 16 for Campaign Manager), and target AccountIds.
- Store the returned UserInvitationId for tracking.
- Poll GetUserInvitations periodically to check if the invitation is still pending.
- Once accepted, call GetUsersInfo to retrieve the new user's Id, then GetUser for full profile.
Watch out for: Invitations expire (typically 30 days). If the user does not accept, you must re-send the invitation. There is no way to force-create an active user without the invitation acceptance step.
List all active users for a customer
- Call GetUsersInfo with CustomerId and StatusFilter=Active.
- Iterate the returned UserInfo list (Id + UserName pairs).
- For each UserId requiring full details, call GetUser with that UserId.
- Handle pagination: GetUsersInfo returns up to 1000 records; use PageInfo (Index, Size) if the customer has more than 1000 users.
Watch out for: GetUsersInfo only returns lightweight records. Full profile data requires N additional GetUser calls, which can trigger throttling for large user bases. Implement exponential back-off.
Update a user's role across accounts
- Call GetUser to retrieve the current user record and TimeStamp.
- Call UpdateUserRoles with CustomerId, UserId, NewRoleId, and the list of AccountIds to apply the new role.
- To remove a role from specific accounts, include DeleteRoleId and DeleteAccountIds in the same request.
- Verify the change by calling GetUser again and inspecting the role assignments.
Watch out for: UpdateUserRoles and UpdateUser are separate operations. Profile field changes (name, contact info) require UpdateUser with TimeStamp; role changes use UpdateUserRoles. Mixing them in one call is not supported.
Why building this yourself is a trap
The two-credential requirement (OAuth Bearer token + developer token) is the most common integration failure point. Developer tokens for production require a separate Microsoft approval process; sandbox tokens use a different base URL (https://clientcenter.api.sandbox.bingads.microsoft.com/...) and are not interchangeable with production.
Teams that test against sandbox and deploy to production without updating the endpoint will receive authentication errors, not a clear environment mismatch signal.
Rate limit thresholds are not publicly documented in a consolidated table. The API returns a CallRateExceeded SOAP fault when throttled, with no Retry-After header. Fetching full user profiles at scale compounds this: GetUsersInfo returns lightweight Id + UserName pairs only, requiring a separate GetUser call per user for full profile data.
On large MCC hierarchies, this N+1 call pattern can trigger throttling quickly. Implement exponential back-off from the start, not as a retrofit.
Automate Microsoft Advertising workflows without one-off scripts
Stitchflow builds and maintains end-to-end IT automation across your SaaS stack, including apps without APIs. Built for exactly how your company works, with human approvals where they matter.