Module reference

UCP Profile for Magento 2 — module reference

Covers angeo/module-ucp 2.2.1 · Checked 16 October 2026 · MIT licensed

UCP Profile publishes a Universal Commerce Protocol business profile at /.well-known/ucp. AI shopping agents — Google AI Mode and Gemini, and other UCP platforms — read it to learn what your store can do and where to call it.

The profile follows UCP spec 2026-08-25 and its official JSON Schemas. On its own, this module only describes the store. The modules that serve the capabilities are UCP Catalog (search and lookup) and UCP Checkout (checkout and orders).

What it does

  • Builds the profile: services, capabilities, extensions, payment handlers, supported versions and public keys.
  • Publishes signing keys in the top-level **keys[] JWK Set (RFC 7517), public keys only**. ES256, ES384 and Ed25519 are supported, with RFC 7638 thumbprint key ids and rotation without downtime.
  • Checks authority binding locally. Since 2026-08-25 a platform must reject an entity whose schema host does not match its namespace — and it does so silently. angeo:ucp:validate runs the same algorithm, so you find out first.
  • Advertises REST by default and, optionally, an MCP binding.
  • Verifies RFC 9421 signatures on requests that arrive at your UCP endpoints (2.1.0).

How the endpoint is served

/.well-known/ucp is served by a PHP controller, not a static file. The spec needs Content-Type: application/json and CORS headers, which a static file without an extension cannot send without web server changes.

The stock Magento nginx config ends with try_files $uri $uri/ /index.php$is_args$args, so the request reaches Magento and a custom router answers it. No nginx or Apache change is needed.

If your host added a rule such as location ~ /\. { deny all; }, it blocks all dot-paths. Then add a one-line allow for ^~ /.well-known/. Do not leave a static file at pub/.well-known/ucp: nginx would serve it first, with the wrong type and no CORS.

The controller sends CORS headers, Cache-Control: public, max-age=300, X-Content-Type-Options: nosniff, X-Frame-Options: DENY and Referrer-Policy: no-referrer. It answers OPTIONS with 204. When the module is off, it returns 404, so the store does not advertise UCP.

Requirements

Magento2.4.6+ (Open Source, Mage-OS or Adobe Commerce) — magento/framework >=103.0.6 <104
PHP8.1 – 8.5 — ~8.1.0||~8.2.0||~8.3.0||~8.4.0||~8.5.0
PHP extensionscurl, json, openssl

Installation

composer require angeo/module-ucp
bin/magento module:enable Angeo_Ucp
bin/magento setup:upgrade
bin/magento setup:di:compile                # production mode only
bin/magento cache:flush

Generate a signing key and check the endpoint:

bin/magento angeo:ucp:keys:generate
curl -sI https://yourstore.com/.well-known/ucp
# HTTP/2 200
# content-type: application/json
# access-control-allow-origin: *
# cache-control: public, max-age=300

Capabilities: declared and served

You switch capabilities on in Stores → Configuration → Angeo → UCP (Universal Commerce Protocol). Since 2.2.0, a switch alone does not advertise cart, checkout, order, fulfillment, discount or buyer consent. They appear in the profile only when an installed module serves them:

CapabilityServed by
dev.ucp.shopping.catalog.search / .lookupUCP Catalog
dev.ucp.shopping.checkout + .discount + .fulfillmentUCP Checkout 1.0+ (MCP tools: UCP Checkout over MCP)
dev.ucp.shopping.order (Get Order and webhooks)UCP Checkout 1.1+
dev.ucp.shopping.permalinkA stock Magento cart URL
Cart, buyer consentNot available yet

bin/magento angeo:ucp:validate lists switches that are on but have no effect. A module registers what it serves through the implementations argument of Angeo\Ucp\Model\Config in its di.xml.

REST endpoint. Leave Transport → REST Endpoint URL empty to advertise {baseUrl}/ucp/v1, where the catalog and checkout modules answer.

Signing keys

CommandWhat it does
bin/magento angeo:ucp:keys:generateGenerate a UCP signing keypair. The public JWK is saved to config
bin/magento angeo:ucp:validateValidate the generated UCP profile against the

Which key type to choose:

  • ES256 (default) — accepted by every counterparty. AP2 mandate signing needs it. Start here.
  • Ed25519 — recommended by the spec for Web Bot Auth on HTTP. Needs ext-sodium. It does not cover AP2, so publish both if you sign mandates.
  • ES384 — for a stricter curve policy.

Rotate in this order, so there is no gap:

bin/magento angeo:ucp:keys:generate --add    # publish the new key next to the old one
# move signing to the new key id, let caches expire
bin/magento angeo:ucp:keys:generate --force  # keep only the newest key

The private key never leaves the server. The profile reads public keys only. If a private JWK member (d, p, q, dp, dq, qi, oth, k) is found in stored config, it is removed before serving, with a warning to rotate.

