UCP Checker

Validate your Universal Commerce Protocol profile

Paste a store's UCP profile and check it against the release it declares, with the same rules as a live check. Nothing is fetched or stored.

Already live? Check your domain instead: it also reads HTTPS, robots.txt, your homepage and whether your services answer.

Every rule a paste can check

The same rules as the live check, run on the text you paste, against the release the profile declares.

Profile passes schema validationspecProfile structure conforms to the published UCP spec.
Protocol version present and well-formedspecucp.version follows YYYY-MM-DD format.
Public keys publishedspecSigning keys published as a top-level keys list for response verification. signing_keys was removed in the 2026-08-25 release; profiles that still use it are accepted.
No validation warningsspecProfile passes structural and field-level rules.
Capabilities declaredcapabilitiesNumber of agent-readable capabilities under ucp.capabilities.
Checkout capabilitycapabilitiesStore declares a checkout-namespaced capability.
Transports declaredcapabilitiesService transports (REST/MCP/A2A/Embedded) declared on services.
Payment handlerscapabilitiesTokenized payment handlers registered for in-conversation checkout.

Common errors and how to fix them

Paste: this page finds it · Live: needs the live check
PasteWrap profile in a "ucp" objectUCP_MISSING_ROOT

The top-level "ucp" object is required by the spec but is missing.

Why it matters: Agents read the profile by drilling into the ucp object first. A flat profile fails strict parsers and will be rejected even if the inner data is correct.

Fix: Move all UCP fields under a top-level "ucp" key. Public keys stay at the root as a keys array (sibling of ucp); v2026-08-25 renamed the legacy signing_keys to keys.

example
{
  "ucp": {
    "version": "2026-08-25",
    "capabilities": { ... },
    "services": { ... }
  },
  "keys": [ ... ]
}
PasteDeclare ucp.versionUCP_MISSING_VERSION

No protocol version found on the profile.

Why it matters: Without a version, agents cannot pick the right schema to validate against. Most strict agents will refuse to load the profile.

Fix: Use the latest UCP protocol version, written as a date (YYYY-MM-DD).

example
{
  "ucp": {
    "version": "2026-08-25"
  }
}
PasteUse YYYY-MM-DD for ucp.versionUCP_INVALID_VERSION_FORMAT

Version is set but does not match the YYYY-MM-DD format the spec mandates.

Why it matters: UCP versions are dates, not semver. Strict parsers reject anything else, even semantically equivalent strings like "2026.04.08".

example
"version": "2026-08-25"
PasteServe profile as application/jsonUCP_RESPONSE_NOT_JSON

The profile URL did not return parseable JSON.

Why it matters: Agents request /.well-known/ucp expecting JSON. HTML error pages, plain text, or YAML will all fail validation regardless of content.

Fix: Set the Content-Type header on the profile response and verify the body is valid JSON (no trailing commas, comments, or BOM).

PasteDeclare ucp.capabilitiesUCP_MISSING_CAPABILITIES

No capabilities are declared, so agents cannot tell what your store supports.

Why it matters: Agents read the capabilities map to know whether to attempt cart, checkout, payment tokenization, identity linking, etc. An empty list collapses the agent to "browse only" mode.

Fix: Name spec capabilities under dev.ucp.shopping.* (for example dev.ucp.shopping.checkout). Each entry needs a version, a spec URL and a schema URL.

example
"ucp": {
  "capabilities": {
    "dev.ucp.shopping.checkout": [
      {
        "version": "2026-08-25",
        "spec": "https://ucp.dev/2026-08-25/specification/checkout/",
        "schema": "https://yourstore.com/.well-known/ucp/schemas/checkout.json"
      }
    ]
  }
}
PasteDeclare ucp.servicesUCP_MISSING_SERVICES

No services declared, so agents have no transport endpoints to call.

Why it matters: Services are the actual endpoints agents hit. A capability without a service is a promise without a URL.

Fix: Each service entry needs version, transport, endpoint (for REST/MCP/A2A), and a schema URL.

example
"ucp": {
  "services": {
    "dev.ucp.shopping": [
      {
        "version": "2026-08-25",
        "transport": "mcp",
        "endpoint": "https://yourstore.com/api/ucp/mcp",
        "spec": "https://ucp.dev/2026-08-25/specification/overview/",
        "schema": "https://yourstore.com/.well-known/ucp/schemas/shopping.json"
      }
    ]
  }
}
PasteDeclare a transport on the serviceUCP_SERVICE_MISSING_TRANSPORT

