AgenticWebScore
Scan

Commerce Protocols · Recommended · Medium impact

Machine-readable booking action

For a service business the agent's task is to book, not to browse — a declared action is what turns a contact page into a completed job.

  • Recommended
  • Medium impact
  • Draft standard
Machine-readable booking action — Property, Value
Property Value
Check idbooking-action
DimensionCommerce Protocols (15%)
TierRecommended — pool 20 pts
Weight inside tier2
ImpactMedium
MaturityDraft — A published specification that is not yet ratified.
ConditionalNo
Publishing skillbooking-action
Standardsschema.org/ReserveAction

What the scanner requests

  • /contact
  • /book
  • /appointment

It also reads documents it has already fetched: $home.

What is measured

This check declares no probe path, so the scanner walks the JSON-LD of the already fetched homepage / for a potentialAction whose @type is ReserveAction (schema.org) and inspects its target. Pass when the target is an EntryPoint carrying a urlTemplate, an RFC 6570 URI template with at least one variable for the agent to fill in such as {date} or {service}, so the booking can be completed by expanding a URL instead of scraping a contact page; partial when ReserveAction is present but target is a bare URL with no urlTemplate, or the template holds no variables and is therefore just a link; fail when no ReserveAction appears anywhere in the graph and the only booking path is a ContactPoint, a tel: link or a free-text form. This profile-scoped check is reported as not scored and excluded from the denominator unless the services profile has been positively identified.

Reproduce it yourself

You do not have to take our word for any of this. Run the same measurement against your own domain:

              DOMAIN="https://example.com"
curl -sL "$DOMAIN/" | perl -0777 -ne 'while (m{<script[^>]*application/ld\+json[^>]*>(.*?)</script>}gsi) { print "$1\n" }' | jq -r '.. | objects | select(([."@type"?] | flatten | any(. == "ReserveAction"))) | (.target // empty | if type=="array" then .[0] else . end) | if type=="object" then [(."@type" // "NO EntryPoint"), (.urlTemplate // "NO urlTemplate")] else ["target is a bare URL", tostring] end | @tsv'
            

The fix

This is the artifact to ship. It is the complete change, not a description of one.

              <script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Service",
  "name": "Boiler service and safety check",
  "serviceType": "Boiler maintenance",
  "areaServed": { "@type": "City", "name": "Bristol" },
  "provider": { "@type": "LocalBusiness", "name": "Harbourside Heating", "telephone": "+44-117-496-0000" },
  "potentialAction": {
    "@type": "ReserveAction",
    "name": "Book a boiler service",
    "target": {
      "@type": "EntryPoint",
      "urlTemplate": "https://www.example.com/book?service={service}&date={date}&postcode={postcode}",
      "contentType": "text/html",
      "actionPlatform": ["https://schema.org/DesktopWebPlatform", "https://schema.org/MobileWebPlatform"],
      "httpMethod": "GET"
    },
    "result": { "@type": "Reservation", "name": "Boiler service appointment" }
  }
}
</script>
            

Standards referenced

  • schema.org/ReserveAction

Related checks

Related checks — Check, Tier, Impact, Same skill
Check Tier Impact Same skill
product-schema — Product/catalog schemaEssentialCritical—
payment-protocols — Agent payment standard support (AP2/ACP/x402/UCP)RecommendedHigh—
agent-purchase — Agent purchase policyRecommendedHigh—
ucp-manifest — UCP manifest (/.well-known/ucp)EmergingMedium—
returns — Return and shipping terms machine-readableRecommendedMedium—
agent-analytics — Agent traffic measurementEmergingLow—
inventory-freshness — Inventory and price freshnessRecommendedHigh—
seller-identity — Seller identity declaredRecommendedMedium—