Inbound signature verification (2.1.0)

The profile publishes keys. Since 2.1.0 the module also checks RFC 9421 signatures on requests that arrive at your UCP endpoints. Set the mode under Request Security:

ModeSigned and validSigned and invalidUnsigned
disabled (default)servedservedserved
optionalserved401served
requiredserved401401

Start with optional. Invalid signatures are refused, but missing ones are allowed, so you can see in the log which agents sign. Endpoint modules use this through Api\SignatureVerifierInterface. Signing your own responses is not done yet.

Configuration reference

All settings are under Stores → Configuration → Angeo → UCP (Universal Commerce Protocol). The table shows each field, its config path (for bin/magento config:set) and its default value.

General (1)
SettingConfig pathDefault
Advertise UCP Profileangeo_ucp/general/enabledNo
Declared Root Capabilities (9)
SettingConfig pathDefault
Catalog Search (dev.ucp.shopping.catalog.search)angeo_ucp/capabilities/catalog_search_enabledNo
Catalog Lookup (dev.ucp.shopping.catalog.lookup)angeo_ucp/capabilities/catalog_lookup_enabledNo
Cart (dev.ucp.shopping.cart)angeo_ucp/capabilities/cart_enabledNo
Checkout (dev.ucp.shopping.checkout)angeo_ucp/capabilities/checkout_enabledNo
Order (dev.ucp.shopping.order)angeo_ucp/capabilities/order_enabledNo
Identity Linking (dev.ucp.common.identity_linking)angeo_ucp/capabilities/identity_linking_enabledNo
Identity Linking OAuth Scopesangeo_ucp/capabilities/identity_linking_scopes—
Permalink (dev.ucp.shopping.permalink)angeo_ucp/capabilities/permalink_enabledNo
Permalink Endpoint URLangeo_ucp/capabilities/permalink_endpoint—
Declared Extensions (3)
SettingConfig pathDefault
Fulfillment (dev.ucp.shopping.fulfillment)angeo_ucp/extensions/fulfillment_enabledNo
Discount (dev.ucp.shopping.discount)angeo_ucp/extensions/discount_enabledNo
Buyer Consent (dev.ucp.shopping.buyer_consent)angeo_ucp/extensions/buyer_consent_enabledNo
Transport (2)
SettingConfig pathDefault
REST Endpoint URLangeo_ucp/transport/rest_endpoint—
MCP Endpoint URLangeo_ucp/transport/mcp_endpoint—
Signing Keys (1)
SettingConfig pathDefault
Public JWK Set (read-only)angeo_ucp/keys/signing_key_jwk—
Advanced Profile Declarations (2)
SettingConfig pathDefault
Supported Versions (JSON)angeo_ucp/advanced/supported_versions—
Payment Handlers (JSON)angeo_ucp/advanced/payment_handlers—
Request Security (1)
SettingConfig pathDefault
Inbound Signature Verificationangeo_ucp/security/inbound_signature_modedisabled

Upgrading from 1.x

1.4.0 still works: it publishes a valid 2026-04-08 profile. 2.x adopts 2026-08-25, where the protocol version, the key field and the capability URLs move together.

1.x (2026-04-08)2.x (2026-08-25)
Signing keyssigning_keys[]**keys[]** (JWK Set)
Capability schemaoptionalrequired
schema origin checkprefix on ucp.devauthority-binding algorithm
Key typesP-256 onlyP-256, P-384, Ed25519
Key idrandomRFC 7638 thumbprint
composer require angeo/module-ucp:^2.0
bin/magento setup:upgrade && bin/magento cache:flush
bin/magento angeo:ucp:validate

Existing keys keep working and move to keys[]. If a platform already integrates with your old profile, save a copy and declare it under Advanced → Supported Versions.

FAQ

Is the profile public?

Yes. The UCP spec requires a public, unauthenticated profile. Never put secrets, internal URLs or admin contacts in it.

Why does my profile not list checkout even though I switched it on?

Since 2.2.0 a capability appears only when an installed module serves it. Install UCP Checkout, then run angeo:ucp:validate.

Do I need to change nginx?

Not with the stock Magento config. Only if your host added a rule that blocks paths starting with a dot. Then allow /.well-known/.

Which key type should I use?

Start with ES256. Add Ed25519 if you want Web Bot Auth interop. Publish both if you sign AP2 mandates.

My CDN still shows the old profile. Why?

The profile is cacheable for five minutes. Purge /.well-known/ucp on your CDN or Varnish after rotating keys or changing settings.

This page was written from the README.md, composer.json and etc/*.xml files of tag 2.2.1, read on 16 October 2026. Settings, commands and defaults come straight from that code. If a newer release is out, the README on GitHub wins.