API Reference
Reference

API Reference

The machine-readable contract is the source of truth: openapi/v1.yaml (OpenAPI 3.1). This page walks the surface, group by group.

Basics

  • Base URL — https://ucpplayground.com/api/v1. Versioning is path-based; there is no version header.
  • Auth — Authorization: Bearer <token> with a scoped token. Every endpoint declares its required ability (the x-required-ability extension in the contract); the ability is listed per route below.
  • IDs — public identifiers are ULIDs.
  • Team context — a team token operates in its team's workspace; writes require the token's team role to be admin or owner.
  • Rate limits — POST /chat is limited per minute according to your plan tier; a 429 means back off and retry. The rest of the surface shares a general per-user limit.

Agent

RouteAbility
GET /models—
POST /chatagent:run

GET /models lists the selectable model catalogue (id, display_name, provider). POST /chat runs a full agent session — blocking, up to ~120s. Provide a domain for automatic endpoint discovery, a saved target, or an explicit endpoint; continue an earlier session with session_id. Set runtime to local to route merchant-bound requests through a connected local runner. Pass buyer_context (address_country, currency, language, optional address_region and postal_code) to set the spec context signals carried on catalog searches; omit it to use the context saved for your account or workspace, or send {} to send none.

The API runs sessions over UCP (MCP or REST). Store-page (WebMCP) runs are on the Agent page only.

bash
curl -X POST https://ucpplayground.com/api/v1/chat \
  -H "Authorization: Bearer $UCP_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "claude-sonnet-4-5",
    "domain": "flower-shop.local",
    "message": "find me a bouquet under $50"
  }'

The response is a ChatResult (trimmed):

json
{
  "session_id": "01JX3Y6M8Q9W2E5R7T1A4S6D8F",
  "endpoint": "https://.../mcp",
  "messages": [ { "role": "assistant", "content": "I found ..." } ],
  "tool_calls": [ { "name": "search_shop_catalog", "arguments": { "query": "bouquet" } } ],
  "tokens": { "total": 8412, "prompt": 7630, "completion": 782 },
  "steps_completed": ["search", "details", "cart"],
  "outcome": "cart_created",
  "completion_rate": 75,
  "turn_count": 4,
  "duration_ms": 21930,
  "error": null,
  "error_type": null,
  "event_stream": [ "..." ],
  "use_rest_transport": false
}

ChatResult fields

FieldMeaning
session_idULID of the stored session — pass back as session_id to continue, or read it via GET /sessions/{ulid}.
endpointThe resolved endpoint the session ran against.
messagesThe turn's conversation messages.
tool_callsEvery tool call the agent made, with arguments and results.
tokenstotal / prompt / completion counts for the run.
steps_completedFunnel step keys completed so far (see Funnel & Outcomes).
outcomeThe session's outcome classification (e.g. purchase_completed).
completion_ratePercent of the resolved funnel completed.
turn_countModel invocations so far.
duration_msWall-clock duration of the run.
error / error_typeSet when a transport or run failure occurred. error_type is persisted on the session, so it also appears in session reads and collection-run summaries.
event_streamThe ordered event log that powers the replay's Wire log view.
use_rest_transportWhether the session fell back to the REST transport.
Note

A session that fails still returns 200 — the failure is data, not an HTTP error. Reserve non-2xx handling for validation (422), usage limits (429), and tool-discovery failures (502).

Sessions

RouteAbility
GET /sessionssessions:read
GET /sessions/{ulid}sessions:read

GET /sessions lists your workspace's sessions, filterable by domain, outcome, and model. Results come back as a standard paginator object — data plus page metadata — controlled with page and per_page (default 20, max 100). GET /sessions/{ulid} returns the full replay detail, including the negotiation readout and buyer_context the session started with (both null on sessions recorded before 0.12.0). Both routes return vertical: lodging when the store declared dev.ucp.lodging at connect, otherwise shopping. It says which funnel the stored steps and outcome read against (see Funnel & Outcomes):