Service entry has no "transport" field and no legacy nested transport.

Why it matters: Without a transport, agents do not know whether to speak REST, MCP, or A2A to your endpoint.

Fix: Allowed transport values per spec: rest, mcp, a2a, embedded.

example
{
  "version": "2026-08-25",
  "transport": "mcp",
  "endpoint": "https://yourstore.com/api/ucp/mcp"
}
PasteUse a valid transport valueUCP_SERVICE_INVALID_TRANSPORT

Service declares a transport not in the spec's allowed list.

Why it matters: Allowed values are rest | mcp | a2a | embedded. Anything else is treated as "transport unknown" by strict agents.

example
"transport": "mcp"
PasteAdd endpoint URL to the serviceUCP_SERVICE_MISSING_ENDPOINT

Service uses a transport that requires an endpoint URL but none is declared.

Why it matters: REST, MCP, and A2A transports all need a URL to call. Embedded is the only transport that omits this.

example
"endpoint": "https://yourstore.com/api/ucp/mcp"
PasteDeclare ucp.payment_handlersUCP_MISSING_PAYMENT_CONFIG

No payment handlers declared.

Why it matters: Without payment handlers, agents cannot tokenize payment for in-conversation checkout. Stores using checkout-link redirects can declare an empty array intentionally.

example
"ucp": {
  "payment_handlers": {
    "com.example.pay": [
      {
        "id": "my-pay-handler",
        "version": "2026-08-25",
        "spec": "https://ucp.dev/2026-08-25/specification/payment-handler-guide/",
        "schema": "https://yourstore.com/.well-known/ucp/schemas/payment.json"
      }
    ]
  }
}
PasteServe UCP endpoints over HTTPSUCP_INSECURE_ENDPOINT

A declared service endpoint uses http:// instead of https://.

Why it matters: Agents reject non-HTTPS endpoints outright. Any signed payload over HTTP is meaningless because the channel itself is tamperable.

example
"endpoint": "https://yourstore.com/api/ucp/mcp"
PasteUpdate to a published UCP versionUCP_UNKNOWN_VERSION

The declared version is not in the published spec list.

Why it matters: Agents fall back to the closest known version, but breaking changes between releases can silently corrupt requests. Pin to a published version your stack actually supports.

Fix: See https://ucpchecker.com/spec for the current published version list.

example
"version": "2026-08-25"
PastePublish the public keys agents use to check your messagesUCP_MISSING_SIGNING_KEYS

Your UCP profile lists no public keys, so an agent cannot confirm that a message really came from your store.

Why it matters: Agents use these keys to check that checkout messages really came from you. A store that takes payment through the agent needs them. A store that sends the buyer to its own checkout page can manage without them for now.

Fix: Create a P-256 (ES256) key pair: ES256 is the one algorithm every UCP agent must be able to check. Add the public key to a "keys" list at the top level of your UCP profile, as in the example, with its own "kid", and keep the private key on your server. The spec recommends a new key every 90 days: publish the new one next to the old, sign with it, and remove the old key a week later.

example
{
  "keys": [
    {
      "kty": "EC",
      "crv": "P-256",
      "x": "<base64url x>",
      "y": "<base64url y>",
      "kid": "store-2026-10",
      "use": "sig",
      "alg": "ES256"
    }
  ],
  "ucp": { ... }
}
PastePopulate ucp.capabilities or remove itUCP_EMPTY_CAPABILITIES

capabilities is present but empty.

Why it matters: An empty capabilities object signals "I support nothing" to agents. It is usually a serialization bug, not the intent. If you genuinely have no capabilities yet, omit the key entirely.

example
"capabilities": {
  "dev.ucp.shopping.checkout": [{ "version": "2026-08-25", ... }]
}
PasteMove capabilities under the ucp objectUCP_FLAT_CAPABILITIES

capabilities is at the root level instead of nested under ucp.

Why it matters: Spec v2026-04-08 canonicalizes capabilities under ucp.capabilities. Some agents already drop the root-level fallback; future versions will too.

example
{
  "ucp": {
    "capabilities": { ... }
  }
}
PasteName capabilities the way the spec doesUCP_CAPABILITY_INVALID_KEY

