Documentation

Simulation only. Estimate, not a reservation. Demo Equipment Hire is fictional; all data is synthetic and every tool is read only. No tool creates a reservation or holds stock.

Contents

The four tools

ToolRetrieval pageRequired parametersOptional parameters
search_catalog/read/catalogquerycategory (cleaning, garden, power_tools, access, decorating, heating_and_drying), limit (1-10, default 5)
search_knowledge/read/knowledgequerytopic (delivery, deposits, collection, returns, cleaning, cancellation, payment, general), limit (1-10, default 5)
check_availability/read/availabilityproductId, quantity, startDate, endDatenone
calculate_quote/read/quoteproductId, quantity, startDate, endDate, fulfillmentzoneId (required when fulfillment is delivery; not allowed for pickup)

Search text (query) is trimmed, whitespace is normalized and it must be 1-200 characters. Product and zone identifiers are lowercase letters, digits, hyphens or underscores (at most 64 characters). quantity is an integer 1-10. fulfillment is pickup or delivery. One product per estimate. Unknown fields are rejected: there is no way to choose a tenant, a URL or a query.

Dates and quantities

JSON API

POST https://sandbox.webcanspeak.com/api/v1/tools/{toolName} with a JSON object of the tool's fields returns the result envelope as JSON. It runs the same validation and handlers as the retrieval pages, so the same input gives the same business result.

curl -s -X POST https://sandbox.webcanspeak.com/api/v1/tools/check_availability \
  -H 'content-type: application/json' \
  -d '{"productId":"carpet-cleaner","quantity":2,"startDate":"2026-10-16","endDate":"2026-10-18"}'

The envelope has schemaVersion, simulation, business, tool, status (ok, needs_input or error), requestId, generatedAt, data, sources, warnings and error.

Plain-text retrieval pages

Four GET pages answer in UTF-8 plain text (text/plain; charset=utf-8). Parameters go in the query string; only public demonstration values belong there. Parsing is strict and happens before any work:

Dynamic answers carry Cache-Control: no-store, X-Robots-Tag: noindex and Referrer-Policy: no-referrer.

The text format (wcs-read/1)

Every line is label: value, split at the first colon and space. Labels are the JSON paths of the result envelope. The document always starts with format and notice and ends with end: wcs-read/1 (a missing last line means the answer was cut off).

The optional challenge

Every retrieval page accepts challenge: 16-64 ASCII letters, digits or hyphens (pattern ^[A-Za-z0-9-]{16,64}$). A valid challenge is repeated in the challenge line of the answer, which lets a client correlate a retrieval it started. An invalid one is refused with HTTP 400. It is not authentication and not proof of freshness, it is not used to compute the result, and it is never logged or recorded.

Errors and HTTP statuses

ResultHTTP statusMeaningRetryable
ok200The tool completed (an empty search or insufficient stock is still ok)-
needs_input422Required business fields are missingno
invalid_input400Schema or business validation failedno
not_found404Unknown or unpublished product or sourceno
unsupported_zone422Requested delivery zone is not servedno
rate_limited429Request allowance exceededyes
upstream_unavailable503Simulator or database could not complete the operationyes
upstream_timeout504Internal deadline exceededyes
invalid_upstream_response502Connector response failed validationno
stale_data503Operational snapshot exceeded its allowed ageyes
internal_error500Unexpected failure with no safe detailed explanationno

The kill switch answers HTTP 503 with upstream_unavailable while documentation and source pages stay available. The retrieval pages and the JSON API use this one status mapping. Error messages are fixed, safe text; no stack traces, internal addresses or raw dependency errors are ever shown, and no price or availability line appears on an error.

Worked examples

These are produced by the same code that serves the pages, and a test compares each one with what the real service returns for the request shown. The request ID and every time stamp (generatedAt, observedAt, expiresAt) are illustrative and differ on every real answer; the revisions shown are those of the seeded demonstration data.

A successful estimate

Status ok, HTTP 200. The amounts are integer cents; the refundable deposit is separate and not taxed.

GET https://sandbox.webcanspeak.com/read/quote?productId=carpet-cleaner&quantity=2&startDate=2026-10-16&endDate=2026-10-18&fulfillment=delivery&zoneId=central
HTTP status 200

