> ## Documentation Index
> Fetch the complete documentation index at: https://agenticadvertisingorg-snap-format-preview-links.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Trusted Match Protocol

> AdCP's real-time execution layer — follow a cross-publisher frequency capping story from wasted budget to structural privacy, across every surface.

<img src="https://mintcdn.com/agenticadvertisingorg-snap-format-preview-links/lrVO3eb-F0CvWfJE/images/walkthrough/tmp-01-wasted-budget.png?fit=max&auto=format&n=lrVO3eb-F0CvWfJE&q=85&s=46331699f38364d63ebe2a9108060ea5" alt="A viewer sees the same outdoor gear ad on their TV and phone within minutes — a budget meter drains with diminishing returns" style={{ width: '100%', borderRadius: '12px', marginBottom: '2rem' }} width="1376" height="768" data-path="images/walkthrough/tmp-01-wasted-budget.png" />

<Note>
  **Experimental.** TMP is part of AdCP 3.0 as an experimental surface — it may change between 3.x releases with at least 6 weeks' notice. Sellers implementing TMP MUST declare `trusted_match.core` in `experimental_features`. See [experimental status](/docs/reference/experimental-status) for the full contract.
</Note>

Priya is Director of Ad Products at StreamHaus, a CTV publisher. She designed how StreamHaus's inventory looks to buyer agents — product catalogs, creative specs, pricing.

Sam's Acme Outdoor campaign runs on StreamHaus, OutdoorNet, and PodTrail with a frequency policy: **5 impressions per week, minimum 2 hours between exposures**. Sam chose this because spaced exposure outperforms concentrated repetition — the same ad every commercial break produces fatigue, not engagement.

The problem: each publisher counts independently.

## Step 1: The problem — wasted budget

StreamHaus, OutdoorNet, and PodTrail each count independently. A viewer who watches hiking content on StreamHaus after dinner, then browses OutdoorNet on their phone 30 minutes later, gets the same ad again — well inside the 2-hour recency window Sam set.

Multiply across a week and the viewer gets 15 impressions instead of 5, concentrated instead of spaced:

| Publisher  | Impressions counted | Actual viewer experience |
| ---------- | ------------------- | ------------------------ |
| StreamHaus | 5 (within cap)      | Same ad every session    |
| OutdoorNet | 5 (within cap)      | Same ad every session    |
| PodTrail   | 5 (within cap)      | Same ad every session    |
| **Total**  | **15**              | **3x over Sam's cap**    |

Every redundant impression is budget that could have reached someone new. Advertising works better with spacing — each exposure after the first few produces diminishing returns. Sam is buying frequency when he should be buying reach.

This isn't a StreamHaus problem. It's a structural problem. No single publisher can enforce a cross-publisher cap because no single publisher sees the full picture.

## Step 2: Adding the TMP Router

<img src="https://mintcdn.com/agenticadvertisingorg-snap-format-preview-links/lrVO3eb-F0CvWfJE/images/walkthrough/tmp-02-router-setup.png?fit=max&auto=format&n=lrVO3eb-F0CvWfJE&q=85&s=4ccb5153ceacda8f00dc1e7a98f27cb7" alt="Priya at a terminal, deploying a TMP Router — a diagram materializes showing context and identity paths splitting into separate channels" style={{ width: '100%', borderRadius: '12px', marginBottom: '1rem' }} width="1376" height="768" data-path="images/walkthrough/tmp-02-router-setup.png" />

Priya deploys the Trusted Match Protocol (TMP) Router — the piece that sits between her ad server and buyer agents, with structurally separate paths for context and identity. She configures Sam's buyer agent (Pinnacle) as a TMP provider, alongside other buyers.

The router sits between StreamHaus's ad server and the buyer agents. When a user loads a page, the router handles the real-time evaluation. Priya didn't write surface-specific code — the same router handles StreamHaus's website, their mobile app, and their CTV app.

