{"id":9355,"date":"2026-08-10T07:10:00","date_gmt":"2026-08-10T05:10:00","guid":{"rendered":"https:\/\/www.lukaswojcik.com\/blog\/?p=9355"},"modified":"2026-10-24T02:15:20","modified_gmt":"2026-10-24T00:15:20","slug":"microsoft-advertising-conversions-api-server-side-uet-in-practice","status":"publish","type":"post","link":"https:\/\/www.lukaswojcik.com\/blog\/en\/digital-marketing\/microsoft-advertising-conversions-api-server-side-uet-in-practice\/","title":{"rendered":"Microsoft Advertising Conversions API: Server-Side UET in Practice"},"content":{"rendered":"<p>Microsoft Advertising Conversions API (CAPI) provides a server route for events recorded in checkout, CRM or other systems. This can reduce gaps caused by a missing browser request. An accepted event is not automatically an attributed conversion: consent, identifiers, conversion goals and attribution rules still apply.<\/p>\n<p>The practical work comprises event mapping, credentials, permitted identifiers, duplicate handling and an observable delivery queue. A universal implementation estimate of one or two weeks would hide differences between existing data systems. The May 2026 release added GetUetTagAuthKey and the click-ID performance report; a documentation update date alone does not prove a change in backend behavior.<\/p>\n<h2>1. Request contract and credentials<\/h2>\n<p>Events are posted as JSON to <code>https:\/\/capi.uet.microsoft.com\/v1\/{tagId}\/events<\/code>, with the tag&#8217;s CAPI key in <code>Authorization: Bearer \u2026<\/code>. The <code>data<\/code> array contains at most 1,000 events. <code>eventType<\/code> is <code>custom<\/code> or <code>pageLoad<\/code>; <code>eventTime<\/code> is UTC Unix time in seconds within the preceding seven days. <code>userData<\/code> requires at least one supported identifier. Page-load events also require <code>eventSourceUrl<\/code>. Custom conversion goals must match the configured event properties.<\/p>\n<p>The separate Campaign Management call uses OAuth and the required developer\/account headers. Those credentials are not interchangeable with the CAPI key. <code>GetUetTagAuthKey<\/code> retrieves an existing key; creating a key when none exists requires ownership of the tag. Retrieving a key again does not rotate that key. Regeneration or revocation must follow the supported account process.<\/p>\n<h2>2. A real documentation mismatch, with limited conclusions<\/h2>\n<p>At the review date of 24 October 2026, the integration guide shows <code>TagId<\/code> and a nested <code>TagAuthKey.AuthKey<\/code> response. The operation reference shows <code>UetTagId<\/code> and a flat <code>UetTagAuthKey<\/code>. This is a documentation inconsistency, not evidence that each account uses a different API contract. Requests should follow the selected SDK or operation contract and be validated in an authorized integration environment.<\/p>\n<p>The adapter below accepts dictionary and object responses in either described shape, rejects reported partial errors and conflicting keys, and never logs the secret. Dictionary access is used only after checking the response type.<\/p>\n<figure style=\"--cbb-digits:2\" class=\"cbb cbb--wrap cbb--numbers wp-block-code-beautifier-block-code\" data-lang=\"python\"><figcaption class=\"cbb-head\"><span class=\"cbb-lang\">Python<\/span><span class=\"cbb-actions\"><button type=\"button\" class=\"cbb-button cbb-button--wrap\" data-cbb-action=\"wrap\" aria-pressed=\"true\" title=\"Wrap long lines\"><svg aria-hidden=\"true\" focusable=\"false\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\"><path d=\"M2 4h12M2 8h9.5a2.5 2.5 0 0 1 0 5H8m0 0 1.5-1.5M8 13l1.5 1.5M2 12h3\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"\/><\/svg><span class=\"cbb-sr\">Wrap long lines<\/span><\/button><button type=\"button\" class=\"cbb-button cbb-button--copy\" data-cbb-action=\"copy\" data-cbb-done=\"Copied\" data-cbb-failed=\"Press Ctrl+C to copy\"><svg aria-hidden=\"true\" focusable=\"false\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\"><rect x=\"5.5\" y=\"5.5\" width=\"8\" height=\"8.5\" rx=\"1.5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"\/><path d=\"M10.5 3.5V3A1.5 1.5 0 0 0 9 1.5H4A1.5 1.5 0 0 0 2.5 3v6.5A1.5 1.5 0 0 0 4 11h.5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"\/><\/svg><span class=\"cbb-button-label\" aria-live=\"polite\">Copy<\/span><\/button><\/span><\/figcaption><pre class=\"cbb-pre\" tabindex=\"0\"><code class=\"cbb-code language-python\" style=\"counter-reset:cbb-line 0;\"><span class=\"cbb-line\"><span class=\"cbb-keyword\">from<\/span> collections.abc <span class=\"cbb-keyword\">import<\/span> Mapping\n<\/span><span class=\"cbb-line\">\n<\/span><span class=\"cbb-line\"><span class=\"cbb-keyword\">def<\/span> <span class=\"cbb-function\">field<\/span>(value, name):\n<\/span><span class=\"cbb-line\">    <span class=\"cbb-keyword\">return<\/span> value.<span class=\"cbb-function\">get<\/span>(name) <span class=\"cbb-keyword\">if<\/span> <span class=\"cbb-function\">isinstance<\/span>(value, Mapping) <span class=\"cbb-keyword\">else<\/span> <span class=\"cbb-function\">getattr<\/span>(value, name, <span class=\"cbb-constant\">None<\/span>)\n<\/span><span class=\"cbb-line\">\n<\/span><span class=\"cbb-line\"><span class=\"cbb-keyword\">def<\/span> <span class=\"cbb-function\">extract_auth_key<\/span>(response):\n<\/span><span class=\"cbb-line\">    <span class=\"cbb-keyword\">if<\/span> <span class=\"cbb-function\">field<\/span>(response, <span class=\"cbb-string\">\"PartialErrors\"<\/span>):\n<\/span><span class=\"cbb-line\">        <span class=\"cbb-keyword\">raise<\/span> <span class=\"cbb-function\">ValueError<\/span>(<span class=\"cbb-string\">\"Auth response contains errors; inspect redacted diagnostics\"<\/span>)\n<\/span><span class=\"cbb-line\">    values = &#91;<span class=\"cbb-function\">field<\/span>(response, <span class=\"cbb-string\">\"UetTagAuthKey\"<\/span>),\n<\/span><span class=\"cbb-line\">              <span class=\"cbb-function\">field<\/span>(<span class=\"cbb-function\">field<\/span>(response, <span class=\"cbb-string\">\"TagAuthKey\"<\/span>), <span class=\"cbb-string\">\"AuthKey\"<\/span>)&#93;\n<\/span><span class=\"cbb-line\">    keys = {v <span class=\"cbb-keyword\">for<\/span> v <span class=\"cbb-keyword\">in<\/span> values <span class=\"cbb-keyword\">if<\/span> <span class=\"cbb-function\">isinstance<\/span>(v, str) <span class=\"cbb-keyword\">and<\/span> v.<span class=\"cbb-function\">strip<\/span>()}\n<\/span><span class=\"cbb-line\">    <span class=\"cbb-keyword\">if<\/span> <span class=\"cbb-function\">len<\/span>(keys) != <span class=\"cbb-number\">1<\/span>:\n<\/span><span class=\"cbb-line\">        <span class=\"cbb-keyword\">raise<\/span> <span class=\"cbb-function\">ValueError<\/span>(<span class=\"cbb-string\">\"Missing or conflicting auth-key fields\"<\/span>)\n<\/span><span class=\"cbb-line\">    key = keys.<span class=\"cbb-function\">pop<\/span>()\n<\/span><span class=\"cbb-line\">    <span class=\"cbb-keyword\">if<\/span> <span class=\"cbb-function\">any<\/span>(c.<span class=\"cbb-function\">isspace<\/span>() <span class=\"cbb-keyword\">or<\/span> <span class=\"cbb-function\">ord<\/span>(c) &lt; <span class=\"cbb-number\">32<\/span> <span class=\"cbb-keyword\">or<\/span> <span class=\"cbb-function\">ord<\/span>(c) == <span class=\"cbb-number\">127<\/span> <span class=\"cbb-keyword\">for<\/span> c <span class=\"cbb-keyword\">in<\/span> key):\n<\/span><span class=\"cbb-line\">        <span class=\"cbb-keyword\">raise<\/span> <span class=\"cbb-function\">ValueError<\/span>(<span class=\"cbb-string\">\"Invalid auth-key whitespace\/control character\"<\/span>)\n<\/span><span class=\"cbb-line\">    <span class=\"cbb-keyword\">return<\/span> key<\/span><\/code><\/pre><\/figure>\n<figure class=\"lw-diagram\"><img decoding=\"async\" src=\"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/diagrams\/quality-9355-auth-20261024.png\" width=\"1120\" height=\"720\" loading=\"lazy\" alt=\"The guide and operation reference disagree on field names. The adapter checks both shapes without treating key retrieval as rotation.\"><figcaption>The guide and operation reference disagree on field names. The adapter checks both shapes without treating key retrieval as rotation.<\/figcaption><\/figure>\n<p>Schema tolerance cannot repair wrong credentials or an invalid request. Diagnostic logs should contain request\/tracking IDs, status and a redacted error classification. Raw auth responses, bearer headers and customer data do not belong in ordinary logs. Loading a newly approved secret between batches helps deployment, but neither zero-downtime rotation nor negligible secret-store latency is guaranteed.<\/p>\n<h2>3. Deduplication is more than an order number<\/h2>\n<p>Browser and server copies of the same event need the same UET tag, compatible event name and stable event ID. UET JavaScript uses <code>event_id<\/code>; CAPI uses <code>eventId<\/code>. An ID should identify the business event, for example the completed purchase, and remain unchanged across retries. Purchase and refund are different events even when both reference one order.<\/p>\n<p>A stored random event ID or a deliberately namespaced order-event ID can provide this stability. No second random ID should be generated by the other transport. Server-only CRM events have no browser counterpart to merge, but still need reliable retry bookkeeping. Stable IDs support duplicate prevention; a crash-proof, exactly-once delivery guarantee does not follow from one field.<\/p>\n<figure class=\"lw-diagram\"><img decoding=\"async\" src=\"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/diagrams\/quality-9355-flow-20261024.png\" width=\"1120\" height=\"720\" loading=\"lazy\" alt=\"Matching UET tag, event name and stable ID support duplicate prevention. HTTP acceptance and attribution require separate checks.\"><figcaption>Matching UET tag, event name and stable ID support duplicate prevention. HTTP acceptance and attribution require separate checks.<\/figcaption><\/figure>\n<h2>4. Field-specific normalization and consent<\/h2>\n<p>Microsoft&#8217;s current email instructions include trimming edge whitespace, removing dots and the plus-alias from the local part, lowercasing and SHA-256 hashing. This is a Microsoft-specific matching rule, not a general rule for editing stored contact addresses or other platforms. Phone hashing uses canonical E.164 including the leading plus. The helper accepts an already normalized international number; country-aware parsing and real-number validation belong upstream.<\/p>\n<figure style=\"--cbb-digits:2\" class=\"cbb cbb--wrap cbb--numbers wp-block-code-beautifier-block-code\" data-lang=\"python\"><figcaption class=\"cbb-head\"><span class=\"cbb-lang\">Python<\/span><span class=\"cbb-actions\"><button type=\"button\" class=\"cbb-button cbb-button--wrap\" data-cbb-action=\"wrap\" aria-pressed=\"true\" title=\"Wrap long lines\"><svg aria-hidden=\"true\" focusable=\"false\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\"><path d=\"M2 4h12M2 8h9.5a2.5 2.5 0 0 1 0 5H8m0 0 1.5-1.5M8 13l1.5 1.5M2 12h3\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"\/><\/svg><span class=\"cbb-sr\">Wrap long lines<\/span><\/button><button type=\"button\" class=\"cbb-button cbb-button--copy\" data-cbb-action=\"copy\" data-cbb-done=\"Copied\" data-cbb-failed=\"Press Ctrl+C to copy\"><svg aria-hidden=\"true\" focusable=\"false\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\"><rect x=\"5.5\" y=\"5.5\" width=\"8\" height=\"8.5\" rx=\"1.5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"\/><path d=\"M10.5 3.5V3A1.5 1.5 0 0 0 9 1.5H4A1.5 1.5 0 0 0 2.5 3v6.5A1.5 1.5 0 0 0 4 11h.5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"\/><\/svg><span class=\"cbb-button-label\" aria-live=\"polite\">Copy<\/span><\/button><\/span><\/figcaption><pre class=\"cbb-pre\" tabindex=\"0\"><code class=\"cbb-code language-python\" style=\"counter-reset:cbb-line 0;\"><span class=\"cbb-line\"><span class=\"cbb-keyword\">import<\/span> hashlib\n<\/span><span class=\"cbb-line\"><span class=\"cbb-keyword\">import<\/span> re\n<\/span><span class=\"cbb-line\">\n<\/span><span class=\"cbb-line\"><span class=\"cbb-keyword\">def<\/span> <span class=\"cbb-function\">microsoft_email_hash<\/span>(value):\n<\/span><span class=\"cbb-line\">    <span class=\"cbb-keyword\">if<\/span> <span class=\"cbb-keyword\">not<\/span> <span class=\"cbb-function\">isinstance<\/span>(value, str):\n<\/span><span class=\"cbb-line\">        <span class=\"cbb-keyword\">return<\/span> <span class=\"cbb-constant\">None<\/span>\n<\/span><span class=\"cbb-line\">    value = value.<span class=\"cbb-function\">strip<\/span>()\n<\/span><span class=\"cbb-line\">    <span class=\"cbb-keyword\">if<\/span> value.<span class=\"cbb-function\">count<\/span>(<span class=\"cbb-string\">\"@\"<\/span>) != <span class=\"cbb-number\">1<\/span> <span class=\"cbb-keyword\">or<\/span> <span class=\"cbb-function\">any<\/span>(c.<span class=\"cbb-function\">isspace<\/span>() <span class=\"cbb-keyword\">or<\/span> <span class=\"cbb-function\">ord<\/span>(c) &lt; <span class=\"cbb-number\">32<\/span> <span class=\"cbb-keyword\">for<\/span> c <span class=\"cbb-keyword\">in<\/span> value):\n<\/span><span class=\"cbb-line\">        <span class=\"cbb-keyword\">return<\/span> <span class=\"cbb-constant\">None<\/span>\n<\/span><span class=\"cbb-line\">    local, domain = value.<span class=\"cbb-function\">split<\/span>(<span class=\"cbb-string\">\"@\"<\/span>)\n<\/span><span class=\"cbb-line\">    local = local.<span class=\"cbb-function\">split<\/span>(<span class=\"cbb-string\">\"+\"<\/span>, <span class=\"cbb-number\">1<\/span>)&#91;<span class=\"cbb-number\">0<\/span>&#93;.<span class=\"cbb-function\">replace<\/span>(<span class=\"cbb-string\">\".\"<\/span>, <span class=\"cbb-string\">\"\"<\/span>)\n<\/span><span class=\"cbb-line\">    <span class=\"cbb-keyword\">if<\/span> <span class=\"cbb-keyword\">not<\/span> local <span class=\"cbb-keyword\">or<\/span> <span class=\"cbb-keyword\">not<\/span> domain <span class=\"cbb-keyword\">or<\/span> <span class=\"cbb-string\">\".\"<\/span> <span class=\"cbb-keyword\">not<\/span> <span class=\"cbb-keyword\">in<\/span> domain:\n<\/span><span class=\"cbb-line\">        <span class=\"cbb-keyword\">return<\/span> <span class=\"cbb-constant\">None<\/span>\n<\/span><span class=\"cbb-line\">    <span class=\"cbb-keyword\">return<\/span> hashlib.<span class=\"cbb-function\">sha256<\/span>((local + <span class=\"cbb-string\">\"@\"<\/span> + domain).<span class=\"cbb-function\">lower<\/span>().<span class=\"cbb-function\">encode<\/span>(<span class=\"cbb-string\">\"utf-8\"<\/span>)).<span class=\"cbb-function\">hexdigest<\/span>()\n<\/span><span class=\"cbb-line\">\n<\/span><span class=\"cbb-line\"><span class=\"cbb-keyword\">def<\/span> <span class=\"cbb-function\">microsoft_phone_hash<\/span>(e164):\n<\/span><span class=\"cbb-line\">    <span class=\"cbb-keyword\">if<\/span> <span class=\"cbb-keyword\">not<\/span> <span class=\"cbb-function\">isinstance<\/span>(e164, str) <span class=\"cbb-keyword\">or<\/span> <span class=\"cbb-keyword\">not<\/span> re.<span class=\"cbb-function\">fullmatch<\/span>(<span class=\"cbb-string\">r\"\\+&#91;1-9&#93;&#91;0-9&#93;{6,14}\"<\/span>, e164):\n<\/span><span class=\"cbb-line\">        <span class=\"cbb-keyword\">return<\/span> <span class=\"cbb-constant\">None<\/span>\n<\/span><span class=\"cbb-line\">    <span class=\"cbb-keyword\">return<\/span> hashlib.<span class=\"cbb-function\">sha256<\/span>(e164.<span class=\"cbb-function\">encode<\/span>(<span class=\"cbb-string\">\"utf-8\"<\/span>)).<span class=\"cbb-function\">hexdigest<\/span>()<\/span><\/code><\/pre><\/figure>\n<p>These helpers are deliberately narrow examples, not complete email or telephone validators. Invalid or unavailable identifiers should be omitted rather than replaced by hashes of placeholders. IP address, user agent and click ID follow their own field rules; the blanket instruction to hash every identifier is wrong. Hashing also does not make identifying data anonymous.<\/p>\n<p><code>adStorageConsent<\/code> accepts <code>G<\/code> or <code>D<\/code>. The documented default when omitted is granted. Explicit consent handling therefore matters: a denied event is not used for advertising purposes, including attribution and remarketing. That field is not permission to send otherwise prohibited personal data.<\/p>\n<p>The application must establish a permitted collection and delivery basis, retain the relevant consent evidence and recheck applicable withdrawal or suppression rules before queued delivery. A historical grant is not a reason to ignore a later withdrawal. A telephone sale may have a separate consent record; absence of a web banner alone establishes neither permission nor prohibition. Unknown must never silently become granted.<\/p>\n<h2>5. Seven days, future timestamps and the last hour<\/h2>\n<p>An age check must reject future timestamps without discarding valid events merely because expiry is approaching. The function separates invalid, future, expired and urgent timestamps. An urgent event remains eligible for an immediate attempt; the warning margin is not an earlier API expiry. Eligibility must be checked again immediately before dispatch.<\/p>\n<figure style=\"--cbb-digits:2\" class=\"cbb cbb--wrap cbb--numbers wp-block-code-beautifier-block-code\" data-lang=\"python\"><figcaption class=\"cbb-head\"><span class=\"cbb-lang\">Python<\/span><span class=\"cbb-actions\"><button type=\"button\" class=\"cbb-button cbb-button--wrap\" data-cbb-action=\"wrap\" aria-pressed=\"true\" title=\"Wrap long lines\"><svg aria-hidden=\"true\" focusable=\"false\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\"><path d=\"M2 4h12M2 8h9.5a2.5 2.5 0 0 1 0 5H8m0 0 1.5-1.5M8 13l1.5 1.5M2 12h3\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"\/><\/svg><span class=\"cbb-sr\">Wrap long lines<\/span><\/button><button type=\"button\" class=\"cbb-button cbb-button--copy\" data-cbb-action=\"copy\" data-cbb-done=\"Copied\" data-cbb-failed=\"Press Ctrl+C to copy\"><svg aria-hidden=\"true\" focusable=\"false\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\"><rect x=\"5.5\" y=\"5.5\" width=\"8\" height=\"8.5\" rx=\"1.5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"\/><path d=\"M10.5 3.5V3A1.5 1.5 0 0 0 9 1.5H4A1.5 1.5 0 0 0 2.5 3v6.5A1.5 1.5 0 0 0 4 11h.5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"\/><\/svg><span class=\"cbb-button-label\" aria-live=\"polite\">Copy<\/span><\/button><\/span><\/figcaption><pre class=\"cbb-pre\" tabindex=\"0\"><code class=\"cbb-code language-python\" style=\"counter-reset:cbb-line 0;\"><span class=\"cbb-line\"><span class=\"cbb-keyword\">from<\/span> datetime <span class=\"cbb-keyword\">import<\/span> datetime, timedelta, timezone\n<\/span><span class=\"cbb-line\">\n<\/span><span class=\"cbb-line\"><span class=\"cbb-keyword\">def<\/span> <span class=\"cbb-function\">event_age_state<\/span>(event_time, now):\n<\/span><span class=\"cbb-line\">    <span class=\"cbb-keyword\">if<\/span> <span class=\"cbb-keyword\">not<\/span> <span class=\"cbb-function\">isinstance<\/span>(event_time, datetime) <span class=\"cbb-keyword\">or<\/span> <span class=\"cbb-keyword\">not<\/span> <span class=\"cbb-function\">isinstance<\/span>(now, datetime):\n<\/span><span class=\"cbb-line\">        <span class=\"cbb-keyword\">return<\/span> <span class=\"cbb-string\">\"invalid\"<\/span>\n<\/span><span class=\"cbb-line\">    <span class=\"cbb-keyword\">if<\/span> event_time.tzinfo <span class=\"cbb-keyword\">is<\/span> <span class=\"cbb-constant\">None<\/span> <span class=\"cbb-keyword\">or<\/span> event_time.<span class=\"cbb-function\">utcoffset<\/span>() <span class=\"cbb-keyword\">is<\/span> <span class=\"cbb-constant\">None<\/span> <span class=\"cbb-keyword\">or<\/span> now.tzinfo <span class=\"cbb-keyword\">is<\/span> <span class=\"cbb-constant\">None<\/span> <span class=\"cbb-keyword\">or<\/span> now.<span class=\"cbb-function\">utcoffset<\/span>() <span class=\"cbb-keyword\">is<\/span> <span class=\"cbb-constant\">None<\/span>:\n<\/span><span class=\"cbb-line\">        <span class=\"cbb-keyword\">return<\/span> <span class=\"cbb-string\">\"invalid\"<\/span>\n<\/span><span class=\"cbb-line\">    age = now.<span class=\"cbb-function\">astimezone<\/span>(timezone.utc) - event_time.<span class=\"cbb-function\">astimezone<\/span>(timezone.utc)\n<\/span><span class=\"cbb-line\">    <span class=\"cbb-keyword\">if<\/span> age &lt; <span class=\"cbb-function\">timedelta<\/span>(<span class=\"cbb-number\">0<\/span>):\n<\/span><span class=\"cbb-line\">        <span class=\"cbb-keyword\">return<\/span> <span class=\"cbb-string\">\"future\"<\/span>\n<\/span><span class=\"cbb-line\">    <span class=\"cbb-keyword\">if<\/span> age &gt;= <span class=\"cbb-function\">timedelta<\/span>(days=<span class=\"cbb-number\">7<\/span>):\n<\/span><span class=\"cbb-line\">        <span class=\"cbb-keyword\">return<\/span> <span class=\"cbb-string\">\"expired\"<\/span>\n<\/span><span class=\"cbb-line\">    <span class=\"cbb-keyword\">if<\/span> age &gt;= <span class=\"cbb-function\">timedelta<\/span>(days=<span class=\"cbb-number\">7<\/span>, hours=<span class=\"cbb-number\">-1<\/span>):\n<\/span><span class=\"cbb-line\">        <span class=\"cbb-keyword\">return<\/span> <span class=\"cbb-string\">\"urgent\"<\/span>\n<\/span><span class=\"cbb-line\">    <span class=\"cbb-keyword\">return<\/span> <span class=\"cbb-string\">\"ready\"<\/span><\/span><\/code><\/pre><\/figure>\n<p>The seven-day boundary is handled conservatively as expired. The helper returns states only; it neither sends nor discards records. A durable queue needs explicit outcomes, bounded retry scheduling and ownership of in-flight work. A worker crash can leave delivery uncertain, so a state column alone is not proof of harmless recovery. Old events cannot be backdated to the current time to bypass the window.<\/p>\n<h2>6. HTTP success and event success differ<\/h2>\n<p>The guide now explicitly documents HTTP 400 validation failures and 401 authorization failures. A 401 requires credential\/tag correction; an unchanged invalid payload should not be retried indefinitely after a 400. Transient transport or service failures may use bounded exponential backoff with jitter. A response that actually supplies a Retry-After instruction should be handled accordingly; no undocumented numeric rate limit is assumed.<\/p>\n<p>By default, a validation error prevents processing the entire batch. With <code>continueOnValidationError: true<\/code>, valid events can be processed while invalid ones are skipped. HTTP 200 can therefore contain errors or warnings; a warning can mean an optional field was removed. <code>eventsReceived<\/code> and diagnostic details must be reconciled before marking records accepted. The documentation limits detailed errors\/warnings to the first ten, so absence from the visible error list is not always sufficient proof of acceptance for every record.<\/p>\n<p>A simpler initial policy keeps partial processing disabled, validates locally and isolates invalid records for correction. Monitoring should distinguish API acceptance, rejected events, removed fields and later attributed conversions. Logs should store safe identifiers and error categories instead of unrestricted response bodies.<\/p>\n<h2>7. Monitoring and reconciliation<\/h2>\n<p>Useful measures include oldest pending age, urgent\/expired counts, delivery-lag percentiles, accepted event counts, validation failures, consent state and coverage of all supported identifiers. \u201cNo email hash\u201d does not mean \u201cno identifier\u201d; an event may carry msclkid or another accepted field. An expired count can result from old backfill or incorrect timestamps and does not prove a six-day outage.<\/p>\n<p>Sudden consent or identifier changes justify investigation, but do not prove a particular form or consent-tool defect. Traffic mix, acquisition channels and legitimate business changes can also move those figures. Microsoft-reported conversions are not expected to equal all accepted orders: matching, goals, windows, counting settings, reporting dates and processing delay affect the comparison.<\/p>\n<div class=\"lw-faq\"><h2>Questions and answers<\/h2><h3>Can aggregate totals prove deduplication?<\/h3><p>No. Aligned totals can reveal suspicious changes, but event-level test cases and delivery records are needed to isolate duplicate handling. A lower platform total does not by itself prove lost API events.<\/p><h3>Is the click-ID report mandatory?<\/h3><p>No. MSClickIdPerformanceReport can support click-level analysis when available. Its column reference includes feature-specific availability notices; two notices on that page do not prove that the entire report is a pilot. ConversionsQualified is documented as a double. Account availability and report semantics must be checked before making the report an operational dependency.<\/p><h3>What changes for remarketing?<\/h3><p>The current guide requires client-side ID Sync for remarketing\/audience use and recommends it for conversion measurement quality. A server-only event feed does not automatically replace that browser step. Any sync must follow the applicable consent controls, and the visitor ID must align with anonymousId in the server event.<\/p><\/div><div class=\"lw-quellen\"><h2>Sources<\/h2><ul><li><a href=\"https:\/\/learn.microsoft.com\/en-us\/advertising\/guides\/uet-conversion-api-integration?view=bingads-13\" target=\"_blank\" rel=\"noopener noreferrer\">Microsoft: CAPI integration<\/a><\/li><li><a href=\"https:\/\/learn.microsoft.com\/en-us\/advertising\/campaign-management-service\/getuettagauthkey?view=bingads-13\" target=\"_blank\" rel=\"noopener noreferrer\">Microsoft: GetUetTagAuthKey<\/a><\/li><li><a href=\"https:\/\/learn.microsoft.com\/en-us\/advertising\/guides\/release-notes?view=bingads-13\" target=\"_blank\" rel=\"noopener noreferrer\">Microsoft: API release notes<\/a><\/li><li><a href=\"https:\/\/learn.microsoft.com\/en-us\/advertising\/reporting-service\/msclickidperformancereportcolumn?view=bingads-13\" target=\"_blank\" rel=\"noopener noreferrer\">Microsoft: click-ID report columns<\/a><\/li><li><a href=\"https:\/\/learn.microsoft.com\/en-us\/advertising\/guides\/universal-event-tracking?view=bingads-13\" target=\"_blank\" rel=\"noopener noreferrer\">Microsoft: Universal Event Tracking<\/a><\/li><li><a href=\"https:\/\/learn.microsoft.com\/en-us\/advertising\/guides\/reports?view=bingads-13\" target=\"_blank\" rel=\"noopener noreferrer\">Microsoft: reporting<\/a><\/li><\/ul><\/div>","protected":false},"excerpt":{"rendered":"<p>Microsoft&#8217;s Conversions API sends purchases from the server to UET: the endpoint, the auth key, deduplication, hashing, and the differing response shapes documented in guide and reference.<\/p>\n","protected":false},"author":1,"featured_media":13788,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[6],"tags":[91261,91386,91285,91516],"class_list":["post-9355","post","type-post","status-publish","format-standard","hentry","category-digital-marketing","tag-conversion-tracking","tag-marketing-cyfrowy-pl","tag-first-party-data","tag-tracking"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.1 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Microsoft Advertising Conversions API: Server-Side UET in Practice | Lukas Wojcik<\/title>\n<meta name=\"description\" content=\"Microsoft Advertising Conversions API: UET server events, authentication, deduplication, hashing and response validation.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.lukaswojcik.com\/blog\/en\/digital-marketing\/microsoft-advertising-conversions-api-server-side-uet-in-practice\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Microsoft Advertising Conversions API: Server-Side UET in Practice | Lukas Wojcik\" \/>\n<meta property=\"og:description\" content=\"Microsoft Advertising Conversions API: UET server events, authentication, deduplication, hashing and response validation.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.lukaswojcik.com\/blog\/en\/digital-marketing\/microsoft-advertising-conversions-api-server-side-uet-in-practice\/\" \/>\n<meta property=\"og:site_name\" content=\"Lukas Wojcik - Blog\" \/>\n<meta property=\"article:published_time\" content=\"2026-08-10T05:10:00+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-10-24T00:15:20+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/09\/hero-9355-microsoft-advertising-conversions-ap-g.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1200\" \/>\n\t<meta property=\"og:image:height\" content=\"630\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Lukas Wojcik\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Lukas Wojcik\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"8 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/digital-marketing\\\/microsoft-advertising-conversions-api-server-side-uet-in-practice\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/digital-marketing\\\/microsoft-advertising-conversions-api-server-side-uet-in-practice\\\/\"},\"author\":{\"name\":\"Lukas Wojcik\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#\\\/schema\\\/person\\\/895f7604f9b6b71aad9bba33af28d0f9\"},\"headline\":\"Microsoft Advertising Conversions API: Server-Side UET in Practice\",\"datePublished\":\"2026-08-10T05:10:00+00:00\",\"dateModified\":\"2026-10-24T00:15:20+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/digital-marketing\\\/microsoft-advertising-conversions-api-server-side-uet-in-practice\\\/\"},\"wordCount\":1336,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#\\\/schema\\\/person\\\/895f7604f9b6b71aad9bba33af28d0f9\"},\"image\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/digital-marketing\\\/microsoft-advertising-conversions-api-server-side-uet-in-practice\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/09\\\/hero-9355-microsoft-advertising-conversions-ap-g.png\",\"keywords\":[\"Conversion Tracking\",\"Digital Marketing\",\"First-Party Data\",\"Tracking\"],\"articleSection\":[\"Digital Marketing\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/digital-marketing\\\/microsoft-advertising-conversions-api-server-side-uet-in-practice\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/digital-marketing\\\/microsoft-advertising-conversions-api-server-side-uet-in-practice\\\/\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/digital-marketing\\\/microsoft-advertising-conversions-api-server-side-uet-in-practice\\\/\",\"name\":\"Microsoft Advertising Conversions API: Server-Side UET in Practice | Lukas Wojcik\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/digital-marketing\\\/microsoft-advertising-conversions-api-server-side-uet-in-practice\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/digital-marketing\\\/microsoft-advertising-conversions-api-server-side-uet-in-practice\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/09\\\/hero-9355-microsoft-advertising-conversions-ap-g.png\",\"datePublished\":\"2026-08-10T05:10:00+00:00\",\"dateModified\":\"2026-10-24T00:15:20+00:00\",\"description\":\"Microsoft Advertising Conversions API: UET server events, authentication, deduplication, hashing and response validation.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/digital-marketing\\\/microsoft-advertising-conversions-api-server-side-uet-in-practice\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/digital-marketing\\\/microsoft-advertising-conversions-api-server-side-uet-in-practice\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/digital-marketing\\\/microsoft-advertising-conversions-api-server-side-uet-in-practice\\\/#primaryimage\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/09\\\/hero-9355-microsoft-advertising-conversions-ap-g.png\",\"contentUrl\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/09\\\/hero-9355-microsoft-advertising-conversions-ap-g.png\",\"width\":1200,\"height\":630,\"caption\":\"Microsoft Advertising Conversions API: Server-Side UET in Practice\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/digital-marketing\\\/microsoft-advertising-conversions-api-server-side-uet-in-practice\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Microsoft Advertising Conversions API: Server-Side UET in Practice\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/\",\"name\":\"Lukas Wojcik - Blog\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#\\\/schema\\\/person\\\/895f7604f9b6b71aad9bba33af28d0f9\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#\\\/schema\\\/person\\\/895f7604f9b6b71aad9bba33af28d0f9\",\"name\":\"Lukas Wojcik\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\",\"contentUrl\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\",\"width\":424,\"height\":636,\"caption\":\"Lukas Wojcik\"},\"logo\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\"},\"sameAs\":[\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Microsoft Advertising Conversions API: Server-Side UET in Practice | Lukas Wojcik","description":"Microsoft Advertising Conversions API: UET server events, authentication, deduplication, hashing and response validation.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.lukaswojcik.com\/blog\/en\/digital-marketing\/microsoft-advertising-conversions-api-server-side-uet-in-practice\/","og_locale":"en_US","og_type":"article","og_title":"Microsoft Advertising Conversions API: Server-Side UET in Practice | Lukas Wojcik","og_description":"Microsoft Advertising Conversions API: UET server events, authentication, deduplication, hashing and response validation.","og_url":"https:\/\/www.lukaswojcik.com\/blog\/en\/digital-marketing\/microsoft-advertising-conversions-api-server-side-uet-in-practice\/","og_site_name":"Lukas Wojcik - Blog","article_published_time":"2026-08-10T05:10:00+00:00","article_modified_time":"2026-10-24T00:15:20+00:00","og_image":[{"width":1200,"height":630,"url":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/09\/hero-9355-microsoft-advertising-conversions-ap-g.png","type":"image\/png"}],"author":"Lukas Wojcik","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Lukas Wojcik","Est. reading time":"8 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/digital-marketing\/microsoft-advertising-conversions-api-server-side-uet-in-practice\/#article","isPartOf":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/digital-marketing\/microsoft-advertising-conversions-api-server-side-uet-in-practice\/"},"author":{"name":"Lukas Wojcik","@id":"https:\/\/www.lukaswojcik.com\/blog\/#\/schema\/person\/895f7604f9b6b71aad9bba33af28d0f9"},"headline":"Microsoft Advertising Conversions API: Server-Side UET in Practice","datePublished":"2026-08-10T05:10:00+00:00","dateModified":"2026-10-24T00:15:20+00:00","mainEntityOfPage":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/digital-marketing\/microsoft-advertising-conversions-api-server-side-uet-in-practice\/"},"wordCount":1336,"commentCount":0,"publisher":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/#\/schema\/person\/895f7604f9b6b71aad9bba33af28d0f9"},"image":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/digital-marketing\/microsoft-advertising-conversions-api-server-side-uet-in-practice\/#primaryimage"},"thumbnailUrl":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/09\/hero-9355-microsoft-advertising-conversions-ap-g.png","keywords":["Conversion Tracking","Digital Marketing","First-Party Data","Tracking"],"articleSection":["Digital Marketing"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.lukaswojcik.com\/blog\/en\/digital-marketing\/microsoft-advertising-conversions-api-server-side-uet-in-practice\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/digital-marketing\/microsoft-advertising-conversions-api-server-side-uet-in-practice\/","url":"https:\/\/www.lukaswojcik.com\/blog\/en\/digital-marketing\/microsoft-advertising-conversions-api-server-side-uet-in-practice\/","name":"Microsoft Advertising Conversions API: Server-Side UET in Practice | Lukas Wojcik","isPartOf":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/digital-marketing\/microsoft-advertising-conversions-api-server-side-uet-in-practice\/#primaryimage"},"image":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/digital-marketing\/microsoft-advertising-conversions-api-server-side-uet-in-practice\/#primaryimage"},"thumbnailUrl":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/09\/hero-9355-microsoft-advertising-conversions-ap-g.png","datePublished":"2026-08-10T05:10:00+00:00","dateModified":"2026-10-24T00:15:20+00:00","description":"Microsoft Advertising Conversions API: UET server events, authentication, deduplication, hashing and response validation.","breadcrumb":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/digital-marketing\/microsoft-advertising-conversions-api-server-side-uet-in-practice\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.lukaswojcik.com\/blog\/en\/digital-marketing\/microsoft-advertising-conversions-api-server-side-uet-in-practice\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/digital-marketing\/microsoft-advertising-conversions-api-server-side-uet-in-practice\/#primaryimage","url":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/09\/hero-9355-microsoft-advertising-conversions-ap-g.png","contentUrl":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/09\/hero-9355-microsoft-advertising-conversions-ap-g.png","width":1200,"height":630,"caption":"Microsoft Advertising Conversions API: Server-Side UET in Practice"},{"@type":"BreadcrumbList","@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/digital-marketing\/microsoft-advertising-conversions-api-server-side-uet-in-practice\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.lukaswojcik.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Microsoft Advertising Conversions API: Server-Side UET in Practice"}]},{"@type":"WebSite","@id":"https:\/\/www.lukaswojcik.com\/blog\/#website","url":"https:\/\/www.lukaswojcik.com\/blog\/","name":"Lukas Wojcik - Blog","description":"","publisher":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/#\/schema\/person\/895f7604f9b6b71aad9bba33af28d0f9"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.lukaswojcik.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":["Person","Organization"],"@id":"https:\/\/www.lukaswojcik.com\/blog\/#\/schema\/person\/895f7604f9b6b71aad9bba33af28d0f9","name":"Lukas Wojcik","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg","url":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg","contentUrl":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg","width":424,"height":636,"caption":"Lukas Wojcik"},"logo":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg"},"sameAs":["https:\/\/www.lukaswojcik.com\/blog"]}]}},"_links":{"self":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/posts\/9355","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/comments?post=9355"}],"version-history":[{"count":8,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/posts\/9355\/revisions"}],"predecessor-version":[{"id":23141,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/posts\/9355\/revisions\/23141"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/media\/13788"}],"wp:attachment":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/media?parent=9355"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/categories?post=9355"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/tags?post=9355"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}