format: wcs-read/1
notice: Simulation only. Estimate, not a reservation.
schemaVersion: 1.0
simulation: true
business: Demo Equipment Hire
tool: calculate_quote
transport: read
status: ok
httpStatus: 200
requestId: 00000000-0000-4000-8000-000000000000
generatedAt: 2026-10-04T09:00:00.000Z
data.quoteStatus: available
data.notice: Simulation only. Estimate, not a reservation.
data.productId: carpet-cleaner
data.quantity: 2
data.startDate: 2026-10-16
data.endDate: 2026-10-18
data.rentalDays: 2
data.fulfillment: delivery
data.zoneId: central
data.currency: EUR
data.availability.productId: carpet-cleaner
data.availability.startDate: 2026-10-16
data.availability.endDate: 2026-10-18
data.availability.requestedQuantity: 2
data.availability.minimumAvailableQuantity: 4
data.availability.available: true
data.availability.observedAt: 2026-10-04T09:00:00.000Z
data.availability.inventoryRevision: 1
data.lineItems.count: 2
data.lineItems[0].code: rental
data.lineItems[0].description: 2 x Carpet cleaner, 2 days at EUR 25.00 net per day
data.lineItems[0].netCents: 10000
data.lineItems[1].code: delivery
data.lineItems[1].description: Delivery to the Central zone (fixed round-trip fee)
data.lineItems[1].netCents: 2000
data.dailyNetCents: 2500
data.rentalNetCents: 10000
data.deliveryNetCents: 2000
data.subtotalNetCents: 12000
data.taxBasisPoints: 2000
data.taxCents: 2400
data.totalCents: 14400
data.depositPerUnitCents: 5000
data.refundableDepositCents: 10000
data.initialAmountIncludingDepositCents: 24400
data.expiresAt: 2026-10-04T09:15:00.000Z
data.sourceRevisions.count: 3
data.sourceRevisions[0].name: inventory
data.sourceRevisions[0].value: 1
data.sourceRevisions[1].name: rates
data.sourceRevisions[1].value: 1
data.sourceRevisions[2].name: rules
data.sourceRevisions[2].value: 1
error: null
sources.count: 3
sources[0].sourceId: inventory:carpet-cleaner
sources[0].title: Inventory availability
sources[0].url: https://sandbox.webcanspeak.com/catalog/carpet-cleaner
sources[0].version: 1
sources[1].sourceId: rates:carpet-cleaner
sources[1].title: Rental rates
sources[1].url: https://sandbox.webcanspeak.com/catalog/carpet-cleaner
sources[1].version: 1
sources[2].sourceId: rules
sources[2].title: Quote rules
sources[2].url: null
sources[2].version: 1
warnings.count: 1
warnings[0]: Simulation only. Estimate, not a reservation.
end: wcs-read/1

Insufficient stock is a valid answer, not an error

Status ok, HTTP 200, quoteStatus unavailable: an explanation and the availability, but no amounts and no expiry. Never read it as a price of zero.

GET https://sandbox.webcanspeak.com/read/quote?productId=carpet-cleaner&quantity=5&startDate=2026-10-16&endDate=2026-10-18&fulfillment=delivery&zoneId=central
HTTP status 200

format: wcs-read/1
notice: Simulation only. Estimate, not a reservation.
schemaVersion: 1.0
simulation: true
business: Demo Equipment Hire
tool: calculate_quote
transport: read
status: ok
httpStatus: 200
requestId: 00000000-0000-4000-8000-000000000000
generatedAt: 2026-10-04T09:00:00.000Z
data.quoteStatus: unavailable
data.notice: Simulation only. Estimate, not a reservation.
data.productId: carpet-cleaner
data.quantity: 5
data.startDate: 2026-10-16
data.endDate: 2026-10-18
data.availability.productId: carpet-cleaner
data.availability.startDate: 2026-10-16
data.availability.endDate: 2026-10-18
data.availability.requestedQuantity: 5
data.availability.minimumAvailableQuantity: 4
data.availability.available: false
data.availability.observedAt: 2026-10-04T09:00:00.000Z
data.availability.inventoryRevision: 1
data.explanation: Only 4 of Carpet cleaner are available on every day from 2026-10-16 up to 2026-10-18, but 5 were requested.
error: null
sources.count: 1
sources[0].sourceId: inventory:carpet-cleaner
sources[0].title: Inventory availability
sources[0].url: https://sandbox.webcanspeak.com/catalog/carpet-cleaner
sources[0].version: 1
warnings.count: 1
warnings[0]: Simulation only. Estimate, not a reservation.
end: wcs-read/1

