TMP for Buyer Agents
As a buyer agent, you receive Context Match and Identity Match requests from TMP Routers and respond with offers and eligibility decisions. You never send requests — publishers initiate every interaction through their router.What You Build
A buyer agent exposes two HTTP/2 endpoints under a single base URL —POST /context for Context Match and POST /identity for Identity Match. The router dispatches by path:
| Message type | Receives | Returns |
|---|---|---|
context_match_request | Page/content signals, placement, geo | Offers with creative manifests |
identity_match_request | Seller agent URL, identity tokens, optional package ID list | Eligible package IDs + serve_window_sec |
Prerequisites
Before TMP requests arrive, your packages must exist. A media buy contains one or more packages — TMP operates at the package level.- Create media buys via
create_media_buywith the publisher’s sales agent - Sync creatives via
sync_creativesso the publisher has your creative assets - Register as a TMP provider so the publisher’s router knows your endpoints
Responding to Context Match
The router sends you page context. You evaluate your active packages against that context and return offers for packages that match.- Look up your active packages for this
property_ridandplacement_id - Evaluate each package’s targeting against the context signals, geo, and artifact refs
- Return offers for packages that match, each with a creative manifest
Responding to Identity Match
The router sends you the seller’sseller_agent_url and one or more identity tokens. Use seller_agent_url to look up the active package set you have registered for that seller, resolve identities on whichever tokens you support, then check each package’s eligibility rules against the resolved user. The publisher MAY also send package_ids to scope evaluation explicitly; when present, evaluate against the intersection of your registered active set and package_ids, and silently drop any IDs you don’t recognize — both publisher modes (all-active and fuzzed/padded) rely on this behavior. Surfacing unknown IDs as errors would leak your registry membership back to the publisher.
- Resolve the tokens against your identity graph on whichever
uid_types you support. Entry order in the request is not semantically significant — apply your own preference order per the buyer’s own preference order. All entries identify the same user, so the first successful resolution is sufficient. When multiple identity types are present, buyers SHOULD prefer opaque provider IDs (UID2, EUID, ID5, RampID) over strongly re-identifying tokens likehashed_email; this neutralizes scenarios where a misconfigured or compromised router forwards only the highest-risk token. - Check frequency caps: has this user exceeded the package’s impression limit?
- Check audience rules: is this user in the target audience?
- Check suppression lists: should this user be excluded?
- Return eligibility for each package
serve_window_sec is a per-package single-shot fcap: after the publisher serves the user one impression on each eligible package within this window, the publisher MUST re-query Identity Match before serving from those packages again. Default 60s, max 300s. This is not a router response cache TTL — see The serve-window contract.
What you never receive in Identity Match: page URLs, content topics, keywords, article text, or any content signal. You cannot determine what the user is looking at.
Why you receive ALL packages, not just the ones that matched in Context Match: this prevents you from inferring what content the user is viewing. If you only received packages that matched the hiking article, you’d know the user was reading about hiking. Receiving all packages preserves structural separation.
The Join Happens Publisher-Side
You never see the combined result. The publisher’s router:- Intersects your Context Match offers with your Identity Match
eligible_package_ids - Only activates packages that appear in both responses
- Sets ad server targeting key-values for matched packages
- The ad server makes the final rendering decision
Frequency Cap Management
Cross-publisher frequency capping is the primary use case for Identity Match. Cap policy and counting live in your impression tracker; the Identity Match service consumes only cap-fire signals at query time. The split:- Impression tracker receives pixel fires, decodes the TMPX token, and applies whatever fcap policies you maintain — counting impressions across whatever dimensions you cap on (package, campaign, advertiser, creative, line item) for each resolved user identity, with whatever windowing and dedup logic your policy engine uses.
- On the impression that exhausts a cap, the impression tracker writes a cap-fire entry —
(user_identity, package) capped until <expireAt>— into the Identity Match cap-state store. - Identity Match service at query time excludes any package with a cap-fire entry against any of the request’s identities from
eligible_package_ids.
max_count rises or falls, a policy is paused or removed, a package is reassigned — you MUST re-evaluate the affected (user_identity, package) cap-state entries against the new policy and push the appropriate updates: delete entries for users no longer over-cap, extend (overwrite with a new expire_at) entries that are still over-cap but whose window changed. The cap-state store doesn’t store counts and can’t re-evaluate on its own; the buyer’s policy owner is the source of truth. See Policy updates and cap-state re-evaluation for the event shapes.
Because Identity Match runs across all publishers using TMP, a user who saw your ad on Publisher A will correctly show as over-frequency on Publisher B — even though you can’t see which publisher sent the request.
For the implementation details — the fcap_keys label model, the reference valkey data model, exposure record shapes, the SDK primitives, and conformance scenarios — see Impression Tracker Implementation Reference. The boundary contract that sits between the impression tracker and the Identity Match service is at Frequency-Cap Data Flow.
How Buyers Learn About Exposures
Thetmpx field on the Identity Match response carries a TMPX token — an HPKE-encrypted blob containing the user’s resolved identity tokens. The publisher substitutes {TMPX} into creative tracking URLs. When the ad serves, your impression pixel receives the encrypted token. Your impression tracker decrypts it, applies your fcap policy logic against the resolved identities, and (when a cap fires) writes a cap-fire entry to the Identity Match cap-state store. Most production deployments separate decode (synchronous, at intake) from policy evaluation and cap-state writes (asynchronous, behind a queue) for buffering.
This gives you real-time per-user exposure signals without the publisher seeing user identity.
See TMPX Exposure Tokens for the encryption format and binary token structure, and Frequency-Cap Data Flow for the cap-state store boundary contract.
Provider Registration
Provider registration is an out-of-band process. After establishing a media buy viacreate_media_buy, coordinate with the publisher to provide your TMP base URL. This typically involves a commercial agreement and may require legal review, since the publisher will be sending content signals and identity tokens to your endpoints. The publisher then configures your provider entry in their router (see router deployment).
identity_match, you MUST declare countries (which country codes you serve) and uid_types (which identity types you resolve). The router uses these to filter Identity Match fan-out — without them, the router cannot route requests to your provider.
You can support either or both endpoints. Context Match only means contextual targeting without frequency capping. Identity Match only means the publisher evaluates context locally from your media buy’s targeting rules and calls you only for frequency checks. Both means full TMP integration.
Health endpoint
You SHOULD exposeGET /health at your base URL. Return HTTP 200 with {"status": "ok"} when ready. The publisher’s router uses this for pre-flight checks and monitoring. It is not called during request fan-out — only on a background interval.
Error Handling
When your agent cannot evaluate a request, return an error response:- No matching packages: Return an empty
offersarray (not an error). This is the normal case when your packages don’t match the content. - Internal failure: Return an error response. The router skips your provider and proceeds with other providers.
- Timeout: If you can’t respond within the latency budget, the router skips you. No error response needed — the router handles this.
The serve-window contract
Theserve_window_sec field on Identity Match responses is a per-package single-shot fcap between the buyer and the publisher:
- For each package in
eligible_package_ids, the publisher MAY serve the user at most one impression on that package withinserve_window_secseconds. - After the publisher has served one impression on each eligible package, the publisher MUST re-query Identity Match before serving any of those packages to the same user again.
- Multi-impression frequency capping (5/day, 100/month, etc.) is separate. It lives in your buyer-side state and is updated out-of-band via TMPX impression callbacks regardless of
serve_window_sec. The serve window is the protocol-level throttle; multi-impression caps are buyer-internal policy.
{identities_hash, provider_id, package_ids_hash, consent_hash} (see spec for canonical bytes), but the publisher’s binding contract is the serve-window throttle, not the router’s cache window.
Choosing a serve_window_sec value: Default 60 seconds. Range 1–300. Anything longer than 300 makes per-package fcap too coarse for typical campaigns. Anything shorter than your IdentityMatch round-trip just adds load. 60 is a good default; tune downward if eligibility state shifts faster (close to a cap, audience just changed) or upward (max 300) if your IdentityMatch service is at load and the campaigns are tolerant of coarser fcap.
Performance Requirements
| Metric | Target |
|---|---|
| Agent-side processing | < 30ms p95 |
| End-to-end (publisher → router → agent → router → publisher) | < 50ms p95 |
| Availability | 99.9% |
| Error rate | < 0.1% |
Measurement
The publisher reports delivery viaget_media_buy_delivery. Your agent queries delivery data to reconcile impressions, track pacing, and update frequency state.
Buyers receive real-time per-user exposure signals via the {TMPX} macro. The Identity Match response includes an encrypted TMPX token that flows through creative tracking URLs to your impression pixel. Your cluster master decrypts the token and updates per-user frequency state in real time. get_media_buy_delivery provides aggregate delivery metrics for reconciliation and pacing — it is not the primary frequency input.
What’s Different from OpenRTB
| OpenRTB | TMP | |
|---|---|---|
| You receive | Full bid request (user + content + device) | Either content OR identity, never both |
| You return | Bid price | Offer (creative manifest) or eligible package IDs + serve window |
| Auction | Exchange runs auction | No auction — publisher joins locally |
| Frequency | Per-DSP only | Cross-publisher via Identity Match |
| Integration | Per-exchange SSP adapter | Two endpoints (context + identity), any surface |