Skip to main content

Trusted Match Protocol Specification

This is the authoritative reference for the Trusted Match Protocol (TMP). For conceptual introductions, see the overview and core concepts.

Definitions

TermDefinition
Context MatchTMP operation that evaluates available packages against content context. Carries no user identity.
Identity MatchTMP operation that evaluates user eligibility against package criteria. Carries no page context.
TMP RouterInfrastructure that fans out TMP requests to buyer agents and merges responses. A single binary that handles both context and identity requests, with structurally separate code paths.
OfferA buyer’s response to a context match request. Ranges from simple activation (package_id only) to rich proposals with brand, price, summary, and creative manifest.
Available packageA package from an active media buy that is eligible for evaluation on a given placement. Package metadata is synced at media buy time.
EligibilityList of eligible package IDs returned by Identity Match, plus a TTL caching contract. The buyer computes eligibility from frequency caps, audience membership, and other signals; the reasons are opaque to the publisher.
ArtifactA typed content reference associated with a publisher property (article URL, episode EIDR, show Gracenote ID, music ISRC, product GTIN, conversation turn). Each artifact has a type and value. Referenced in context match requests.
Temporal decorrelationRandom delay introduced between Context Match and Identity Match requests to prevent timing-based correlation.

Message Types

All TMP message types include a type field that identifies the message for deserialization. This allows routers and agents to deserialize without inspecting URL path or content structure.
Messagetype value
Context Match requestcontext_match_request
Context Match responsecontext_match_response
Identity Match requestidentity_match_request
Identity Match responseidentity_match_response
Error responseerror

ContextMatchRequest

Sent by the publisher (via router) to buyer agents. Contains content context. MUST NOT contain user identity.
FieldTypeRequiredDescription
typestringYes"context_match_request". Message type discriminator for dispatch.
protocol_versionstringNoTMP protocol version. Default: 1.0. Allows receivers to handle semantic differences across versions.
request_idstringYesUnique request identifier for logging. MUST NOT correlate with any Identity Match request_id.
property_ridUUIDYesProperty catalog UUID (v7). Globally unique, stable.
property_idstringNoPublisher’s human-readable slug. Optional when property_rid is present.
property_typeenumYesOne of: website, mobile_app, ctv_app, desktop_app, dooh, podcast, radio, streaming_audio, ai_assistant. See property-type enum.
placement_idstringYesPlacement identifier from the publisher’s placement registry in adagents.json. One placement per request.
artifactArtifactNoFull content artifact adjacent to this ad opportunity. Same schema as content standards evaluation. The publisher sends the full artifact when they want the buyer to evaluate the actual content. Contractual protections govern buyer use. TEE deployment upgrades contractual trust to cryptographic verification.
artifact_refsList<ArtifactRef>NoPublic content references the buyer can resolve independently. Each has a type (one of: url, url_hash, eidr, gracenote, isrc, gtin, rss_guid, isbn, custom) and a value. For URL-addressable content, the buyer may have pre-classified these. Use url_hash when the publisher prefers not to reveal the URL (contextual clean room).
context_signalsContextSignalsNoPre-computed classifier outputs for the content environment. Use when content is ephemeral (conversation turns, search queries) or to supplement artifact-based matching. Can replace artifact_refs entirely. Raw content MUST NOT be included — only classified outputs. The publisher is the classifier boundary.
geoGeoNoCoarse geographic location of the viewer. Publisher controls granularity — country for regulatory compliance, region/metro for campaign targeting and valuation. No postcode or coordinates — coarsened to prevent user identification.
package_idsList<string>NoRestrict evaluation to specific packages. When omitted, the provider evaluates all eligible packages for this placement (the common case). Package metadata (formats, catalogs) is synced at media buy time — not sent per request.

ContextSignals