A capability is not named in the spec's dotted form (e.g. dev.ucp.shopping.checkout).

Why it matters: Capabilities are named like reversed web addresses so that names never collide: "checkout" is ambiguous; "dev.ucp.shopping.checkout" is not.

example
"capabilities": {
  "dev.ucp.shopping.checkout": [...]
}
PasteAdd version to each capability entryUCP_CAPABILITY_MISSING_VERSION

A capability declaration is missing the required "version" field.

Why it matters: Capabilities evolve independently of the profile. Agents pick the highest mutually supported version, and without one declared, they cannot.

example
{
  "version": "2026-08-25",
  "spec": "https://ucp.dev/2026-08-25/specification/checkout/",
  "schema": "https://yourstore.com/.well-known/ucp/schemas/checkout.json"
}
PasteUse YYYY-MM-DD for capability versionUCP_CAPABILITY_INVALID_VERSION

A capability version is not in YYYY-MM-DD format.

Why it matters: Capability versions follow the same date-based format as the profile version itself.

example
"version": "2026-08-25"
PasteMove services under the ucp objectUCP_FLAT_SERVICES

services is at the root level instead of nested under ucp.

Why it matters: Spec canonicalizes services under ucp.services. Future agents may drop the flat fallback.

example
{
  "ucp": {
    "services": { ... }
  }
}
PasteName services the way the spec doesUCP_SERVICE_INVALID_KEY

A service is not named in the spec's dotted form (e.g. dev.ucp.shopping).

Why it matters: Like capabilities, services are named like reversed web addresses so names never collide.

example
"services": {
  "dev.ucp.shopping": [...]
}
PasteAdd version to each service entryUCP_SERVICE_MISSING_VERSION

A service entry is missing the required "version" field.

Why it matters: Service versions tell agents which contract to expect at the endpoint.

example
"version": "2026-08-25"
PasteUse YYYY-MM-DD for service versionUCP_SERVICE_INVALID_VERSION

A service version is not in YYYY-MM-DD format.

Why it matters: Service versions follow the same date-based format as the profile version.

example
"version": "2026-08-25"
PasteMove payment_handlers under the ucp objectUCP_FLAT_PAYMENT_HANDLERS

payment_handlers is at the root level instead of under ucp.

Why it matters: Canonical location is ucp.payment_handlers as of v2026-04-08. The root-level fallback is supported now but may not be in future protocol versions.

example
{
  "ucp": {
    "payment_handlers": { ... }
  }
}
PasteFlatten payment.handlers to ucp.payment_handlersUCP_NESTED_PAYMENT_HANDLERS

Payment handlers are nested under a root "payment" object.

Why it matters: Older Shopify-managed profiles used payment.handlers. Spec v2026-04-08 canonicalized to ucp.payment_handlers.

example
{
  "ucp": {
    "payment_handlers": {
      "com.example.pay": [...]
    }
  }
}
PasteName payment handlers the way the spec doesUCP_HANDLER_INVALID_KEY

A payment handler is not named in the spec's dotted form (e.g. com.google.pay).

Why it matters: Handlers are named like reversed web addresses (com.google.pay, com.stripe.terminal) so every store declaring the same payment method names it the same way, and an agent can recognise it.

example
"payment_handlers": {
  "com.google.pay": [...]
}
PasteAdd id to each payment handlerUCP_HANDLER_MISSING_ID

A payment handler is missing the required "id" field.

Why it matters: The id field uniquely identifies the handler instance for token routing. Required by the spec.

example
{
  "id": "my-google-pay-prod",
  "version": "2026-08-25"
}
PasteAdd version to each payment handlerUCP_HANDLER_MISSING_VERSION

A payment handler is missing the required "version" field.

Why it matters: Handler versions evolve independently of the profile. Agents pin their token request format to a specific handler version.

example
"version": "2026-08-25"
PasteUse YYYY-MM-DD for handler versionUCP_HANDLER_INVALID_VERSION

A payment handler version is not in YYYY-MM-DD format.

Why it matters: Handler versions follow the same date-based format as everything else in UCP.

example
"version": "2026-08-25"
PasteMove to the latest UCP protocol versionUCP_VERSION_OUTDATED

Your profile declares a valid but older protocol version. A newer one is published.

Why it matters: Older versions stay valid (agents use the version you declare), but newer abilities (embedded checkout, agent payment mandates, linked customer accounts, card authentication, payment terms and store location lookup) only work against the latest version. The profile itself barely changes: the signing keys move to a root-level "keys" list, and the rest of the update is in what capabilities can say.

Fix: Set the version to 2026-08-25 and publish your public keys as a root-level "keys" list. The older "signing_keys" field is still accepted, but "keys" is the one every verifier reads.

example
"ucp": {
  "version": "2026-08-25",
  ...
},
"keys": [ ... ]   // beside "ucp", not inside it
PasteLink to the capability spec URLUCP_CAPABILITY_MISSING_SPEC

Capability is missing its "spec" URL pointing to the published spec.

Why it matters: Agents fetch the spec URL to understand the request/response contract. Required of platforms; recommended for stores.

example
"spec": "https://ucp.dev/2026-08-25/specification/checkout/"
PastePublish a schema URL for the capabilityUCP_CAPABILITY_MISSING_SCHEMA

Capability is missing its "schema" URL.

Why it matters: The schema URL points to a JSON Schema (or equivalent) that agents validate request/response shapes against. Without it, runtime validation degrades to "best effort."

example
"schema": "https://yourstore.com/.well-known/ucp/schemas/checkout.json"
PasteLink to the service spec URLUCP_SERVICE_MISSING_SPEC

A service is missing its "spec" URL.

Why it matters: Agents fetch the spec to understand what the endpoint actually does. Required of platforms.

example
"spec": "https://ucp.dev/2026-08-25/specification/overview/"
PastePublish a schema URL for the serviceUCP_SERVICE_MISSING_SCHEMA

Service is missing its "schema" URL.

Why it matters: The schema lets agents validate request/response shapes before sending. Highly recommended for any non-trivial endpoint.

example
"schema": "https://yourstore.com/.well-known/ucp/schemas/shopping.json"
PasteLink to the handler spec URLUCP_HANDLER_MISSING_SPEC

A payment handler is missing its "spec" URL.

Why it matters: Spec URL helps agents understand what flavour of token to request (Apple Pay, Google Pay, network token, etc.).

example
"spec": "https://ucp.dev/2026-08-25/specification/payment-handler-guide/"
PastePublish handler request schemaUCP_HANDLER_MISSING_SCHEMA

A payment handler is missing its "schema" URL.

Why it matters: Schema URL points to the JSON Schema for token requests. Agents validate request shape before submitting.

example
"schema": "https://yourstore.com/.well-known/ucp/schemas/payment.json"
LivePublish a UCP profile at /.well-known/ucpUCP_NOT_DETECTED

No profile was found at the well-known path.

Why it matters: Without a profile, agents fall back to scraping HTML: slower, more error-prone, and far more likely to fail at checkout. UCP turns "guess what this store sells" into a contract.

Fix: Serve a JSON document at /.well-known/ucp with at minimum a ucp.version, ucp.capabilities, and ucp.services. See the developer tools page for platform-specific guides.

LiveAllow UCPCheckerBot in robots.txtUCP_BLOCKED_BY_ROBOTS

robots.txt disallows access to /.well-known/ucp for known AI agents.

Why it matters: Even if your profile exists, AI agents respect robots.txt. Disallowing them means agents will not even attempt to fetch the profile.

Fix: Add explicit Allow rules for /.well-known/ucp for each AI agent you want to support. The profile is intentionally public.

LiveLet agents reach /.well-known/ucp through your firewallUCP_BLOCKED_BY_FIREWALL

Our request for your profile was refused (401/403), usually by a firewall or bot-protection rule.

Why it matters: Many firewalls turn away anything that is not a browser by default. The profile is meant to be public, so bot-protection rules should let it through.

Fix: Add a firewall rule that lets requests for /.well-known/ucp skip bot protection. The profile must be readable without logging in.

LiveResolve connectivity / TLS issuesUCP_UNREACHABLE

The profile URL did not respond to the latest check.

Why it matters: Connection timeouts, DNS failures, or TLS handshake errors look identical to "store offline" from an agent's perspective. Continuous unreachability removes the store from agent surfaces.

Fix: Check DNS, TLS certificate validity, server availability, and any intermediate CDN configuration. Re-run a fresh check once resolved.

