Blog · Microsoft CAPI
Microsoft published UET CAPI docs. Access is still a per-account pilot.
capi.uet.microsoft.com/v1/{tagId}/events is documented. You cannot assume the Use Conversions API control is on every UET tag. Microsoft still provisions access per account. A 200 is not enrollment.
The integration guide reads like general availability. There is an endpoint, a Bearer token, a data[] of events, msclkid, hashed email, visitor ids, consent, batching, error codes. People will paste a Meta CAPI worker, rewrite the host, and ship. The About CAPI help page is shorter and more honest: not everyone has this feature yet.
PPC Land reports the same gap from the other side: documentation is public, access stays a per-account pilot, and advertisers cannot switch it on themselves. I am not using their survey numbers. The vendor sentence is enough. A documented path is not an enrolled account. That is the news.
The UI path is not a self-serve flip
The integration guide tells you to edit the UET tag, choose Use Conversions API, and copy the token. A Campaign Management call, POST /CampaignManagement/v13/UetTagAuthKey/Query, returns TagAuthKey.AuthKey for a TagId. If a token already exists, you get the existing one. Callers who only see a shared tag can retrieve; they cannot generate. If the tag is invalid or not visible, you get an error.
Microsoft's About CAPI page still carries the feature-not-on-every-account note. If Use Conversions API is missing from the tagging setup, the account that owns the tag is not enrolled. A manager account can look fully configured while the client's customer ID has no CAPI. The flag sits on the account that owns the UET tag, not on the agency MCC.
Posting to capi.uet.microsoft.com without that enrollment is not a clever workaround. Auth is Bearer plus the UET tagId in the path. 401 is a missing, wrong, or unauthorized token. A 200 from a sandbox you stood up against the documented host is not proof Microsoft attached CAPI to the customer. Enrollment is the account, not the JSON.
Run it with the JS tag. Same eventId and eventName.
Microsoft recommends using CAPI with UET whenever possible. UET captures browser activity and page context. CAPI sends the server event that happens after that, or instead of it when JavaScript cannot run. If both pipes fire the same conversion, pass the same eventId and a compatible eventName on the same tagId. That is how Microsoft avoids counting the purchase twice.
Website events are two types. pageLoad once per page view or SPA navigation, with eventSourceUrl, referrerUrl, pageTitle, and a pageLoadId as a v4 UUID. custom for checkout, purchase, cart, search, product view. When a custom action belongs to a page, reuse pageLoadId. Conversion goals have to exist on that UET tag and match the eventName you post. Microsoft will accept events with a 200 when no goal is tied to that action. No conversion appears.
Revenue does not ride on a pageLoad. If a destination URL goal needs variable revenue, the documented answer is a second custom event that carries only the value and the matching pageLoadId. Sending Purchase as a Graph event_name on a Microsoft pageLoad is the wrong eventType, the wrong name, and no join to the page. eventTime is a UNIX epoch in seconds, UTC, within the last 7 days. A millisecond clock, or a Meta helper you already floored, can still 400 as InvalidEventTime.
ID Sync stays in the browser
CAPI does not replace the identity pixel. Microsoft wants a client-side ID Sync to c.bing.com/c.gif so it can read browser context at sync time. Red3 is required: a Microsoft-assigned customer ID in the form BACID_ plus that id. VID is required: the guest anonymous id, preferably a v1 UUID, and it must match userData.anonymousId on the server events. UID is optional and lines up with externalId. The customer ID is not the UET tag ID. One customer account can hold several tags.
ID Sync is required for audience creation, remarketing, and dynamic remarketing. It is strongly recommended for conversion measurement quality when msclkid or hashed identifiers are thin. Do not send raw email, raw phone, or real user ids on the pixel. A 200 on CAPI does not grow a remarketing list if the sync never fired, or if VID and anonymousId drifted.
msclkid remains the click id. Auto-tagging appends it to the landing URL. Suggested retention is 90 days. Store the most recent UUID, overwrite on a new click, and send it on later events. Microsoft says not to rely on visitor ID alone when msclkid is available. userData must include at least one of anonymousId, externalId, em, ph, msclkid, idfa, or gaid. em and ph are hashed. clientIpAddress and clientUserAgent stay plaintext.
The body people will send first
A Meta CAPI purchase. Microsoft wants eventType, eventName, eventId, and userData.msclkid on capi.uet.microsoft.com.
{
"data": [{
"event_name": "Purchase",
"event_time": 1755552000,
"action_source": "website",
"event_source_url": "https://shop.example.com/checkout",
"user_data": { "em": ["64ec88ca..."] }
}]
}
That object is a legal Meta event if the hash is right. Posted to Microsoft it is the wrong field names inside data[], no eventType, website instead of a Microsoft event, and no msclkid. The host can still return 200 when continueOnValidationError is true and some other row in the batch is valid. Warnings strip optional fields and still 200. A 200 is not a conversion, and it is not enrollment.
Batches can hold up to 1,000 events. Default is all-or-nothing: one validation error 400s the batch. continueOnValidationError true processes the valid rows and reports the rest. Real-time is preferred. Auth is Authorization: Bearer plus the token for that tagId. Mixing a Graph token, or a token from a different tag, is a 401 that looks like a broken worker.
Names that do not translate
- Graph event_name Purchase is eventType custom plus eventName that matches the UET goal.
- event_time milliseconds is eventTime in seconds, within seven days.
- action_source website is not a Microsoft field. Use eventType pageLoad or custom.
- event_source_url is eventSourceUrl, required on pageLoad.
- event_id is eventId. Reuse it on the UET JavaScript event_id.
- user_data.em is userData.em. fbclid is not msclkid.
- A Graph 200 is not Microsoft enrollment. About CAPI still says not every account has the feature.
Consent and the default that will bite
adStorageConsent is G for granted and D for denied. Denied events are not used for advertising, including attribution and retargeting. If you omit the field, Microsoft treats consent as granted. That default is in the payload reference. For regions where you must signal consent before advertising storage, omitting the field is not a conservative choice.
About CAPI describes two flows: server-to-server UET events and client-side ID synchronization. Page loads for every page view, custom events for richer actions, hashed identifiers and click ids on the JSON, delivered in real time. That is the product. It is not a Meta dialect with the host rewritten, and it is not on every account because the Learn page exists.
Microsoft recommends using CAPI with Universal Event Tracking (UET) whenever possible. UET captures browser-based activity and page context, while CAPI provides a server-side path for sending additional events and details that occur after UET fires.
Microsoft UET Conversion API integration
What to do
Ask whether the customer ID that owns the UET tag is enrolled before you build the worker. If Use Conversions API is absent, stop. Do not scrape a token from a manager account and POST against a client tag. Keep the JS tag. Copy eventId and eventName onto both pipes. Capture msclkid on the landing hit. Fire ID Sync client-side with Red3 and a VID that matches anonymousId.
Emit Microsoft's envelope at the edge: data[] with eventType, eventTime in seconds, userData, customData. Persist Meta event_id and Microsoft eventId as different columns if you send both vendors. Lint the body you actually POST. The Microsoft pack is vendor/microsoft-conversions-api. One fixture cannot serve Graph and UET CAPI.
The contract page for pixel plus CAPI is the docs. This post is the market fact: Microsoft published the hop, and access is still gated. Pixellint is not affiliated with Microsoft. Passing a linter means the artifact matches the published envelope. It does not mean Microsoft attributed the conversion, and it does not mean the account is in the pilot.
Checklist
- Confirm the account that owns the UET tag has CAPI. About CAPI still says not every account does.
- POST to https://capi.uet.microsoft.com/v1/{tagId}/events with Authorization: Bearer <token> for that tag.
- Send data[] with eventType pageLoad or custom. eventTime is Unix seconds, last seven days.
- Reuse eventId and eventName on UET JavaScript and CAPI. Same tagId.
- Pass msclkid. Fire ID Sync to c.bing.com with Red3 and a VID that matches anonymousId.
- A 200 is not enrollment, not a conversion goal match, and not proof every field survived validation.
Sources
Contract pages
The dated argument is above. These pages are the field lists.