Pre-computed classifier outputs for the content environment. MUST NOT contain raw content (conversation text, article body, URLs). Only classified outputs. The publisher is the classifier boundary.
FieldTypeRequiredDescription
topicsList<string>NoContent topic identifiers. Use IAB Content Taxonomy 3.0 IDs when taxonomy_id is 7 (default), or human-readable strings for custom taxonomies.
taxonomy_sourceenumNoOrganization that defines the topic taxonomy. Default: iab.
taxonomy_idintegerNoTaxonomy version within the source. For IAB, follows the AdCOM cattax enum: 7 = Content Taxonomy 3.0 (CC-BY-3.0). Default: 7.
sentimentenumNoContent sentiment: positive, negative, neutral, mixed.
keywordsList<string>NoContent keywords extracted by the publisher’s classifier.
languagestringNoISO 639-1 language code.
content_policiesList<string>NoPolicy IDs from the AdCP Policy Registry that this content satisfies. Routers populate this from the publisher’s property governance configuration or content metadata. Buyers filter on policies they require via required_policies on packages. This is a pre-filtering optimization — contexts missing required policies are excluded before reaching downstream governance. Definitive enforcement happens at the governance layer via check_governance.
summarystringNoNatural language summary for relevance judgment. Useful for LLM-native buyers that evaluate semantically.
embeddingstringNoContent embedding as base64-encoded int8 vector. Captures semantic content beyond topics and keywords.
embedding_modelstringNoEmbedding model identifier (e.g., nomic-embed-text-v1.5). Required when embedding is present.
embedding_dimsintegerNoNumber of dimensions in the embedding vector. Required when embedding is present.
Three levels of content disclosure — the publisher chooses based on what the buyer needs and what the publisher is comfortable sharing:
  • artifact — the full content (article body, transcript, conversation flow, product page). Same schema as content standards artifacts. The buyer evaluates the content directly. Contractual protections govern what the buyer can do with it. TEE deployment adds cryptographic verification on top.
  • artifact_refs — public references (URLs, EIDR IDs, URL hashes) the buyer resolves independently. Use for publicly addressable content the buyer can crawl and classify themselves.
  • context_signals — classified outputs (topics, sentiment, keywords, summary). Use when the publisher wants to describe the content without sharing it or a reference to it.
context_signals is the baseline — every buyer agent MUST handle it. artifact_refs and artifact are progressive enhancements. Publishers who send artifact_refs SHOULD also send context_signals as a fallback for buyers who cannot resolve references. LLM-based buyer agents SHOULD evaluate context_signals.summary and context_signals.topics first. These fields provide sufficient signal for most relevance decisions at minimal token cost (~30 tokens). Full content resolution from artifact_refs or artifact evaluation SHOULD be reserved for high-value packages where precision justifies the cost. Buyers MUST treat artifact content and context_signals.summary as untrusted publisher-generated input. A request can include any combination. A news site sends artifact_refs (the URL) and context_signals (pre-classified topics). A CTV app sends artifact_refs (EIDR IDs) alone. An AI assistant sends artifact (the conversation) for buyers that evaluate content directly, plus context_signals as a fallback. A publisher who doesn’t want to share content or references sends only context_signals.

Artifact Ref Type Conventions

Buyers parse artifact_refs strings by pattern. The following conventions are normative:
TypePatternExample
URLStarts with https://https://oakwood.example/articles/sustainable-kitchen
URL hash44-char base64 (Blake3)k7Xp9mQ2vL8nR3wY5tB1aH6jK0pZ4xC9dF2eG7iMqw==
EIDRStarts with eidr:eidr:10.5240/XXXX-XXXX-XXXX-XXXX-XXXX-C
Gracenote TMSStarts with tms:tms:SH012345670000
RSS + GUIDStarts with rss:rss:https://feed.example/rss+guid:ep-2026-03-15
GTIN8-14 digit numeric00012345600012
Buyers SHOULD ignore ref types they do not support rather than failing the request.

Artifact

A typed content reference. Each artifact identifies a piece of content using a standard or custom identifier scheme.
FieldTypeRequiredDescription
typeenumYesOne of: url, url_hash, eidr, gracenote, isrc, gtin, rss_guid, isbn, custom.
valuestringYesThe identifier value. For url: canonical content URL (MUST NOT contain user-specific paths or query params; use url_hash to avoid revealing URLs). For url_hash: base64-encoded Blake3 hash (canonicalization: strip scheme, strip www./m./amp. prefixes, lowercase, strip trailing slash, strip query params and fragments). For eidr: EIDR DOI (e.g., 10.5240/xxxx). For gracenote: Gracenote TMS ID (e.g., SH032541890000). For isrc: ISRC code (e.g., USRC17607839). For gtin: GTIN (e.g., 00012345678905). For rss_guid: episode GUID from RSS feed. For isbn: ISBN (e.g., 978-0-123456-78-9). For custom: publisher-defined string.

