5 min read

How to Fix "UCP signing_keys missing"

Your UCP manifest validates as structurally correct. But AI shopping agents still can't trust it. Here's why - and exactly how to fix it.

Updated 29 August 2026 - the field is now called keys.

UCP v2026-08-25 removed signing_keys from the profile document and promoted keys (a JWK Set, RFC 7517) as the sole canonical field. The array contents are unchanged - it is the same JWK Set under a new name.

This matters more than a rename usually would. The profile schema allows additional properties, so if you bump your version to 2026-08-25 and leave signing_keys in place, your profile stays valid and no verifier reads it. Everything below still applies - substitute keys for signing_keys if you are on the current spec. See what v2026-08-25 breaks for the full migration.

What are UCP signing keys?

Signing keys are cryptographic public keys published in your UCP profile at /.well-known/ucp - under keys as of v2026-08-25, and under signing_keys before it. They let AI agents verify that commerce requests originated from your domain.

Without signing_keys, an AI agent has no way to confirm that a checkout request or cart update actually came from your store. The agent will either refuse to transact or fall back to a degraded experience - which means you're invisible at the moment of purchase.

This is the single most common UCP failure. In our scans, missing signing_keys shows up on the majority of profiles that otherwise pass structural validation.

Why signing_keys are NOT optional

Some validators mark signing_keys as "optional" or "recommended." This is misleading.

Any profile that supports transactional capabilities (Checkout, Payment, Cart) needs published signing keys. If your store accepts purchases, your profile needs them. Period.

A nuance worth knowing, because it is exactly what makes this failure quiet: the profile schema does not list the key field in its required set. A profile with no keys at all is still schema-valid. It just cannot be transacted with. That is why a green result from a shape-only checker is not the same as being agent-ready.

Google AI Mode, ChatGPT, and other AI shopping agents all require cryptographic verification before initiating transactions. A profile without signing_keys may still be "discovered" - but the agent won't complete a purchase.

Think of it like HTTPS certificates.

You wouldn't run an e-commerce site without TLS. You shouldn't run a UCP profile without signing_keys.

How signing_keys work (the short version)

  • Your UCP profile declares one or more public keys under keys (signing_keys before v2026-08-25)
  • When an AI agent wants to interact with your store, it fetches your manifest
  • The agent uses those public keys to verify signed requests from your domain
  • If verification fails or keys are missing, the agent aborts the transaction

How to add signing_keys to your UCP manifest

Step 1: Generate a key pair

Use Ed25519 (recommended by the UCP spec) or ES256:

# Generate Ed25519 key pair
openssl genpkey -algorithm Ed25519 -out ucp_private.pem
openssl pkey -in ucp_private.pem -pubout -out ucp_public.pem

# Extract the public key in JWK format
# You'll need the key ID (kid) and the base64url-encoded x coordinate

Step 2: Add the key to your profile

Your /.well-known/ucp document publishes the key at the root, as a sibling of the ucp object. On v2026-08-25 and later that field is keys:

{
  "ucp": {
    "version": "2026-08-25",
    "services": {
      "dev.ucp.shopping": {
        "version": "2026-08-25",
        "spec": "https://ucp.dev/specification/overview/",
        "rest": {
          "endpoint": "https://yourstore.com/api/ucp",
          "schema": "https://ucp.dev/services/shopping/rest.openapi.json"
        }
      }
    },
    "capabilities": [
      {
        "name": "dev.ucp.shopping.checkout",
        "version": "2026-08-25",
        "spec": "https://ucp.dev/specification/checkout/",
        "schema": "https://ucp.dev/schemas/shopping/checkout.json"
      }
    ]
  },
  "keys": [
    {
      "kid": "2026-08-primary",
      "kty": "OKP",
      "crv": "Ed25519",
      "x": "your-base64url-encoded-public-key-here",
      "use": "sig"
    }
  ],
  "payment": {
    "handlers": [
      {
        "id": "stripe",
        "name": "Stripe",
        "version": "2026-08-25",
        "spec": "https://ucp.dev/specification/payment/"
      }
    ]
  }
}

On v2026-04-08 the same array is named signing_keys and sits in the same place. Before that it was nested inside the ucp object.

One extra rule if you are doing Web Bot Auth.

For keys used in dual-audience (WBA) signatures, kid MUST be the key's JWK SHA-256 Thumbprint (RFC 7638), so that UCP-Agent and Signature-Agent lookups resolve to the same key. Otherwise kid can be any stable string.

Step 3: Sign your outgoing requests

When your store responds to AI agent requests, sign the payload with your private key. The agent verifies using the public key from your manifest.

Step 4: Validate the fix

After adding signing_keys, run a full UCP validation that includes network-level testing. A structural check won't catch key mismatches. You need structural (is the field present and well-formed?), network (can the agent fetch and parse the key?), and SDK/simulation (can the agent actually verify a signed request?).

Common signing_keys mistakes

  • Wrong key format. The spec requires JWK format. Raw PEM or hex-encoded keys will fail.
  • Missing key ID (kid). Agents use the kid field to identify which key to use. Omit it and verification breaks.
  • Key rotation without updating the manifest. If you rotate keys, update the manifest immediately. A stale manifest with revoked keys is the same as no keys at all.
  • Only testing structural validation. Your validator says "PASS" but the key is malformed or the signing implementation is wrong. Always test with an AI agent simulator.
  • Using the same key across multiple domains. Each origin should have its own signing key. Cross-domain key reuse breaks the origin verification model.

How to verify your fix actually works

Don't rely on structural-only validators. You need a tool that tests all four levels:

  1. Structural: is the key field present, under the name your declared version actually uses?
  2. Rules: are the key format and fields correct per spec?
  3. Network: can agents fetch and parse the key over HTTPS?
  4. SDK/Simulation: can an AI agent actually verify a signed request from your domain?

See the four levels of UCP validation for why a structural pass isn't enough.

Check your signing_keys in one scan

Run a free 4-level validation - structural, rules, network, and full agent simulation - to confirm agents can actually verify a signed request from your domain.

Validate Your Store Free