<Accordion title="What Priya configures">
  Priya registers Sam's buyer agent (Pinnacle) as a TMP provider on the router:

  ```json theme={null}
  {
    "providers": [
      {
        "name": "Pinnacle (Acme Outdoor)",
        "endpoint": "https://pinnacle.acme.example/tmp",
        "context_match": true,
        "identity_match": true,
        "properties": ["01J5A2B3C4-streamhaus-web", "01J5A2B3C5-streamhaus-ios"],
        "latency_budget_ms": 50,
        "priority": 1
      }
    ]
  }
  ```

  `context_match: true` means the router sends content context to Pinnacle for targeting. `identity_match: true` means it also sends opaque user tokens so Pinnacle can enforce frequency caps and audience eligibility. `properties` scopes which StreamHaus properties this provider serves — Pinnacle evaluates web and iOS, not CTV. `latency_budget_ms` sets a per-provider timeout; if Pinnacle consistently exceeds it, the router deprioritizes it.

  The router fans out to all configured providers in parallel and merges their responses.
</Accordion>

## Step 3: Context Match — what's on the page?

<img src="https://mintcdn.com/agenticadvertisingorg-snap-format-preview-links/lrVO3eb-F0CvWfJE/images/walkthrough/tmp-03-context-match.png?fit=max&auto=format&n=lrVO3eb-F0CvWfJE&q=85&s=c6c398f50a301e904acb267894ae42af" alt="A StreamHaus article about hiking gear with content signals radiating outward — Sam's buyer agent responds with a package offer and creative manifest" style={{ width: '100%', borderRadius: '12px', marginBottom: '1rem' }} width="1376" height="768" data-path="images/walkthrough/tmp-03-context-match.png" />

A viewer opens a StreamHaus article about hiking gear. StreamHaus's properties are registered in the [property governance](/docs/governance/property) with stable `property_rid` identifiers, so the buyer knows exactly which property this request came from. StreamHaus sends a **Context Match** request with the article's content signals, placement, and geo.

Sam's buyer agent evaluates: "This hiking content matches `pkg-outdoor-display`." It responds with an offer that includes a creative manifest — the Trail Pro 3000 banner.

The key constraint: **no user identity crosses this boundary.** The buyer evaluates content, not people. It doesn't know who is reading the article — only what the article is about.

<Accordion title="Context Match request and response">
  Request from StreamHaus to Sam's buyer agent:

  ```json theme={null}
  {
    "type": "context_match_request",
    "request_id": "ctx-8f3a2b",
    "property_rid": "01916f3a-9c4e-7000-8000-000000000010",
    "property_type": "website",
    "placement_id": "article-sidebar",
    "seller_agent_url": "https://streamhaus.example",
    "artifact_refs": [
      { "type": "url", "value": "https://streamhaus.example/articles/hiking-gear-2026" }
    ],
    "context_signals": {
      "topics": ["596"],
      "taxonomy_source": "iab",
      "taxonomy_id": 7,
      "keywords": ["hiking gear", "outdoor equipment"]
    }
  }
  ```

  The publisher sends both `artifact_refs` (for buyers that crawl content directly) and `context_signals` (pre-classified topics and keywords as a fallback). The buyer agent already knows which packages are active for this placement — it set them up via `create_media_buy`. No package list needs to travel on the wire.

  Response from Sam's buyer agent:

  ```json theme={null}
  {
    "type": "context_match_response",
    "request_id": "ctx-8f3a2b",
    "offers": [
      {
        "package_id": "pkg-outdoor-display"
      }
    ]
  }
  ```
</Accordion>

## Step 4: Identity Match — is this user eligible?

<img src="https://mintcdn.com/agenticadvertisingorg-snap-format-preview-links/lrVO3eb-F0CvWfJE/images/walkthrough/tmp-04-identity-match.png?fit=max&auto=format&n=lrVO3eb-F0CvWfJE&q=85&s=aef9c2e3423bfee3b8a03f2ba605359b" alt="An opaque user token with package IDs flows to Sam's buyer agent — a timeline shows last exposure 45 minutes ago, recency window 2 hours, verdict: not eligible" style={{ width: '100%', borderRadius: '12px', marginBottom: '1rem' }} width="1376" height="768" data-path="images/walkthrough/tmp-04-identity-match.png" />