Geo

Geographic context for the impression opportunity. Publisher controls granularity.
FieldTypeRequiredDescription
countrystringNoISO 3166-1 alpha-2 country code (e.g., US, GB).
regionstringNoISO 3166-2 subdivision code (e.g., US-CA, GB-SCT).
metroMetroNoMetro area using AdCP’s metro classification systems.

ContextMatchResponse

Returned by the buyer agent. Contains offers for matched packages and optional response-level targeting signals.
FieldTypeRequiredDescription
typestringYes"context_match_response". Message type discriminator.
request_idstringYesEcho of the request’s request_id.
offersList<Offer>YesOffers from the buyer, one per activated package. Empty list means no packages matched.
signalsSignalsNoResponse-level targeting signals for ad server pass-through. Not per-offer — applies to the response as a whole. In the GAM case, these carry the key-value pairs that trigger line items.

Offer

A buyer’s response for a single package.
FieldTypeRequiredDescription
package_idstringYesPackage identifier from the media buy.
brandBrandRefNoBrand for this offer. Required when the product allows dynamic brands. For single-brand packages, already known from the media buy.
priceOfferPriceNoVariable price for this offer. Only present when the product supports variable pricing.
summarystringNoBuyer-generated description of the offer for the publisher to judge relevance. E.g., “50% off Goldenfield mayo — recipe integration”.
creative_manifestCreativeManifestNoFull creative details, inline. When present, the publisher has everything needed to render. For large creatives (VAST, video), the manifest references external assets via URLs.
macrosMap<string, string>NoKey-value pairs for dynamic creative rendering or attribution tracking. In the GAM case, these flow as macro values. Attribution reconciliation happens via delivery reporting or clean room.

OfferPrice

FieldTypeRequiredDescription
amountnumberYesPrice amount in the specified currency.
currencystringNoISO 4217 currency code. Default: USD.
modelenumYesOne of: cpm, cpc, cpcv, cpa, flat.

Signals

Response-level targeting signals for ad server pass-through.
FieldTypeRequiredDescription
segmentsList<string>NoAudience or contextual segment IDs.
targeting_kvsList<KeyValuePair>NoKey-value pairs for ad server targeting.

KeyValuePair

FieldTypeRequiredDescription
keystringYesTargeting key.
valuestringYesTargeting value.

IdentityMatchRequest

Sent by the publisher (via router) to buyer agents. Contains an opaque user token and package IDs. MUST NOT contain page context.
FieldTypeRequiredDescription
typestringYes"identity_match_request". Message type discriminator for dispatch.
protocol_versionstringNoTMP protocol version. Default: 1.0.
request_idstringYesUnique request identifier. MUST NOT correlate with any Context Match request_id.
user_tokenstringYesOpaque token from an identity provider (ID5, LiveRamp, UID2) or publisher-generated. Buyer may map to internal identity graph but cannot reverse to PII.
uid_typeenumYesType of user identifier: uid2, rampid, id5, euid, pairid, maid, hashed_email, publisher_first_party, other. Tells the buyer which identity graph to resolve against. Required for signature verification. See uid-type enum.
consentConsentNoPrivacy consent signals. Buyers in regulated jurisdictions MUST NOT process the user token without consent information.
package_idsList<string>YesALL active packages for this buyer at this publisher. MUST include every active package, not just those on the current page, to prevent set-correlation with Context Match.

IdentityMatchResponse