Missing information: needs_input

Status needs_input, HTTP 422. error.fields names what is missing; ask the user for it. Nothing is guessed.

GET https://sandbox.webcanspeak.com/read/quote?productId=carpet-cleaner&quantity=2&fulfillment=pickup
HTTP status 422

format: wcs-read/1
notice: Simulation only. Estimate, not a reservation.
schemaVersion: 1.0
simulation: true
business: Demo Equipment Hire
tool: calculate_quote
transport: read
status: needs_input
httpStatus: 422
requestId: 00000000-0000-4000-8000-000000000000
generatedAt: 2026-10-04T09:00:00.000Z
data: null
error.code: needs_input
error.message: Missing required fields (startDate: startDate is required; endDate: endDate is required)
error.fields.count: 2
error.fields[0]: startDate
error.fields[1]: endDate
error.retryable: false
sources.count: 0
warnings.count: 1
warnings[0]: Simulation only. Estimate, not a reservation.
end: wcs-read/1

Invalid input

Status error, error.code invalid_input, HTTP 400. Here the quantity is outside 1-10.

GET https://sandbox.webcanspeak.com/read/availability?productId=carpet-cleaner&quantity=11&startDate=2026-10-16&endDate=2026-10-18
HTTP status 400

format: wcs-read/1
notice: Simulation only. Estimate, not a reservation.
schemaVersion: 1.0
simulation: true
business: Demo Equipment Hire
tool: check_availability
transport: read
status: error
httpStatus: 400
requestId: 00000000-0000-4000-8000-000000000000
generatedAt: 2026-10-04T09:00:00.000Z
data: null
error.code: invalid_input
error.message: Invalid input (quantity: quantity must be an integer 1-10)
error.fields.count: 1
error.fields[0]: quantity
error.retryable: false
sources.count: 0
warnings.count: 1
warnings[0]: Simulation only. Estimate, not a reservation.
end: wcs-read/1

Unsupported delivery zone

Status error, error.code unsupported_zone, HTTP 422. No price or availability lines appear on an error.

GET https://sandbox.webcanspeak.com/read/quote?productId=carpet-cleaner&quantity=2&startDate=2026-10-16&endDate=2026-10-18&fulfillment=delivery&zoneId=outer-region
HTTP status 422

format: wcs-read/1
notice: Simulation only. Estimate, not a reservation.
schemaVersion: 1.0
simulation: true
business: Demo Equipment Hire
tool: calculate_quote
transport: read
status: error
httpStatus: 422
requestId: 00000000-0000-4000-8000-000000000000
generatedAt: 2026-10-04T09:00:00.000Z
data: null
error.code: unsupported_zone
error.message: Requested delivery zone is not served
error.fields.count: 0
error.retryable: false
sources.count: 0
warnings.count: 1
warnings[0]: Simulation only. Estimate, not a reservation.
end: wcs-read/1

Connecting an MCP client

Assistants that support remote MCP servers can use the same four tools. Connecting is an explicit setup step in your assistant or MCP client: you add the server yourself, and nothing on this website installs or connects it. No authentication is needed for this public demonstration.

Example, with the official TypeScript SDK:

import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";

const client = new Client({ name: "my-assistant", version: "1.0.0" });
await client.connect(new StreamableHTTPClientTransport(new URL("https://sandbox.webcanspeak.com/mcp")));
const { tools } = await client.listTools();
const quote = await client.callTool({ name: "calculate_quote", arguments: { productId: "carpet-cleaner", quantity: 2, startDate: "2026-10-16", endDate: "2026-10-18", fulfillment: "pickup" } });

Schemas, MCP and source pages


Demo Equipment Hire is a fictional business. Everything here is simulated.