Agent Identity & Webhooks
The Playground identifies itself cryptographically on every request and verifies the order webhooks your store sends back. This page explains how to verify the Playground's identity and how to deliver signed order events to it.
The agent profile
Every request the Playground makes carries a UCP-Agent header pointing at its public profile:
UCP-Agent: profile="https://ucpplayground.com/.well-known/ucp-agent" That document is a standard UCP platform profile — a ucp member declaring the capabilities the Playground supports, plus a root-level keys array: a JWK Set of public EC keys used to verify its request signatures.
{
"ucp": {
"version": "2026-08-25",
"services": {},
"capabilities": { "dev.ucp.shopping.checkout": [ /* ... */ ] },
"payment_handlers": {}
},
"keys": [
{ "kid": "...", "kty": "EC", "crv": "P-256", "x": "...", "y": "...", "use": "sig", "alg": "ES256" }
],
"signing_keys": [ /* the same set, for verifiers still on v2026-04-08 */ ]
}keys is a sibling of ucp at the document root — not nested inside it. Verifiers resolve a key as profile.keys and match it to a request by kid. v2026-08-25 made keys the canonical field, replacing signing_keys; the Playground publishes both, and reads either from your profile, so verification works whichever version you are on. Verifying the Playground's requests
Requests are signed with HTTP Message Signatures (RFC 9421, ECDSA P-256 / ES256), in the default shape of the UCP signatures specification. A signed request looks like this:
POST /ucp/v1/catalog/search HTTP/1.1
Content-Type: application/json
UCP-Agent: profile="https://ucpplayground.com/.well-known/ucp-agent"
Idempotency-Key: <uuid>
Content-Digest: sha-256=:<base64 sha-256 of body>:
Signature-Input: sig1=("@method" "@authority" "@path" "ucp-agent" "idempotency-key" "content-digest" "content-type");created=<unix time>;keyid="<kid from keys>"
Signature: sig1=:<base64 signature>:The signature label is sig1 and its only parameters are created and keyid. There is no tag and no alg: UCP defines no tag of its own, and the algorithm comes from the published key (kty/crv). The covered components follow the request: @query when there is a query string, idempotency-key when that header is sent, content-digest and content-type when there is a body. To verify one:
- Read the profile URL from the
UCP-Agentheader and fetch it over HTTPS. - Parse
Signature-Inputfor the covered components and thekeyid, and check the components cover the method, authority and path, plus each of the headers above that the request carries. - Find the matching key in
keysbykid. - Confirm
Content-Digestequals the SHA-256 of the raw body. - Reconstruct the signature base and verify the signature against the public key.
Verification is optional — the spec makes signing a SHOULD, and you may process unsigned requests — but verifying lets you trust the caller's identity rather than the header string alone.
This applies to UCP requests over MCP and REST. A store-page (WebMCP) run is different: it loads your page in an ordinary browser and uses the tools the page registers, so those page loads carry no UCP-Agent header or request signature.
Sending order webhooks to the Playground
When the Playground completes an order with your store, it can receive your order events. The delivery URL is advertised as config.webhook_url on the order capability in its profile:
"dev.ucp.shopping.order": [
{
"version": "2026-08-25",
"spec": "https://ucp.dev/2026-08-25/specification/order",
"schema": "https://ucp.dev/2026-08-25/schemas/shopping/order.json",
"config": { "webhook_url": "https://ucpplayground.com/webhooks/ucp/orders" }
}
]Your store must sign every webhook. Send these headers, signed with a key published in your own store profile's keys (or signing_keys if you are still on v2026-04-08 — both are read):
POST /webhooks/ucp/orders HTTP/1.1
Content-Type: application/json
UCP-Agent: profile="https://your-store.example/.well-known/ucp"
Content-Digest: sha-256=:<base64 sha-256 of body>:
Signature-Input: sig1=("@method" "@authority" "@path" "ucp-agent" "content-digest" "content-type");keyid="<your-kid>"
Signature: sig1=:<base64 signature>:
{"id":"order_abc123","event_id":"evt_123","type":"order.updated", ...}How the Playground verifies your webhook
- Signature — resolves your profile from
UCP-Agent, matches thekidin yourkeys, checks the body digest, and verifies the RFC 9421 signature. - Ownership — confirms the signer owns the referenced order. A webhook signed by a business that did not place the order is rejected, even with a valid signature.
Responses you can expect:
202 Accepted— verified and recorded.400 Bad Request— the signature verified but the body names no order.401 Unauthorized— missingUCP-Agent, unknown key, digest mismatch, or invalid signature.403 Forbidden— the order is unknown, or the signer does not own it.
event_id, and retry failed deliveries. The Playground acknowledges quickly with a 2xx and records each delivery for inspection.