Returned by the buyer agent. A list of eligible package IDs with a caching TTL.
FieldTypeRequiredDescription
typestringYes"identity_match_response". Message type discriminator.
request_idstringYesEcho of the request’s request_id.
eligible_package_idsList<string>YesPackage IDs the user is eligible for. Packages not listed are ineligible.
ttl_secintegerYesHow long the router should cache this response, in seconds. A value of 0 means do not cache — re-query on every request.
The response is a flat list of eligible package IDs and a TTL. The buyer computes eligibility from whatever identity signals they have (frequency caps, audience membership, purchase history) and returns only the packages that pass. The publisher does not need to know why a package was excluded — just which packages are eligible. The ttl_sec field is a caching contract. The buyer is saying: “Cache this for N seconds.” The router caches the eligible_package_ids list and returns it for subsequent requests during the window — it does not track which packages have been served. The publisher enforces allocation rules (at most one ad per package, competitive separation, pod composition) using the cached eligibility as input. This eliminates the need for pod-specific or batch-specific protocol semantics — the router has cached eligibility and the publisher allocates across whatever placements exist during the TTL window (a CTV ad pod, a web page with 20 slots, a single pre-roll). The buyer doesn’t need to know the allocation details. Privacy consent signals for the identity match. Publishers MUST include consent information when operating in regulated jurisdictions (EU/EEA, California, etc.). Buyers MUST NOT process user tokens without consent information when required by applicable law.
FieldTypeRequiredDescription
gdprboolNoWhether GDPR applies to this request.
tcf_consentstringNoIAB TCF v2.2 consent string. Present when gdpr is true.
gppstringNoIAB Global Privacy Platform string.
us_privacystringNoUS Privacy string (CCPA). Deprecated in favor of GPP but still widely used.

Error Response

Returned by a provider or router when a request cannot be processed. Distinct from an empty result — an empty offers array or empty eligible_package_ids list is a valid response meaning no matches, not an error.
FieldTypeRequiredDescription
typestringYes"error". Message type discriminator.
request_idstringYesEcho of the original request’s request_id.
codeenumYesMachine-readable error code: invalid_request, unknown_package, rate_limited, timeout, internal_error, provider_unavailable.
messagestringNoHuman-readable error description for debugging.
The router SHOULD exclude providers that return errors from the merged response for that request. The router MAY track error rates per provider and preemptively skip providers with sustained errors.

Provider Registration

TMP providers are registered with the router via publisher configuration. The publisher specifies which providers the router should call, along with each provider’s endpoint and supported capabilities. This is an operational relationship — the publisher trusts the provider to run code in their ad decisioning path.
SettingTypeRequiredDescription
context_matchboolYesProvider supports Context Match requests.
identity_matchboolNoProvider supports Identity Match requests. Default: false.
Providers MAY support any combination of context_match and identity_match. A provider that supports only context_match is a pure enrichment or contextual targeting provider. A provider that supports only identity_match is a frequency capping provider — the publisher evaluates context locally from the media buy’s targeting rules and calls the buyer only for identity checks.

Product Integration

Publishers declare TMP support on their products via the trusted_match field. Buyers see this on get_products and know what TMP capabilities are available.
FieldTypeRequiredDescription
context_matchboolYesProduct supports Context Match requests.
identity_matchboolNoProduct supports Identity Match requests. Default: false.
response_typesList<string>NoWhat the publisher can accept back: activation (default), catalog_items, creative, deal.
dynamic_brandsboolNoWhether the buyer can select a brand at match time. When false (default), brand must be on the media buy. When true, the buyer’s offer can include any brand — the publisher applies approval rules at match time. Enables multi-brand agreements.
providersList<ProviderEntry>NoTMP providers integrated with this product’s inventory. Each entry identifies a provider by agent_url (from the registry) and declares what match types it supports. The product-level context_match and identity_match booleans declare overall support; per-provider booleans declare which provider handles each. Enables buyer discovery.

ProviderEntry

FieldTypeRequiredDescription
agent_urlstring (URI)YesProvider’s agent URL from the registry. Canonical identifier for this TMP provider.
context_matchboolNoWhether this provider handles context match for this product. Default: false.
identity_matchboolNoWhether this provider handles identity match for this product. Default: false.

Privacy Requirements

The following requirements use RFC 2119 keywords (MUST, SHOULD, MAY).

Structural separation

  • Context Match requests MUST NOT contain user identity data (user tokens, device IDs, IP addresses, session tokens, or any data that could identify a specific user).
  • Identity Match requests MUST NOT contain page context data (URLs, content hashes, topic IDs, content signals, or any data that could identify what the user is viewing).
  • The TMP Router MUST process Context Match and Identity Match in structurally separate code paths with no shared state.
  • Context Match and Identity Match request IDs MUST NOT be correlated or derivable from each other.

