The UCP Agent Profile: How We Gave Our Shopping Agent a Verifiable Identity
When an AI shopping agent calls your store, who exactly is calling?
For most of agentic commerce's short history, the honest answer has been: you don't know. A request arrives, it claims to be a shopping agent, it asks for your catalog and tries to build a cart — but there is nothing on the wire that proves which platform sent it, or that the request wasn't altered in flight. The agent is a voice on the phone with no caller ID.
That is the gap the UCP agent profile closes. As of this week, UCP Playground's platform profile at /.well-known/ucp-agent conforms fully to the UCP profile schema defined in UCP 2026-04-08. A merchant can now fetch our profile, read the capabilities we support, pull our public keys, and cryptographically verify that a request really came from us. Here is what that means, why the spec is built the way it is, and how we implemented it.
Two different kinds of identity
It is worth separating two things that both contain the word "identity," because they solve opposite problems.
Identity linking authenticates the buyer — the human — to the merchant, so an agent can shop as you and unlock loyalty pricing, saved addresses, and order history. That flows from the user, through the agent, to the store.
The agent profile authenticates the platform — the software making the calls — to the merchant. It answers a different question: not "who is the shopper?" but "which agent is this, and can I trust that this request is genuinely theirs and unmodified?"
Real agentic commerce needs both. This post is about the second one.
Two profiles, one schema
UCP is symmetric by design. Both sides of an agent-to-merchant conversation publish a profile, and both profiles share a common base structure.
A merchant publishes its profile at /.well-known/ucp. That is the document our checker reads on every scan — protocol version, services, capabilities, payment handlers. A platform (an agent like Playground) publishes the mirror-image document too — the spec defines its shape but deliberately not its address, since the URL travels with every request (next paragraph). We host ours at /.well-known/ucp-agent, the natural mirror of the merchant path.
The link between them is the UCP-Agent header. When our agent calls a store, the request carries a UCP-Agent header pointing at our profile URL. The merchant fetches that URL, and now it has everything it needs to identify us and verify our signatures — from the same document that declares what we can do.
One profile, two jobs: capability negotiation and cryptographic identity.
What the spec defines
Per UCP 2026-04-08, a profile document's root is a ucp member with a sibling signing_keys array. That sibling relationship is the part that matters, and the part we got wrong the first time (more on that below).
The ucp member carries the protocol version, the required services and payment_handlers registries, and a capabilities registry where each entry carries its own version, spec, and schema URLs. The signing_keys array sits next to it at the root — a JWK set of the public keys used to verify signed requests.
Illustratively, the shape looks like this:
{
"ucp": {
"version": "2026-04-08",
"services": { /* ... */ },
"payment_handlers": { /* ... */ },
"capabilities": {
"dev.ucp.shopping.checkout": [
{
"version": "2026-04-08",
"spec": "https://ucp.dev/2026-04-08/specification/checkout/",
"schema": "https://ucp.dev/2026-04-08/schemas/shopping/checkout.json"
}
]
}
},
"signing_keys": [
{ "kid": "GSlYTYjTjtyG2pdrmaxuUH-z3mtP-j1ThxvPVpRhrW0", "kty": "EC", "crv": "P-256", "x": "...", "y": "..." }
]
}
That kid isn't a label we picked — it's the key's RFC 7638 JWK thumbprint, a hash derived from the key material itself. Because the identifier is computed from the key, the kid a verifier matches on can never silently drift from the key it points to. And the document as a whole is built to the shape the official UCP profile schema defines; a profile that doesn't match that shape is one a strict verifier is entitled to reject — which is exactly what makes the next section worth its own headline.
How a merchant verifies us
Once a merchant has our profile, verification follows the UCP signing model, built on standard RFCs rather than anything bespoke:
- Read the pointer. The incoming request carries a
UCP-Agentheader pointing to our profile. - Fetch and cache the profile at that URL (ours is
/.well-known/ucp-agent). - Match the key. The merchant matches the
keyidfrom the request'sSignature-Inputto akidin oursigning_keys[]. - Verify the signature. Using the corresponding public key, it verifies an HTTP Message Signature (RFC 9421, ECDSA P-256 / ES256). Each signature covers the request method, the target URI, the body digest (
Content-Digest, RFC 9530), and the advertised agent identity.
The same profile that advertises our capabilities provides the verification keys. That is UCP's key-resolution mechanism in a sentence.
Per the spec, platforms SHOULD sign requests — and Playground does, on every outbound call to a merchant. Crucially, this works across transports: MCP (JSON-RPC) requests now also carry the transport-level UCP-Agent header alongside the existing meta.ucp-agent.profile in the tool arguments, so a merchant gets the same verifiable identity whether they speak REST or MCP.
Why "conforms to the schema" was the headline
We published a public agent profile before it was schema-perfect, and the gap is instructive.
Our first cut used a non-standard envelope and nested signing_keys inside it. It looked reasonable. It was wrong. Per UCP 2026-04-08, verifiers resolve keys via profile.signing_keys matched by kid — they expect signing_keys as a sibling of ucp, at the root of the document. A verifier that follows the spec literally would look for our keys, not find them where the schema says they live, and fail the verification.
So the fix was structural: emit the correct shape — a ucp member plus a root-level signing_keys array — to match what the official profile schema defines, locked down with tests so it can't regress. The lesson generalizes to anyone shipping a UCP profile: "we publish keys" is not the same as "a stranger's verifier can find and use them." Conformance is what makes the trust transferable.
What our profile declares
Concretely, the Playground profile at /.well-known/ucp-agent now publishes:
- Who we are — the platform's name and contact, so a merchant can identify the party behind the requests.
- What we support — the UCP capabilities we implement, so a store can compute the capability intersection between what it offers and what our agent can actually use.
- How to verify us — the
signing_keysJWK set used to check our signed requests.
That third item is what turns the profile from a description into a credential.
Why this matters for merchants
Caller ID is the headline benefit, but it compounds:
Trust you can act on. A verified request is a different thing from an anonymous one. A merchant can apply different rate limits, surface different inventory, or enable different payment methods for agents it can cryptographically identify.
Capability intersection. Because our profile declares what we support, a store doesn't have to guess. It can negotiate against the overlap between its capabilities and ours, instead of probing blindly.
Verified both ways. The trust isn't one-directional. Playground signs the requests it sends to a store, which the store verifies; and per spec a merchant signs the order webhooks it sends back, which Playground verifies. Each side authenticates the other — and that symmetry is what lets agentic commerce graduate from "anonymous traffic we tolerate" to "named parties we transact with."
What changes for agent platforms
If you are building an agent, the takeaway is that publishing a conformant profile makes you a first-class participant rather than unidentified traffic. A schema-conformant profile at a stable URL (we use /.well-known/ucp-agent), a signing_keys JWK set, and signed requests are increasingly the price of admission for merchants who care who they let into their checkout — and the merchants who care most are exactly the ones worth selling to.
The asymmetry of early agentic commerce — stores that publish rich profiles, agents that show up anonymous — was always temporary. The agent profile closes it.
Try it
See our profile: ucpplayground.com/.well-known/ucp-agent Read the changelog: ucpplayground.com/changelog Check your store's profile: ucpchecker.com/check Follow the spec: ucp.dev · github.com/Universal-Commerce-Protocol/ucp
Related reading: The agent profile is the platform-side mirror of UCP identity linking, which authenticates the buyer. For the merchant side of being agent-ready, see Is My Store UCP-Ready? and the breakdown of the UCP profile and where stores still have gaps. For why we built an agent that actually shops in the first place, see Why We Built UCP Playground.
About UCP Checker
UCP Checker is the independent validation and monitoring layer for the Universal Commerce Protocol. We crawl, validate and grade every public UCP profile we can find, run the merchant directory, the UCP Score and live adoption stats, and — through UCP Playground — test how real AI agents behave against real stores. The agent profile in this post is how Playground identifies itself to those stores.
- See our agent profile: ucpplayground.com/.well-known/ucp-agent
- Check your store: ucpchecker.com/check
- Grade it (UCP Score): ucpchecker.com/score
- Browse the directory: ucpchecker.com/directory
- Get notified on changes: ucpchecker.com/alerts
Check your domain's UCP status
See if your storefront is ready for agentic commerce in seconds.
Get the agentic commerce digest every Monday
Real adoption data, ecosystem trends, new spec versions, and the stores that broke or recovered this week. Read by founders and engineers building the next generation of commerce.