LiveRepair declared transport endpointsUCP_PROBE_TRANSPORT_FAILED

One or more declared transport endpoints did not respond when probed.

Why it matters: A declared endpoint that does not answer stops an agent at that step, even though the profile itself validates. Connection refused, DNS failure, TLS errors, and 5xx responses all fall here. See the Full Check Breakdown below for the specific endpoints that failed.

Fix: Open the Full Check Breakdown, expand the Capability Coverage tab, and look for transport rows marked failed/partial. Verify each endpoint resolves, returns 200, and (for MCP) accepts a tools/list request.

LivePublish Organization schema (JSON-LD) on the homepageUCP_MISSING_ORG_SCHEMA

No Organization-typed JSON-LD detected on your homepage.

Why it matters: Organization schema gives agents a structured representation of your brand identity: name, logo, social profiles, contact info, founding date. Agents use this to verify you are who you claim to be and to link your profile data to a recognizable entity.

Fix: Drop into <head> or end of <body>. Use OnlineStore (more specific) when the entire site is an ecommerce store; Organization is the generic fallback.

LiveFix broken spec or schema URLsUCP_PROBE_URL_BROKEN

One or more spec/schema URLs declared in the profile do not resolve.

Why it matters: Spec and schema URLs let agents validate request/response shapes before sending. When they 404 or time out, runtime validation degrades to "best effort" and strict agents reject the integration entirely. Common cause: copy-pasting a placeholder URL during initial profile setup. See the Full Check Breakdown for the specific URLs that failed.

Fix: Open the Full Check Breakdown, expand the UCP Conformance tab, and look for url_resolution rows marked failed. Either publish the missing schema/spec at the declared URL, or update the profile to point to a working one.

LivePublish a /llms.txt brand briefUCP_MISSING_LLMS_TXT

No /llms.txt file detected at the root of your domain.

Why it matters: llms.txt is an emerging convention (analogous to robots.txt) that lets you give AI agents a hand-written brief about your brand, product categories, return policy, and crawl preferences. Strict UCP agents do not require it, but recommendation/discovery agents increasingly read it for context.

Fix: Save as /llms.txt at your site root. Plain text, written for an LLM audience. The format is informal: these section headings are a working convention, not a spec. Replace the placeholders with your own brand details and update when policies or product lines change.

LivePublish a sitemap.xmlUCP_MISSING_SITEMAP

No sitemap.xml detected at the root of your domain.

Why it matters: Sitemaps tell agents and crawlers which pages on your store are canonical and how often they change. Without one, agents fall back to following internal links, which is slower and less complete, especially for catalog pages buried behind faceted nav.

Fix: Most ecommerce platforms generate sitemap.xml automatically. If yours does not, generate one and serve it at /sitemap.xml.

LiveAdd Open Graph meta tags to the homepageUCP_MISSING_OG_TAGS

OG tags missing or incomplete on your homepage.

Why it matters: OG tags give agents and link unfurlers (Slack, iMessage, ChatGPT) a clean title, description, and image to represent your store. Without them, shares show garbled fallback text.

Fix: Add inside <head>. og:title and og:type are the minimum; og:url, og:description, and og:image are strongly recommended.

LiveAdd a mobile viewport meta tagUCP_MISSING_VIEWPORT

No viewport meta tag detected on your homepage.

Why it matters: Mobile-originating agent sessions (ChatGPT iOS, Apple Intelligence) render store pages in browser sandboxes that respect the viewport tag. Without it, the page renders at desktop width and pinch-to-zoom UX kicks in, and agents that take screenshots of pages get unreadable images.

Fix: One line inside <head>. Modern frontend frameworks add this automatically; its absence usually means a hand-rolled or legacy template.

Questions

Is my profile stored or fetched?
No. The text you paste is read in memory with the same rules as a live check and then dropped. Nothing is fetched from your store, and nothing is saved.
Will this match what the live check says?
For everything in the document, yes: it is the same code. The live check also reads what only the live store can show: HTTPS and reachability, robots.txt, the homepage, whether each spec and schema URL resolves, and whether the services answer. Check your domain once the profile is live.
Which release is it checked against?
The release the profile declares in ucp.version. An unknown release is checked against the latest, 2026-08-25, and flagged.
Where do I learn what goes in a UCP profile?
The UCP profile guide walks through every field, with a minimal valid example.