Background
The AdCP Python SDK currently exposes two authorization-check primitives:
- Push (publisher → agent):
verify_agent_authorization(adagents_data, agent_url, ...) — given a parsed adagents.json, is this agent listed?
- Pull, with caller-supplied list (agent → known publishers):
fetch_agent_authorizations(agent_url, publisher_domains=[...]) (adcp-client-python adagents.py:1306) — caller passes a list of publisher_domains, SDK fetches each one and returns the subset that authorize the agent.
Neither answers the question every sales agent operator actually needs at sync time:
"What publishers have authorized my agent?"
Today operators have to either (a) maintain the publisher_domain list manually and call fetch_agent_authorizations against it, or (b) crawl the open web. Both are infeasible at scale.
Concrete trigger
Raptive (managed by CafeMedia, ~6,800 owned-and-operated domains) all delegate authorization to a single cafemedia.com adagents.json via either ads.txt MANAGERDOMAIN=cafemedia.com or adagents.json authoritative_location. The SDK's chain-following discovery handles per-domain verification correctly — but for a sales-agent operator onboarding Raptive, there's no way to discover the 6,800-domain set without either:
- Asking CafeMedia to hand over a spreadsheet (manual, stale)
- Building a per-domain bulk-import UI (papers over the missing primitive)
- Crawling DNS / ads.txt across the web
The AAO directory at agenticadvertising.org is already indexing publisher adagents.json files. It has the inverse map — it just doesn't expose it.
Proposal
Define an AAO directory inverse-lookup endpoint and add the corresponding SDK client function.
Endpoint shape (strawman)
GET https://{aao_directory}/v1/agents/{agent_url_encoded}/publishers
GET https://{aao_directory}/v1/agents/{agent_url_encoded}/publishers?since={iso8601} # incremental sync
Response:
{
"agent_url": "https://sales-agent.example.com",
"directory_indexed_at": "2026-05-19T12:00:00Z",
"publishers": [
{
"publisher_domain": "cooking.com",
"discovery_method": "ads_txt_managerdomain",
"manager_domain": "cafemedia.com",
"authorized_properties_count": 12,
"total_properties_count": 12,
"status": "authorized",
"last_verified_at": "2026-05-19T08:00:00Z"
},
{
"publisher_domain": "wsj.com",
"discovery_method": "direct",
"authorized_properties_count": 47,
"total_properties_count": 200,
"status": "authorized",
"last_verified_at": "2026-05-19T10:00:00Z"
}
],
"next_cursor": null
}
Mirrors the existing discovery_method / manager_domain fields on AdAgentsValidationResult so operators get the same provenance they already use for direct verification.
Status semantics
Reuse PublisherPartnerStatusKind-style discriminators that consumers like the Prebid Sales Agent already implement against:
authorized — typed binding resolves to ≥1 property
unbound — bare entry, top-level properties present (permissive resolution)
pending — agent listed but selector resolves to nothing, or not listed but file is fetchable
Excludes unreachable and no_properties — the directory only indexes publishers whose adagents.json was successfully fetched and references the agent.
Out of scope
- Authentication on the directory (publishers are public; if rate-limiting is needed, key on agent_url with a public key proof — separate RFC)
- Cross-directory federation
- Push notification of new authorizations (poll-based v1 is fine)
Work items
References
- Salesagent issue blocking on this: prebid/salesagent#511 — being closed in favor of this upstream solve
- Existing per-domain pull API:
adcp/adagents.py:1306 fetch_agent_authorizations
- Existing single-domain discover-and-validate with provenance:
adcp/adagents.py:676 validate_adagents_domain
Background
The AdCP Python SDK currently exposes two authorization-check primitives:
verify_agent_authorization(adagents_data, agent_url, ...)— given a parsed adagents.json, is this agent listed?fetch_agent_authorizations(agent_url, publisher_domains=[...])(adcp-client-python adagents.py:1306) — caller passes a list of publisher_domains, SDK fetches each one and returns the subset that authorize the agent.Neither answers the question every sales agent operator actually needs at sync time:
Today operators have to either (a) maintain the publisher_domain list manually and call
fetch_agent_authorizationsagainst it, or (b) crawl the open web. Both are infeasible at scale.Concrete trigger
Raptive (managed by CafeMedia, ~6,800 owned-and-operated domains) all delegate authorization to a single
cafemedia.comadagents.json via either ads.txtMANAGERDOMAIN=cafemedia.comor adagents.jsonauthoritative_location. The SDK's chain-following discovery handles per-domain verification correctly — but for a sales-agent operator onboarding Raptive, there's no way to discover the 6,800-domain set without either:The AAO directory at
agenticadvertising.orgis already indexing publisher adagents.json files. It has the inverse map — it just doesn't expose it.Proposal
Define an AAO directory inverse-lookup endpoint and add the corresponding SDK client function.
Endpoint shape (strawman)
Response:
{ "agent_url": "https://sales-agent.example.com", "directory_indexed_at": "2026-05-19T12:00:00Z", "publishers": [ { "publisher_domain": "cooking.com", "discovery_method": "ads_txt_managerdomain", "manager_domain": "cafemedia.com", "authorized_properties_count": 12, "total_properties_count": 12, "status": "authorized", "last_verified_at": "2026-05-19T08:00:00Z" }, { "publisher_domain": "wsj.com", "discovery_method": "direct", "authorized_properties_count": 47, "total_properties_count": 200, "status": "authorized", "last_verified_at": "2026-05-19T10:00:00Z" } ], "next_cursor": null }Mirrors the existing
discovery_method/manager_domainfields onAdAgentsValidationResultso operators get the same provenance they already use for direct verification.Status semantics
Reuse
PublisherPartnerStatusKind-style discriminators that consumers like the Prebid Sales Agent already implement against:authorized— typed binding resolves to ≥1 propertyunbound— bare entry, top-level properties present (permissive resolution)pending— agent listed but selector resolves to nothing, or not listed but file is fetchableExcludes
unreachableandno_properties— the directory only indexes publishers whose adagents.json was successfully fetched and references the agent.Out of scope
Work items
discovery_method = ads_txt_managerdomaininteracts with the salesagent#377-style warning that manager-domain authorizations must verify the source publisher is named in the manager's adagents.jsonadcp-client-python—fetch_agent_authorizations_from_directory(agent_url, directory_url, ...)References
adcp/adagents.py:1306fetch_agent_authorizationsadcp/adagents.py:676validate_adagents_domain