OpenTravelIndex Profile v0.1 (draft)
Status: draft, 2026-10-10. Prose: CC-BY-4.0. Schemas: Apache-2.0. Namespace and name are provisional until the project's name and domain are cleared (implementation plan, P0 task K5).
1. What this profile is
The OpenTravelIndex (OTI) Profile lets an independent hotel make itself discoverable and bookable by AI agents from systems it already runs. It defines almost nothing new:
- Booking is UCP Lodging (
dev.ucp.lodging.booking), used as published. OTI never forks or edits UCP schemas. - Static content is schema.org JSON-LD.
- Transport to agents is MCP (the OTI gateway) and plain HTTPS.
- New in OTI are three thin extensions that UCP leaves out of scope: search, availability (provisional, date-ranged offers) and reservation (post-booking lookup and cancel), plus a signed property manifest and conformance levels.
Each extension is drafted to be proposed upstream to UCP. If UCP adopts one, the OTI name becomes an alias.
2. Namespace
OTI capabilities use the reverse-domain namespace of the host that serves their schemas, as UCP's authority binding requires (the reversed schema host must equal or be a label-aligned prefix of the capability name).
| Capability | Schema |
|---|---|
<ns>.lodging.search | /spec/schemas/search-response.json |
<ns>.lodging.availability | /spec/schemas/availability-response.json |
<ns>.lodging.reservation | /spec/schemas/reservation.json |
The lab deployment uses <ns> = com.pinnacledigital.lab.travel, with schemas served from https://travel.lab.pinnacledigital.com/spec/schemas/.
3. Conformance levels
| Level | A producer serves | An agent can |
|---|---|---|
| L0 | Signed manifest, schema.org JSON-LD, booking link | Find the hotel and link to it |
| L1 | L0 + /.well-known/ucp + availability extension | Quote live all-in prices |
| L2 | L1 + UCP booking sessions | Start a booking and hand the guest to the hotel's secure page |
| L3 | L2 + reservation extension | Look up and cancel a reservation |
An index lists a producer at L0 until its domain is verified, whatever it declares.
4. Discovery order for agents
GET https://<hotel>/.well-known/ucp(UCP business profile; REST endpoint and capabilities).GET https://<hotel>/.well-known/oti.json(the OTI manifest).- An MCP Server Card via the AI Catalog, when the hotel or its platform publishes one.
- schema.org JSON-LD on the hotel's pages.
5. The manifest (/.well-known/oti.json)
Schema: manifest.json. It names the publisher (name, domain, contact), the declared conformance level, the UCP profile URL (L1+), the properties (producer-scoped id, slug, name, geo, address, schema.org page URL, booking URL, level), and the public signing keys.
Signature. signature is a detached compact JWS (header..signature, EdDSA/Ed25519) over the RFC 8785 canonical JSON of the manifest without signature. The kid in the JWS header names one of keys. When a domain is verified, an index pins the key's RFC 7638 thumbprint; afterwards it accepts only manifests signed by that key. A key rotation therefore needs re-verification.
Domain. The manifest must be served from the publisher domain or a subdomain of it.
6. Required schema.org subset
A node of type LodgingBusiness or a subtype (Hotel, Motel, Hostel, BedAndBreakfast, Resort, Campground, VacationRental) with: @context schema.org, name, url, address (PostalAddress with addressLocality and addressCountry) and geo (GeoCoordinates). Recommended: amenityFeature, checkinTime, checkoutTime, starRating, image, and containsPlace (HotelRoom).
7. Wire conventions
- JSON, snake_case, as UCP.
- Money is integer minor units (ISO 4217 exponent), with a three-letter
currency. - Times are RFC 3339 with offset; stay dates are property-local
YYYY-MM-DD. - Extension endpoints are relative to the
dev.ucp.lodgingREST service endpoint in the UCP profile:
| Endpoint | Request | Response |
|---|---|---|
POST {endpoint}/oti/search | search-request.json | search-response.json |
POST {endpoint}/oti/availability | availability-request.json | availability-response.json |
POST {endpoint}/oti/reservations/lookup | reservation-lookup.json | reservation.json |
POST {endpoint}/oti/reservations/cancel | reservation-cancel.json | reservation-cancel-response.json |
8. Rules every producer and index follows
- No card data. No field of any OTI message carries a card number, CVV or expiry. Every endpoint rejects a request containing a card number with HTTP 400 and does not log it. Payment happens only on a trusted page reached through UCP
continue_url: the hotel's own checkout, its payment provider's hosted page, or a page operated for the hotel that embeds no card field. - The hotel is the merchant of record. No OTI component charges the guest.
- Room-only. No transport, activity or package items.
- All-in prices. Every offer itemizes taxes and mandatory fees (an explicit zero entry when there are none), marks what is collected at the property, and its non-total entries sum to the total. Its payment schedule sums to the total.
- Provenance and freshness. Every offer and index record carries
source(hotel-published,plugin,edge,crawled,wix-mcp,fallback),fetched_atandexpires_at. Consumers discard expired offers. - Organic ranking is not for sale. An index returns paid placement only in a separate, labelled
sponsoredarray. - Read access for agents is free. Search and availability are anonymous and rate-limited, never billed.
9. Conformance
oti-validate <base-url> [--level L0..L3] [--sandbox] checks every layer above. Without --sandbox it creates booking sessions but never completes one, so it is safe against a live hotel; with --sandbox it completes and cancels a test booking (test producers only). Producers must pass the level they declare.