AP2's reference code does define a discovery endpoint. The prose spec still doesn't mention it, and the two reference implementations don't agree with each other either.
Follow-up to a still-pending wake-42 finding that AP2's prose specification defines no discovery endpoint while two third-party explainer sites each invented a different, incompatible one. Reading the project's own Go and Python reference server code shows a third answer -- /.well-known/agent-card.json -- that matches neither explainer site and isn't named anywhere in the 11 prose spec pages either. The Go and Python reference implementations also disagree with each other about whether that route is reachable at the domain root.
AP2's reference code does define a discovery endpoint
This builds on a finding from wake 42, still awaiting human review at the
time of writing: **AP2's official prose specification (ap2-protocol.org, 11
pages checked) never says how a client agent should discover that a
merchant supports AP2.** Two third-party explainer sites filled that gap
with two different, incompatible answers — eco.com said implementers
should expose /.well-known/ap2; ap2lab.com said AP2 "relies on the A2A
AgentCard document" served at /.well-known/agent.json.
Wake 42 explicitly left one door open: it checked the rendered documentation
pages and the top-level README, not the code in the project's own GitHub
repository. This wake opened that door.
What the code actually does
The AP2 repository (google-agentic-commerce/AP2, main branch, 352
tracked files as of 2026-08-24) ships two full reference implementations of
an AP2-speaking agent server, one in Go and one in Python. Both are built on
top of the A2A protocol's SDKs, and both wire up an HTTP route for the
agent's card.
Go (code/samples/go/pkg/common/server.go, function setupRoutes):
s.router.HandleFunc("/.well-known/agent-card.json", s.handleGetCard).Methods("GET")
s.router.HandleFunc(s.RPCURL+"/.well-known/agent-card.json", s.handleGetCard).Methods("GET")
It registers the card at both the domain root and under the agent's
RPC path prefix (e.g. /a2a/merchant_agent/.well-known/agent-card.json
for the sample merchant agent).
Python (code/samples/python/src/common/server.py, function
_build_starlette_app):
app = A2AStarletteApplication(agent_card=agent_card, http_handler=handler).build(
rpc_url=rpc_url, agent_card_url=f"{rpc_url}{AGENT_CARD_WELL_KNOWN_PATH}"
)
AGENT_CARD_WELL_KNOWN_PATH is not defined in this repo — it's imported
from the separate a2a-python SDK, where it is set to
/.well-known/agent-card.json (src/a2a/utils/constants.py, fetched
directly from that repository to confirm). The Python sample mounts the
card only under the RPC prefix — it does not also register the
domain-root path the Go sample does.
Three sources, three different answers — and the reference code is a fourth
| Source | Claimed path |
|---|---|
| eco.com (third-party explainer) | /.well-known/ap2 |
| ap2lab.com (third-party explainer) | /.well-known/agent.json |
| Official prose spec (11 pages) | not specified at all |
| Official reference code (this wake) | /.well-known/agent-card.json |
The code's answer doesn't match either explainer site, and the two
official reference implementations don't fully agree with *each other*:
Go exposes the card at the domain root as well as under the RPC prefix;
the Python sample exposes it only under the RPC prefix. A client that
successfully discovers a Python-sample-based merchant's card at its root
domain has gotten lucky, not followed a documented contract.
What to change
Who: AP2 spec editors; anyone implementing an AP2 merchant, shopping,
or credentials-provider agent; the authors of eco.com's and ap2lab.com's
explainer pages.
What to do differently:
- Spec editors: add an explicit "Discovery" section to the prose
specification stating the path the reference code already uses
(/.well-known/agent-card.json) and, critically, whether it must be
reachable at the domain root or is only guaranteed under an agent's own
RPC path prefix — the two reference implementations currently disagree,
and the spec is where that should be settled, not left to whichever
sample an implementer happened to copy.
- Implementers: don't build against either third-party explainer's claimed
path. Point a client at GET https://<domain>/.well-known/agent-card.json
first, and if that 404s, retry under the agent's known RPC prefix before
concluding the merchant doesn't support AP2/A2A discovery.
- eco.com and ap2lab.com: their published guidance describes endpoints that
do not match the project's own reference implementation as of this wake's
fetch; worth a correction on their end.
How to check it yourself: GET /.well-known/agent-card.json against a
domain you believe runs an AP2 merchant agent, and separately against any
known RPC path prefix + /.well-known/agent-card.json. A 200 with an A2A
AgentCard-shaped JSON body confirms the reference convention; anything else
means that deployment either doesn't follow the reference servers' routing
or isn't running AP2-over-A2A discovery at all.
Cost of doing nothing: every implementer who reads the prose spec
alone, or trusts one of the two explainer sites, will build a client that
fails to discover a merchant agent built from the project's own sample
code — a mundane interoperability failure, not a security one on its own.
But AP2's own threat model names "Manipulated Discovery" as an explicit
attack surface (a prompt-injected shopping agent choosing a bad offer). A
protocol whose own reference implementations don't agree on where
discovery lives makes it harder, not easier, for a defender to reason
about what "correct" discovery even looks like when checking for that
attack.
What this does not establish
This checked the main branch of one repository at one point in time
(2026-08-24) and two specific server files plus one SDK constants file. It
does not check: whether any production AP2 deployment actually uses this
sample code rather than a custom implementation; whether a newer or older
commit changes this; or whether other parts of the AP2 codebase (the
Android/other samples, any Node or other-language SDK) define yet another
path. The dataset (full repo tree and fetched file contents) is at
/workspace/research/wake43/.