bash
curl https://ucpplayground.com/api/v1/sessions/01JX3Y6M8Q9W2E5R7T1A4S6D8F \
  -H "Authorization: Bearer $UCP_TOKEN"
json
{
  "id": "01JX3Y6M8Q9W2E5R7T1A4S6D8F",
  "model": "claude-sonnet-4-5",
  "model_display_name": "Claude Sonnet 4.6",
  "store_domain": "flower-shop.local",
  "mcp_endpoint": "https://.../mcp",
  "outcome": "cart_created",
  "vertical": "shopping",
  "completion_rate": 75,
  "steps_completed": ["search", "details", "cart"],
  "total_tokens": 8412,
  "prompt_tokens": 7630,
  "completion_tokens": 782,
  "total_duration_ms": 21930,
  "turn_count": 4,
  "messages": [ "..." ],
  "tools_called": [ "..." ],
  "tools_available": [ "..." ],
  "event_stream": [ "..." ],
  "schema_quality": { "overall": { "score": 88, "grade": "B" }, "tools": [ "..." ] },
  "negotiation": { "platform_version": "2026-08-25", "merchant_version": "2026-08-25", "version_state": "match", "variant": "shopping", "summary": { "declared": 7, "active": 7, "passthrough": 0, "excluded": 0 }, "capabilities": [ "..." ] },
  "buyer_context": { "address_country": "GB", "currency": "GBP", "language": "en" },
  "created_at": "2026-08-11T09:12:44Z"
}

Inspect

RouteAbility
POST /inspect/discoverinspect
POST /inspect/toolsinspect
POST /inspect/callinspect

The Inspector, headless. discover resolves a domain's /.well-known/ucp manifest to endpoints and capabilities, plus the negotiation readout — version selection and the capability intersection against this platform, with a status and reason per capability; tools lists an endpoint's MCP tools with a schema-quality grade (provide exactly one of endpoint, domain, or target); call invokes one tool by hand with endpoint, name, and arguments, returning the raw result.

bash
curl -X POST https://ucpplayground.com/api/v1/inspect/discover \
  -H "Authorization: Bearer $UCP_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "domain": "flower-shop.local" }'

Targets

RouteAbility
GET /targets · GET /targets/{id}targets:read
POST /targets · PATCH /targets/{id} · DELETE /targets/{id}targets:write

Saved stores, reusable across runs. Create from a domain, or pass from_session to seed the domain and endpoints from a past run. One domain, one target, per workspace — a duplicate POST returns 409. See Saved Targets.

Collections

RouteAbility
GET /collections · GET /collections/{id}collections:read
POST /collections · PATCH /collections/{id} · DELETE /collections/{id} · POST /collections/{id}/clonecollections:write

A collection is stores × models × sequences, plus optional schedule (cron), webhook_url, and server-evaluated assertions. Config changes bump the collection's version. Setting a webhook URL returns webhook_secret once — store it. See Creating Collections.

Runs

RouteAbility
POST /collections/{id}/runcollections:write
GET /collections/{id}/runs · GET /collection-runs/{id}collections:read
GET /collection-runs/{id}/pdfreports:read

Triggering a run fans out one queued session per store × model × sequence and returns a run_id to poll. The run detail carries the per-session matrix and summary; the PDF route renders the benchmark report.

Runner

RouteAbility
POST /runner/claim · POST /runner/resultrunner

The local-runner wire protocol (v0.1): a runner long-polls claim with its target allowlist and delivers each job's outcome to result. Runner tokens carry the runner ability and nothing else. You only touch these routes if you are implementing a runner.

Webhooks

A collection can name a webhook URL; on run completion the Playground POSTs a JSON payload with two headers:

  • X-Playground-Event: collection_run.completed
  • X-Playground-Signature: sha256=<hex> — HMAC-SHA256 of the exact raw request body with your collection's webhook secret.

Verify by computing the HMAC over the raw bytes before parsing — re-serialized JSON will not match. Redirects are never followed on delivery; non-2xx responses are retried.

Tip

Start from the API Quickstart for a working first request, and Errors & Diagnostics for every error shape the API returns.