DEV Community

Peter
Peter

Posted on

Which UCP version is your validator actually checking against?

If you have a UCP profile at /.well-known/ucp, you have probably run it through a validator and got a score. The question almost nobody asks next is which version of the spec that score was measured against.

It matters more than it sounds. UCP has four published releases: 2026-01-11, 2026-01-23, 2026-04-08 and 2026-08-25. The profile shape changed completely in April, and the signing-keys field was renamed in August. A validator pinned to an older release does not just miss the new features. It can fail a correct profile and pass one that stopped being valid months ago, and both results look like any other report.

We learned this the hard way. Earlier this month I wrote up how six profile builders inside our own product were still emitting the January shape in September, and how our tests agreed with them the whole time. This post is the outward-facing version of the same lesson: how to tell whether the tool you rely on is current, and how to check it without taking anyone's word for it, ours included.

What each tool says it validates against

I went through the public UCP validators and wrote down the spec version each one states on its own site. As of September 24, 2026:

Tool Spec version stated
UCPChecker every published version, including 2026-08-25
UCPtools 2026-08-25
Rankly 2026-01-23
aicommerceaudit 2026-04-08
spck.dev 2026-04-08
UCPhub 2026-04-08
Nextwaves UCP Tester not stated

A few caveats before anyone reads this as a leaderboard. These are claims from each tool's own pages, not results of a test I ran against each of them. Stating an older version is not the same as being wrong, since a tool can be deliberately pinned, and plenty of live profiles still declare 2026-04-08. And a stated version is not a guarantee either. We stated a version we did not fully implement for five months.

What the table does tell you is where to look. If your profile declares 2026-08-25 and your validator says 2026-04-08, some of what it reports is about a spec your profile is not using.

What actually changed between versions

The changes that trip validators up are structural, so a validator on the wrong side of them gives confident wrong answers rather than vague ones.

2026-04-08 changed the shape of the profile. Services went from an object with transports nested under their name to an array of entries with a flat transport field. Capabilities went from an array of objects carrying their own name to a map keyed by name. Payment handlers moved from root $.payment into $.ucp.payment_handlers.

// 2026-01-11 / 2026-01-23
"services": {
  "dev.ucp.shopping": {
    "rest": { "schema": "...", "endpoint": "https://shop.example/ucp" }
  }
},
"capabilities": [{ "name": "checkout", "spec": "..." }]

// 2026-04-08 and 2026-08-25
"services": {
  "dev.ucp.shopping": [
    { "transport": "rest", "endpoint": "https://shop.example/ucp", "schema": "..." }
  ]
},
"capabilities": { "checkout": [{ "spec": "..." }] }
Enter fullscreen mode Exit fullscreen mode

A validator built for January can read a current profile as malformed from the first key, and every later check that depends on finding the services is either skipped or fails.

2026-08-25 renamed signing_keys to keys, and removed the old name entirely. A validator on 2026-04-08 can look for signing_keys in a current profile, not find it, and report that your signing keys are missing. It can also accept a profile that still uses signing_keys while declaring 2026-08-25, which is exactly the profile it should be flagging.

2026-08-25 also moved and renamed a lot of smaller things: payment extensions from dev.ucp.shopping.* to dev.ucp.common.payment.*, the allows_ prefix dropped from fulfillment flags, buyer consent booleans replaced by a reverse-DNS map. It added new capabilities too, including location search and lookup, permalink and loyalty. An older validator will treat all of them as unknown.

Schema URLs became version-scoped. Unversioned https://ucp.dev/schemas/... URLs return 404 today, and https://ucp.dev/2026-08-25/... returns 200. A validator that does not fetch the schemas it is pointed at will never notice this. One that fetches the wrong ones will fail on a network error that has nothing to do with your profile.

One warning if you plan to check these details yourself: read the schemas, not the release notes. The 2026-08-25 notes get three field names wrong. They say $requestConstraints, ap2_mandates and payment_terms, while the schemas define request_constraints, dev.ucp.common.payment.ap2_mandate and dev.ucp.common.payment.terms. A validator written from the notes is wrong in exactly those places.

How to check your validator yourself

You do not need to trust a comparison table, including the one above. Three tests take about twenty minutes and will tell you more.

1. Build a fixture from the spec, not from anyone's sample. Clone the spec repository at the release tag and take the business profile example from docs/, cross-checked against source/schemas/:

git clone --depth 1 --branch v2026-08-25 \
  https://github.com/Universal-Commerce-Protocol/ucp.git
Enter fullscreen mode Exit fullscreen mode

Do not use the samples repository for this. It has no tags, and its reference server still serves a 2026-04-08 profile. Run the fixture through your validator. A current validator should report zero errors on it. Anything it flags is either a real finding you can confirm in the schema, or a sign that the validator is modelling a different version.

2. Run the keys canary. Take that same fixture and rename keys to signing_keys. Against 2026-08-25, this is now wrong, and a current validator should say so. Then put keys back and remove it entirely. keys is optional in the schema, so a validator that hard-errors on its absence is inventing a requirement. The two results together tell you whether the tool knows about the August rename and whether it knows what is actually required.

3. Check what it calls required. In a /.well-known/ucp business profile, the required fields are ucp, ucp.version, ucp.services and ucp.payment_handlers. Capabilities are optional, and so are signing keys. If your validator errors on something outside that list, look the field up in the schema at the tag. We shipped a hard error for a field called supported_mechanisms that does not exist in any published version. Grepping source/ and docs/ at every tag returns nothing. Nobody noticed until we tested against the real schemas.

If a tool passes all three, it is current, whatever its site says. If it fails one, you know which of its findings to discount.

Why this is the question to ask

Scores are the part everyone looks at, and they are the part that hides this problem best. A 62 and a 25 look like a difference in your profile. In our case they were a difference in our validator: our own site went from F/25 to D/62 without the profile changing, purely by removing false negatives that came from modelling the wrong version.

So before you act on a report, whoever it came from, find out which spec it measured you against. If the answer is not written down anywhere, the fixture test above will tell you in a few minutes.


UCP is an open standard co-developed by Google and Shopify. UCPtools is an independent community tool and is not affiliated with either company. Every schema detail above was read from the published specification in the Universal-Commerce-Protocol/ucp repository at the release tags, not from the release notes. Tool versions were taken from each tool's public site on September 24, 2026.

You can check a profile against v2026-08-25 with the free validator at ucptools.dev, or run it in CI with the UCP validate GitHub Action. The story of how our own builders drifted is in Five months, six profile builders, one silent spec drift.

Top comments (0)