Package set decorrelation

  • Context Match MUST NOT be filtered by user identity or audience. The provider evaluates its synced package set for the placement — the same packages for every user. No per-request package list is sent, so the publisher cannot accidentally leak identity through package filtering.
  • Identity Match package_ids MUST include ALL active packages for the buyer at this publisher, not just those available on the current page. Sending only the page-specific subset would allow a buyer to correlate Identity Match with Context Match by comparing package sets.
  • The publisher SHOULD maintain a cached list of all active package IDs per buyer and send the full set on every Identity Match request.
  • The publisher performs the intersection of context match offers and identity match eligibility locally, after both responses arrive.

Temporal decorrelation

  • Publishers SHOULD introduce a random delay between Context Match and Identity Match requests. Recommended: 100-2000ms, uniformly distributed.
  • Publishers MAY batch Identity Match requests across multiple page views.
  • Publishers MAY route Context Match and Identity Match through different network paths.

TEE attestation

  • The TMP Router SHOULD provide TEE attestation when available, proving the deployed binary matches the published source.
  • Attestation documents SHOULD be available on request to publishers and auditors.
  • Attestation SHOULD include measurements confirming service code integrity and isolation.
  • When consent is omitted from an Identity Match request, buyers MUST treat this as “consent status unknown” rather than “consent not required.”
  • Buyers in jurisdictions where consent is required MUST reject Identity Match requests that omit consent, not assume consent.

User token requirements

  • User tokens MUST be opaque to buyer agents. Tokens may originate from identity providers (ID5, LiveRamp, UID2) or be publisher-generated.
  • User tokens MUST NOT contain PII or be reversible to PII by the buyer agent.

Request Authentication

TMP requests carry a signature to prove the request originated from an authorized router. This prevents unauthorized parties from sending forged requests to providers to probe targeting logic, extract sponsored content, or manipulate frequency state.

Signing model

The router signs all requests using Ed25519. Both Context Match and Identity Match requests are signed, but with different signed fields reflecting their different contents and caching characteristics. The daily epoch provides replay protection — a captured signature is valid for at most ~48 hours (current + previous epoch accepted by verifiers).

Signature envelope

The signature is transmitted via HTTP headers alongside the JSON body.
HeaderValue
X-AdCP-SignatureBase64-encoded (URL-safe, no padding) Ed25519 signature
X-AdCP-Key-IdKey identifier from the agent’s agent-signing-key.json

Context Match signed fields

Concatenated in this order, UTF-8, newline-separated:
FieldSource
typecontext_match_request
property_ridFrom the request body
placement_idFrom the request body
package_idsSorted, comma-separated list of active package IDs
daily_epochfloor(unix_timestamp / 86400)
When package_ids is absent from the request, the signature MUST use an empty string for that field in the signed payload. Because the signed fields are static per placement, the same signature can be cached and reused for all requests to the same placement within a 24-hour epoch.

Identity Match signed fields

Concatenated in this order, UTF-8, newline-separated:
FieldSource
typeidentity_match_request
request_idFrom the request body
user_tokenFrom the request body
uid_typeFrom the request body
consent.gdprFrom the request body (false if absent)
consent.tcf_consentFrom the request body (empty string if absent)
package_idsSorted, comma-separated list of active package IDs
daily_epochfloor(unix_timestamp / 86400)
Identity Match signatures include request_id and user_token, so they are unique per request and cannot be cached. This is intentional — Identity Match responses affect buyer-side frequency state and must be idempotent. Buyers MUST deduplicate Identity Match requests by request_id within the daily epoch window. A repeated request_id MUST return the same response without updating frequency state.

Signature verification

The router MUST authenticate incoming requests from the publisher before signing and fanning out. The mechanism for publisher-to-router authentication is deployment-specific (mTLS, API key, etc.) and outside the scope of TMP signing, but MUST be enforced. This prevents a compromised publisher-side component from laundering unauthenticated requests through the router’s signature. The router signs requests before fanning out. Providers verify signatures using the publisher’s public key, obtained from the property registry. This proves the request originated from an authorized router — not a third party probing the provider’s targeting logic. Providers SHOULD sample-verify rather than verify every request — Ed25519 verification adds ~30μs per request, which is small compared to the full pipeline but adds up at volume. A 5% sample rate detects fraudulent publishers within seconds while adding negligible overhead. On verification failure, the provider SHOULD suppress the property for a configurable period (recommended: 24 hours) and alert operations.

Key rotation

