Order Webhooks
After the Playground's agent places an order with your store, your store can send signed order events back. This page covers where to send them, how the Playground verifies them, what it answers, and where to see each delivery in the run.
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 2026-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: the host of the profile in
UCP-Agentmust be the store's host (with or withoutwww.), or a host your own UCP profile names as a service endpoint. Another store on the same parent domain does not count. 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 (unknown_order), or the signer does not own it (ownership_mismatch). The Playground records an order once yourcomplete_checkoutanswer reaches it, so anorder.createdsent before that answer getsunknown_order: send webhooks after responding, and retry this one with backoff.
event_id, and retry failed deliveries. The Playground acknowledges quickly with a 2xx and records each delivery. Seeing your webhooks in a run
Every delivery for an order placed in a run shows in that run's Trace, after the call that returned the order, as a line such as Store sent order.created · signed · accepted, or the reason it was refused. Open the line for the event id and type, the host and key that signed it, whether the signature verified, whether the signer owns the order, our answer, the attempt, and how long after checkout it arrived. Deliveries that arrive after the run ended still show when the run is opened again, and Info counts them under Order updates from the store. A shared run shows the type, status and timing only, never the order body.
Something wrong on this page?