Separately, StreamHaus sends an **Identity Match** request: an opaque user token and ALL of Sam's active package IDs across every publisher.

Sam's buyer agent checks its exposure history: "This user saw 1 impression 45 minutes ago on OutdoorNet. The 2-hour recency window hasn't elapsed. **Not eligible.**"

The key constraint: **no page context crosses this boundary.** The buyer checks eligibility, not content fit. It doesn't know what the user is looking at — only whether this user should see more ads right now.

The recency check crosses publisher boundaries because Sam's buyer agent maintains a shared exposure store. StreamHaus, OutdoorNet, and PodTrail all send Identity Match requests to the same buyer agent — so it knows the user's total exposure across all three.

<Accordion title="Identity Match request and response">
  Request from StreamHaus to Sam's buyer agent:

  ```json theme={null}
  {
    "type": "identity_match_request",
    "request_id": "id-7c9e1d",
    "seller_agent_url": "https://streamhaus.example",
    "identities": [
      { "user_token": "opaque-streamhaus-token-abc123", "uid_type": "uid2" },
      { "user_token": "ID5*zP3wK...", "uid_type": "id5" }
    ],
    "package_ids": [
      "pkg-outdoor-display",
      "pkg-outdoor-ctv",
      "pkg-outdoor-audio"
    ]
  }
  ```

  Response from Sam's buyer agent:

  ```json theme={null}
  {
    "type": "identity_match_response",
    "request_id": "id-7c9e1d",
    "eligible_package_ids": ["pkg-outdoor-audio"],
    "serve_window_sec": 60
  }
  ```

  Only eligible packages are listed — `pkg-outdoor-audio` passes the buyer's checks. The `serve_window_sec: 60` tells the router to cache this eligibility for 60 seconds.

  The example sends `package_ids` explicitly, but the publisher MAY omit it — Sam's identity-match service resolves the active package set from `seller_agent_url`. When `package_ids` IS sent, its composition MUST be independent of the current page — either all-active (every Sam package at StreamHaus) or fuzzed (a random sample padded with synthetic IDs that Sam will silently drop). A page-specific subset is forbidden; it would let the buyer correlate package sets across Context Match and Identity Match, breaking the structural separation.
</Accordion>

## Step 5: The join — StreamHaus makes the decision

<img src="https://mintcdn.com/agenticadvertisingorg-snap-format-preview-links/lrVO3eb-F0CvWfJE/images/walkthrough/tmp-05-publisher-join.png?fit=max&auto=format&n=lrVO3eb-F0CvWfJE&q=85&s=bd7acfe2f095f97739c92eef04490b13" alt="Two response cards merge at StreamHaus — the Trail Pro ad fades while a different advertiser's ad activates in its place" style={{ width: '100%', borderRadius: '12px', marginBottom: '1rem' }} width="1376" height="768" data-path="images/walkthrough/tmp-05-publisher-join.png" />

StreamHaus joins both responses locally:

* **Context Match** said: "Activate `pkg-outdoor-display` with this creative manifest."
* **Identity Match** said: "Not eligible — recency window."

Result: **suppress the ad.** A different advertiser's campaign fills the slot. Sam's budget is preserved for a better moment — one where the viewer hasn't seen the ad recently and the impression will actually matter.

The buyer never saw user identity and page context together. Privacy isn't a policy that could be violated — it's structural. The two paths never share data, and the publisher (who already has both signals) makes the final decision.

## Step 6: Three winners

<img src="https://mintcdn.com/agenticadvertisingorg-snap-format-preview-links/lrVO3eb-F0CvWfJE/images/walkthrough/tmp-06-three-winners.png?fit=max&auto=format&n=lrVO3eb-F0CvWfJE&q=85&s=8aa285d742697c6d93e2fd6fdfda0ab8" alt="Three panels: a viewer relaxing with varied ads across devices, Sam's dashboard showing increased unique reach, Priya seeing rising buyer satisfaction metrics" style={{ width: '100%', borderRadius: '12px', marginBottom: '1rem' }} width="1376" height="768" data-path="images/walkthrough/tmp-06-three-winners.png" />

