How UCP Profiles Enable Permissionless Onboarding for Developers
UCP profiles are self‑contained JSON documents hosted at well‑known URLs that allow developers to discover capabilities and verify cryptographic identities without prior registration, API keys, or secret exchange.
The Universal Commerce Protocol (UCP) eliminates traditional integration friction by treating discovery profiles as publicly accessible configuration files. Under the Universal‑Commerce‑Protocol/ucp specification, any developer can publish a static JSON file to begin accepting secure requests, while consumers can immediately verify identities and negotiate capabilities simply by fetching a URL.
What Are UCP Discovery Profiles?
A discovery profile is a JSON document that describes a party’s cryptographic identity and commerce capabilities. According to source/discovery/profile_schema.json, the profile contains two critical sections: signing_keys (an array of JWK public keys) and ucp.capabilities (an object listing supported services). Because these profiles are served over HTTPS at standardized locations, they function as self‑sovereign identity documents that require no central registry.
How Profile Hosting Eliminates Registration Barriers
The specification mandates that business profiles are served at /.well‑known/ucp on the merchant’s domain, while platform profiles are advertised via the UCP‑Agent request header ([docs/specification/overview.md‑L70](/Universal-Commerce-Protocol/ucp/blob/main/docs/specification/overview.md#L64)). This design means:
- No out‑of‑band coordination is required to begin integration.
- Any HTTP GET to the well‑known URL returns the complete configuration.
- Developers publish a static file once, and the ecosystem discovers it automatically.
Capability Advertisement Without Coordination
Profiles advertise supported operations through the ucp.capabilities object, defined in [profile_schema.json‑L89](/Universal-Commerce-Protocol/ucp/blob/main/source/discovery/profile_schema.json#L77). This object lists services such as dev.ucp.shopping.checkout along with version arrays. When a platform fetches a business profile, it can immediately determine the intersection of supported operations and begin requests without negotiating feature flags through support tickets or dashboard configurations.
Cryptographic Trust Without Shared Secrets
Identity verification relies on JWK public keys embedded in the signing_keys array ([profile_schema.json‑L70](/Universal-Commerce-Protocol/ucp/blob/main/source/discovery/profile_schema.json#L58)). Because the profile itself serves as the trust anchor:
- Platforms verify HTTP Message Signatures against the published public key.
- No API secrets or OAuth client credentials are exchanged beforehand.
- Trust is bootstrapped from the HTTPS‑served JSON document alone.
The Permissionless Discovery Flow
The onboarding sequence defined in [overview.md‑L70](/Universal-Commerce-Protocol/ucp/blob/main/docs/specification/overview.md#L66) follows a discover‑first, negotiate‑later pattern:
- Advertisement: The requesting platform includes its profile URI in the
UCP‑Agentheader. - Fetch: The receiving party extracts the URI, performs an HTTP GET, and validates the JSON schema.
- Verification: The receiver extracts
signing_keysto verify the request’s HTTP Message Signature and matchesucp.capabilitiesto determine viable endpoints.
This flow triggers automatically upon the first request, eliminating manual onboarding checklists.
Implementation Examples
Fetching Business Profiles in Python
The following example retrieves a merchant’s profile and lists advertised capabilities. It validates basic HTTPS requirements as mandated by the specification.
import requests
import json
def fetch_profile(url: str) -> dict:
"""Retrieve a UCP profile; raise if HTTPS or caching rules are violated."""
resp = requests.get(url, timeout=5)
resp.raise_for_status()
# Very light validation – real implementations should check the JSON schema.
profile = resp.json()
return profile
def list_capabilities(profile: dict):
"""Print the capabilities advertised by the profile."""
caps = profile.get("ucp", {}).get("capabilities", {})
for cap, versions in caps.items():
versions_str = ", ".join(v.get("version", "?") for v in versions)
print(f"{cap}: {versions_str}")
# Example: a merchant’s well‑known profile
merchant_profile_url = "https://merchant.example/.well-known/ucp"
merchant_profile = fetch_profile(merchant_profile_url)
print("Merchant capabilities:")
list_capabilities(merchant_profile)
Key references: The ucp.capabilities structure is defined in source/discovery/profile_schema.json under $defs/base, and the well‑known path /.well-known/ucp is mandated in the discovery specification.
Verifying Signatures in Node.js
This middleware extracts the profile URL from the UCP‑Agent header, fetches the public keys, and validates the HTTP Message Signature without any prior shared secret.
const fetch = require('node-fetch');
const { parseSignature, verifySignature } = require('http-message-signatures');
// Extract profile URL from the UCP-Agent header
function getProfileUrl(req) {
const header = req.headers['ucp-agent'];
const match = /profile="([^"]+)"/.exec(header);
return match ? match[1] : null;
}
// Middleware that validates the signature
async function ucpAuth(req, res, next) {
const profileUrl = getProfileUrl(req);
if (!profileUrl) return res.status(400).send('Missing UCP-Agent');
const profileRes = await fetch(profileUrl);
if (!profileRes.ok) return res.status(424).send('Profile unreachable');
const profile = await profileRes.json();
const signingKey = profile.signing_keys.find(k => k.kid === req.headers['signature-input']?.kid);
if (!signingKey) return res.status(403).send('Unknown key');
const verified = verifySignature({
request: req,
key: signingKey, // JWK format
components: ['@method','@authority','@path','ucp-agent'],
});
if (!verified) return res.status(403).send('Invalid signature');
next();
}
Key references: The UCP-Agent header format is documented in docs/specification/signatures.md, and the signing_keys array schema resides in source/discovery/profile_schema.json‑L70.
Caching and Safety Requirements
To ensure profiles remain safe for automated retrieval, the specification enforces strict transport rules in [overview.md‑L38](/Universal-Commerce-Protocol/ucp/blob/main/docs/specification/overview.md#L33):
- HTTPS only: Profiles must be served over TLS; plaintext HTTP is prohibited.
- No redirects: The endpoint must return the document directly.
- Cache control: Responses must include
Cache-Control: public, max-age=60(or greater), allowing platforms to cache profiles and reduce latency for repeated interactions.
These constraints allow implementations to fetch profiles on‑the‑fly without security warnings or stale data concerns.
Summary
- UCP profiles are JSON documents hosted at
/.well-known/ucpthat containsigning_keysanducp.capabilities. - No registration is required because platforms discover profiles via the
UCP‑Agentheader and standard HTTP GET requests. - Cryptographic verification uses JWKs published in the profile, eliminating the need for pre‑shared secrets or API keys.
- Caching rules (HTTPS, no redirects,
max-age ≥ 60s) ensure safe, performant discovery at scale.
Frequently Asked Questions
What makes UCP onboarding "permissionless"?
UCP onboarding is permissionless because developers publish a static JSON profile to a well‑known URL, and any platform can immediately discover capabilities and verify signatures by fetching that URL. No API key provisioning, OAuth registration, or manual approval is required before the first secure interaction.
How does a platform discover a business's profile?
A platform discovers a business profile by performing an HTTP GET to https://<domain>/.well-known/ucp. Conversely, a business discovers a platform’s profile by reading the profile="<url>" parameter from the UCP-Agent header sent with incoming requests, as specified in docs/specification/overview.md.
Where are cryptographic keys stored in UCP?
Public keys are stored in the signing_keys array within the discovery profile, defined in source/discovery/profile_schema.json. Each key is a JWK (JSON Web Key) that includes the public key material and a kid (Key ID) for signature verification.
What security requirements exist for hosting profiles?
Profiles must be served over HTTPS without redirects, and responses must carry Cache-Control: public, max-age=60 or higher. These requirements, documented in docs/specification/overview.md, ensure that fetched profiles are authentic and safe to cache, preventing man‑in‑the‑middle attacks and stale data usage.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →