# /.well-known/ucp - Definition of the UCP Business Profile

> What the UCP business profile contains, which members are required, the hosting rules, and why keys moved to keys[].

Source: https://angeo.dev/well-known-ucp-definition/
Updated: 2026-10-17

Canonical definition

# /.well-known/ucp - Definition of the UCP Business Profile

**`/.well-known/ucp` is the fixed URL where a business publishes its UCP profile: a public JSON document declaring the protocol version it speaks, the services and capabilities it supports, its payment handlers, and the public keys used to verify its signed responses.** It is the single entry point of the protocol - an agent that cannot fetch and parse this file cannot transact with the store at all.

**In one sentence**
A store's machine-readable business card for AI agents, served unauthenticated over HTTPS at a path every agent already knows to look for.

## What the document contains

```
{
  "ucp": {
    "version": "2026-08-25",
    "services": {
      "dev.ucp.shopping": [
        {
          "version": "2026-08-25",
          "spec": "https://ucp.dev/2026-08-25/specification/overview/",
          "transport": "rest",
          "endpoint": "https://store.example.com/ucp/v1",
          "schema": "https://ucp.dev/2026-08-25/services/shopping/rest.openapi.json"
        }
      ]
    },
    "capabilities": {
      "dev.ucp.shopping.catalog.search": [
        {
          "version": "2026-08-25",
          "spec": "https://ucp.dev/2026-08-25/specification/shopping/catalog/search",
          "schema": "https://ucp.dev/2026-08-25/schemas/shopping/catalog_search.json"
        }
      ]
    },
    "payment_handlers": {}
  },
  "keys": [
    {
      "kid": "poqkLGiymh_W0uP6PZFw-dvez3QJT5SolqXBCW38r0U",
      "kty": "OKP", "crv": "Ed25519",
      "x": "JrQLj5P_89iXES9-vFgrIy29clF9CC_oPPsw3c5D0bs",
      "use": "sig", "alg": "EdDSA"
    }
  ]
}
```

## Required members

| Member | Status | Note |

| `ucp.version` | Required | Date format, e.g. `2026-08-25` |

| `ucp.services` | Required | Must be present even when empty - and must serialize as `{}`, never `[]` |

| `ucp.payment_handlers` | Required | Same rule |

| `ucp.capabilities` | Optional | Legal to omit, but a store with none has nothing to sell an agent |

| `keys` | Optional | Top-level, sibling of `ucp`. An RFC 7517 JWK Set |

| `ucp.supported_versions` | Optional | Map of older versions to complete profiles you host yourself |

**The empty-registry trap**
All three registries are JSON *objects* keyed by reverse-domain name. An empty PHP or JavaScript array encodes as `[]`, which fails schema validation with `[] is not of type 'object'`. A store with no payment handlers must emit `"payment_handlers": {}`.

## Hosting rules

- Served over **HTTPS**. Plain HTTP is rejected.

- `Content-Type: application/json`.

- `Access-Control-Allow-Origin: *` - agents fetch it cross-origin.

- `Cache-Control: public` with `max-age` of at least 60 seconds.

- **No 3xx redirects.** A platform does not follow them when fetching a profile.

- Public and unauthenticated by design. Never put secrets, internal URLs or staff contacts in it.

## Keys live in `keys[]`, not `signing_keys[]`

Protocol version 2026-04-08 published signing keys under `signing_keys[]`. Since 2026-08-25 the canonical field is the top-level `keys[]` array - an RFC 7517 JWK Set, which makes the profile simultaneously a valid JWK Set a signer can reuse as its [Web Bot Auth](https://angeo.dev/web-bot-auth-definition/) key source.

A profile that advertises 2026-08-25 while still using `signing_keys[]` is not rejected outright - but no verifier reads that field, so it publishes no usable key at all. The reverse also holds: a key is not effectively *revoked* until it is absent from `keys[]`, which is why rotation goes new-key-first.

## Serving it from Magento 2

The path contains a dot segment, and Magento's router forbids dots in front names, so a static file or a naive route will not work. Two failure modes are common:

- A file dropped at `pub/.well-known/ucp` is served by nginx as `application/octet-stream` with no CORS headers - it fails validation.

- On LiteSpeed, `PATH_INFO` is frequently empty for dot-segment paths, so a router matching only `getPathInfo()` returns 404.

[angeo/module-ucp](https://angeo.dev/modules/ucp/) serves the endpoint from a PHP controller with correct headers and multi-source path matching, and ships `bin/magento angeo:ucp:validate` to check the generated profile - including [authority binding](https://angeo.dev/ucp-authority-binding/), which platforms enforce silently.

## How to check any store's profile

```
curl -sI https://store.example.com/.well-known/ucp
# HTTP/2 200
# content-type: application/json
# access-control-allow-origin: *
# cache-control: public, max-age=300

curl -s https://store.example.com/.well-known/ucp | python3 -m json.tool
```

## Questions

Does the UCP profile have to be at exactly /.well-known/ucp?
Yes for a business. That path is where every agent looks. Platforms publish their own profile at a URI they advertise in the `UCP-Agent` header instead.

Is the UCP profile public?
Yes, and unauthenticated by design. Everything in it is world-readable, so it must contain no secrets, no internal hostnames and no private key material.

What happens if my UCP profile returns a redirect?
The fetch fails. A platform must not follow 3xx responses when fetching a profile, so an http-to-https or trailing-slash redirect makes the store undiscoverable.

Should I declare a UCP capability before the endpoint exists?
No. Negotiation activates whatever both sides declare, so an advertised capability with no endpoint behind it produces failing requests rather than a graceful skip.

Why does my empty UCP profile fail schema validation?
Almost always the empty-registry encoding. `services`, `capabilities` and `payment_handlers` are JSON objects, and an empty array encodes as `[]` instead of `{}`.

## Related

- [UCP - definition](https://angeo.dev/ucp-definition/)

- [Authority binding - definition and algorithm](https://angeo.dev/ucp-authority-binding/)

- [Web Bot Auth - definition](https://angeo.dev/web-bot-auth-definition/)

- [Module: UCP merchant profile for Magento 2](https://angeo.dev/modules/ucp/)

- [UCP readiness checklist for Magento 2](https://angeo.dev/ucp-readiness-checklist-magento/)

- [UCP for Magento 2  -  complete guide](https://angeo.dev/magento-ucp/)

Verified 28 August 2026 against the official specification repository at tag v2026-08-25 (profile.json, ucp.json, capability.json, service.json). Disclosure: we publish the open-source UCP modules referenced above.

## More on this topic

- [What Is UCP? Google's Commerce Protocol Explained](https://angeo.dev/what-is-ucp-for-store-owners/)
- [Best Magento 2 UCP Modules Compared (2026)](https://angeo.dev/magento-ucp-modules-compared/)
- [UCP Catalog Service for Magento 2](https://angeo.dev/modules/ucp-catalog/)

## Sources

- [Universal Commerce Protocol - specification](https://ucp.dev/)
- [UCP repository on GitHub](https://github.com/Universal-Commerce-Protocol/ucp)
- [RFC 8615: Well-Known URIs](https://www.rfc-editor.org/rfc/rfc8615.html)
- [RFC 7517: JSON Web Key (JWK)](https://www.rfc-editor.org/rfc/rfc7517.html)

Links checked 23 September 2026.