**The viewer** had a normal evening across three platforms. They saw the Trail Pro ad during hiking content on StreamHaus — relevant, well-timed. When they browsed OutdoorNet 30 minutes later, a different ad appeared. No sense of being followed across the internet.

**Sam** got spaced exposure instead of concentrated repetition. His 5 weekly impressions land across different contexts and moments, each one more effective than the 6th or 7th impression would have been. And the budget freed by suppression reaches viewers who haven't seen the ad yet — more unique reach for the same spend.

**Priya** differentiated StreamHaus. Buyers prefer publishers that support TMP because their frequency policies actually work. StreamHaus's inventory is more valuable per impression because buyers know they're not wasting budget on over-exposed viewers.

| Before TMP                          | With TMP                                             |
| ----------------------------------- | ---------------------------------------------------- |
| Each publisher counts independently | Buyer agent tracks exposure across all publishers    |
| 15 impressions per viewer per week  | 5 impressions per viewer per week, properly spaced   |
| Budget buys frequency               | Budget buys reach                                    |
| Concentrated repetition, ad fatigue | Spaced exposure, higher effectiveness per impression |
| Publishers compete on volume        | Publishers compete on quality and buyer experience   |

## Step 7: Same protocol, every surface

<img src="https://mintcdn.com/agenticadvertisingorg-snap-format-preview-links/lrVO3eb-F0CvWfJE/images/walkthrough/tmp-07-every-surface.png?fit=max&auto=format&n=lrVO3eb-F0CvWfJE&q=85&s=c760ca08e0ace6b77ae478c7e1e61b18" alt="Five surface icons — web, mobile, CTV, retail media, AI assistant — connected to a single TMP Router hub, all in teal" style={{ width: '100%', borderRadius: '12px', marginBottom: '1rem' }} width="1376" height="768" data-path="images/walkthrough/tmp-07-every-surface.png" />

The same TMP Router handles StreamHaus's website, their mobile app, their CTV app, and their AI assistant. Sam's buyer agent works across all of them without surface-specific logic. The protocol handles the surface differences. Priya and Sam handle the business.

## Go deeper

<CardGroup cols={2}>
  <Card title="AI assistant mediation" icon="robot" href="/docs/trusted-match/ai-mediation">
    A mediation protocol for AI assistants — how demand finds conversational AI when the context can't be broadcast.
  </Card>

  <Card title="The execution gap" icon="puzzle-piece" href="/docs/trusted-match/execution-gap">
    Why existing protocols fail at serve time and why TMP takes a matching approach instead of an auction approach.
  </Card>

  <Card title="Context and identity" icon="arrows-split-up-and-left" href="/docs/trusted-match/context-and-identity">
    Both operations with concrete examples, including catalog refinement and the publisher-side join.
  </Card>

  <Card title="Specification" icon="scroll" href="/docs/trusted-match/specification">
    Authoritative message types, field tables, and conformance requirements.
  </Card>

  <Card title="Privacy architecture" icon="shield-halved" href="/docs/trusted-match/privacy-architecture">
    Structural separation, temporal decorrelation, and TEE attestation.
  </Card>

  <Card title="Data protection roles" icon="scale-balanced" href="/docs/trusted-match/data-protection-roles">
    Controller vs. processor analysis for each TMP participant.
  </Card>

  <Card title="Router architecture" icon="diagram-project" href="/docs/trusted-match/router-architecture">
    Deployment, fan-out, and provider configuration.
  </Card>
</CardGroup>

### Surface guides

<CardGroup cols={3}>
  <Card title="Web" icon="globe" href="/docs/trusted-match/surfaces/web" />

  <Card title="AI assistants" icon="robot" href="/docs/trusted-match/surfaces/ai-assistants" />

  <Card title="Mobile" icon="mobile" href="/docs/trusted-match/surfaces/mobile" />

  <Card title="Retail media" icon="store" href="/docs/trusted-match/surfaces/retail-media" />

  <Card title="CTV" icon="tv" href="/docs/trusted-match/surfaces/ctv" />
</CardGroup>