Agents publish new signing keys via agent-signing-key.json at their well-known agent URL. Routers SHOULD cache keys with a 5-minute TTL. When a signature fails verification, the router SHOULD re-fetch the key before rejecting — the agent may have rotated.

Key distribution

Publisher public keys are distributed via the property registry. Each property record includes the publisher’s Ed25519 public key. Providers download the registry at startup and keep it current via incremental sync.

Wire Format

Content type: application/json All TMP messages use JSON encoding. Field names and types follow the JSON Schema definitions in this specification. Implementations MUST support JSON. TMP messages are small (200-600 bytes per request/response). At these sizes, serialization format is less than 1% of total latency — the protocol’s performance comes from smaller messages and structural separation, not encoding efficiency. JSON is universal, debuggable, and supported by every language and tool.

Transport

  • JSON over HTTP/2 POST. All implementations MUST use this transport.
  • The router calls each provider’s configured endpoint URL.
  • The request type is distinguished by a type field in the message, not by URL path.
  • Connections SHOULD be reused via HTTP/2 multiplexing.
  • The router SHOULD maintain a connection pool to each buyer agent.
  • The adcp-go SDK provides the reference client and server implementation. Conformance tests validate compatibility — implementations in other languages MUST pass the same test suite.

HTTP Status Codes

TMP uses HTTP status codes for transport-level errors only. Application-level results (including TMP error responses) are always returned with HTTP 200:
HTTP StatusMeaning
200Request processed. Body contains the TMP response (success, empty result, or TMP error).
400Malformed request (invalid JSON, missing type field). Not a TMP response — no body to parse.
503Provider temporarily unavailable. The router should retry or skip.
This means a 200 with an empty offers array is a valid “no matches” response, and a 200 with a TMP error body ("type": "error") is a valid application error. The router handles one response format regardless of outcome.

Latency

  • TMP targets sub-50ms end-to-end latency (publisher → router → agents → router → publisher).
  • The router SHOULD apply adaptive per-agent timeouts based on observed latency percentiles.
  • Agents that exceed the timeout are excluded from the merged response for that request.
  • The router MAY preemptively skip agents whose p95 latency consistently exceeds the budget.

Caching

Context Match responses are cacheable because the same packages are evaluated for every user on a given placement. The recommended cache key is {property_rid, placement_id, provider_id}.
  • Routers SHOULD cache Context Match responses with a TTL of 5 minutes.
  • Providers MAY include a cache_ttl field (integer, seconds) in Context Match responses to override the default. Routers MUST respect this value when present.
  • Identity Match responses are cached per the ttl_sec value in the response. Cache key: {user_token, provider_id, hash(package_ids)}. Including the package list hash ensures cached responses are invalidated when the active package set changes (e.g., a new media buy activates). The router returns cached eligibility for subsequent requests during the window. The publisher enforces allocation rules (one ad per package, competitive separation, pod composition) using the cached eligibility as input.
  • When a provider’s targeting configuration changes (new packages, updated targeting rules), the provider SHOULD return "cache_ttl": 0 until the change has propagated, then resume normal caching.
  • Both ttl_sec and cache_ttl have a schema-enforced maximum of 86400 seconds (24 hours). Routers SHOULD clamp buyer-provided values to a configured maximum (recommended: 3600 seconds) to limit the blast radius of stale caches.

Conformance Levels

TMP Buyer Agent (Basic)

  • Supports context_match capability
  • Responds to ContextMatchRequest with valid ContextMatchResponse
  • Meets latency budget (p95 < 30ms for agent-side processing)
  • Respects privacy constraints (does not log or correlate requests with identity data from other sources)

TMP Buyer Agent (Full)

All of Basic, plus:
  • Supports identity_match capability
  • Responds to IdentityMatchRequest with valid IdentityMatchResponse (eligible package IDs + TTL)
  • Supports rich offers (brand, price, summary, creative manifest) when the product declares matching response_types

TMP Router (Basic)

  • Configured with provider endpoints
  • Fans out Context Match and Identity Match to authorized providers
  • Merges responses
  • Meets end-to-end latency budget (p95 < 50ms)

TMP Router (Trusted)

All of Basic, plus:
  • Runs in a TEE-attested environment (e.g., AWS Nitro Enclaves)
  • Provides attestation documents on request, proving the deployed binary matches the published source
  • Structural separation between context and identity code paths is verifiable via attestation measurements