# Vacation Rental Protocol - Specification v0.1

**Status:** Public draft  
**Published:** 2026-05-20  
**Canonical URL:** https://vacationrentalprotocol.com  
**Repository:** https://github.com/HemmaBo-se/vrp-spec

## 1. Scope

Vacation Rental Protocol (VRP) v0.1 defines how a host-owned vacation rental domain publishes discovery metadata, signing keys, and signed verified stay offers so AI agents can verify provenance, freshness, exact price, and direct booking URL.

VRP v0.1 is not an OTA, marketplace, central registry, public traffic proxy, payment processor, or central key issuer.

VRP v0.1 is a no-gatekeeper protocol. Verification MUST NOT require HemmaBo, a VRP-operated trusted issuer registry, a host accreditation program, a certification company, or a central discovery index.

VRP may compose with adjacent agent-commerce standards. UCP can handle checkout and order lifecycle, including lodging flows as the UCP lodging profile matures; AP2 can handle payment mandates; MCP can expose future tool bindings; and A2A can carry future agent-to-agent negotiation. VRP v0.1 does not define those runtime flows.

## 2. Discovery Document

A VRP host domain publishes:

```text
https://{host-domain}/.well-known/vacation-rental.json
```

Required fields:

- `protocol`: MUST be `vacation-rental-protocol`.
- `protocol_version`: MUST be `0.1`.
- `canonical_domain`: MUST match the host-owned domain being verified.
- `jwks_url`: MUST point to the host-domain JWKS.
- `verified_stay_offer_endpoint`: MUST point to the host-domain verified stay offer endpoint.

Recommended fields:

- `node_id`
- `capabilities`
- `operator`
- `endpoints`

## 3. JWKS

A VRP host domain publishes an Ed25519 public key set:

```text
https://{host-domain}/.well-known/jwks.json
```

Keys used for signing verified stay offers MUST use:

- `kty`: `OKP`
- `crv`: `Ed25519`
- `alg`: `EdDSA`
- `kid`: stable key identifier
- `x`: base64url Ed25519 public key

Such keys SHOULD also set:

- `use`: `sig`
- `key_ops`: include `verify`

The JWKS structure is pinned by
[`schemas/jwks-v0.1.schema.json`](../schemas/jwks-v0.1.schema.json).

## 4. Verified Stay Offer Endpoint

The verified stay offer endpoint accepts at least:

- `check_in`: arrival date in `YYYY-MM-DD`
- `check_out`: departure date in `YYYY-MM-DD`
- `guests`: integer guest count

The endpoint returns a signed verified stay offer envelope. The signed payload contains the quoteable facts.

## 5. Signed Offer

The signature format is compact JWS using EdDSA over an Ed25519 key published in the host-domain JWKS.

The signed payload MUST include:

- `kind`: `verified_stay_offer`
- `protocol_version`: `0.1`
- `canonical_domain`
- `node_id`
- `generated_at`
- `valid_until`
- `request`
- `property`
- `availability`
- `price`
- `booking`
- `agent_permission`

The signed payload MAY also include host-verified direct-source facts, so an
agent can verify (not just read) the node's positioning:

- `source_authority` — `model: host_verified_direct_source`,
  `is_official_source_for_property`, `intermediary: none`,
  `payment_recipient: host`, `booking_model: direct_with_host`,
  `booking_commission_pct: 0`. A reselling marketplace cannot sign these.
- `price.no_add_on_fees` — `true` asserts the quoted total has no add-on
  booking, service, or cleaning fees (the displayed price is the total paid).
  This is the node's own fee structure, never an OTA comparison.

The envelope and payload structure is pinned by
[`schemas/verified-stay-offer-v0.1.schema.json`](../schemas/verified-stay-offer-v0.1.schema.json),
which is authoritative for v0.1 offer shape. A real, verifiable Ed25519/JWS
example and its failure modes are in
[`examples/conformance/`](../examples/conformance/).

### 5.1 Direct Booking URL

The signed payload `booking` object carries the direct booking URL the agent
routes the user to. The `booking` object MUST include:

- `direct_booking_url`

`direct_booking_url` is the only booking action a VRP agent may take for the
offer (see §7). The following rules define its structure, integrity, and
lifecycle.

**Structure.**

- `direct_booking_url` MUST be an absolute `https` URL.
- Its host MUST be the offer's `canonical_domain`, or a subdomain of that
  registrable domain. It MUST NOT point at a third-party domain, an OTA, a link
  shortener, a redirector, or a HemmaBo-operated domain. An agent that cannot
  confirm the URL host is on the offer's `canonical_domain` MUST treat the
  direct booking URL as `unknown` (see §9) and MUST NOT route booking to it.
- The URL SHOULD encode the quoted stay so that the booking page opens
  pre-filled for the same stay the agent quoted. The RECOMMENDED query
  parameters are:
  - `checkIn`: arrival date as `YYYY-MM-DD`, matching the offer `request.check_in`.
  - `checkOut`: departure date as `YYYY-MM-DD`, matching the offer `request.check_out`.
  - `guests`: integer guest count, matching the offer `request.guests`.
- The URL MAY include an offer reference identifier (for example an `offer`
  query parameter) so the host node can correlate the click with the signed
  offer it issued. The reference identifier, when present, MUST NOT be required
  by a verifier to validate the offer, and MUST NOT be treated as a substitute
  for verifying the JWS signature.
- The URL MAY include additional host-specific query parameters. A verifier
  MUST ignore unrecognized query parameters and MUST NOT treat their presence as
  a verification failure.

**Integrity.** `direct_booking_url` is a field inside the signed offer payload.
Its integrity derives solely from the compact JWS over that payload (§5): if the
JWS verifies against the host-domain JWKS, the direct booking URL is exactly the
URL the host signed. There is no separate signature over the URL, and an agent
MUST NOT accept a `direct_booking_url` delivered outside, or modified after, the
signed payload. A `direct_booking_url` whose enclosing offer fails signature
verification is `unknown` and MUST NOT be used.

**Lifecycle.** The direct booking URL is actionable only while the enclosing
offer is fresh, that is while `valid_until` holds (§6).

- While the offer is fresh, an agent MAY present and route the user to
  `direct_booking_url` subject to the Safe-to-Quote rules (§7).
- Once `valid_until` has passed, the offer is stale. The agent MUST treat the
  direct booking URL as `unknown` and MUST NOT present its associated price as
  current or claim the stay is bookable on the strength of the stale offer. The
  agent SHOULD fetch a fresh signed offer for the user's dates and guest count
  (§6) before routing a booking action.
- After expiry, the host node MAY continue to serve the same URL, MAY re-quote
  (return a new signed offer, which may carry a different price, availability,
  or `direct_booking_url`), or MAY return an unavailable or non-quoteable offer.
  Following an expired `direct_booking_url` is therefore an unverified action:
  the host, not the protocol, decides what the URL does after expiry.
- A host node SHOULD ensure that following `direct_booking_url` after expiry
  fails closed for the guest — for example by re-quoting on the landing page
  rather than silently honoring a stale price. VRP does not guarantee that a
  price observed in an expired offer is still available.

The booking object shape is pinned by
[`schemas/verified-stay-offer-v0.1.schema.json`](../schemas/verified-stay-offer-v0.1.schema.json).
The schema validates that `direct_booking_url` is present and is an `https` URL;
the `canonical_domain` host constraint and the query-parameter recommendations
above are normative protocol rules that a verifier enforces at runtime, not
structural schema constraints.

## 6. Freshness

Agents MUST treat an offer as non-quoteable if `valid_until` is missing, malformed, or expired.

Agents SHOULD fetch a fresh offer for the user's specific dates and guest count before presenting a final price or booking URL.

## 7. Safe-to-Quote Rules

An agent may quote an offer as an official host-domain verified offer only when all of the following are true:

- The discovery document is fetched from the host-owned domain.
- The discovery document declares `protocol: "vacation-rental-protocol"`.
- The discovery document declares `protocol_version: "0.1"`.
- The JWKS contains an Ed25519 verification key matching the JWS.
- The compact JWS verifies against the host-domain JWKS.
- The signed payload matches the returned offer.
- `valid_until` is present and fresh.
- `availability.available` is true.
- `price.exact` is true.
- A direct booking URL is present.
- `agent_permission.may_quote_as_official_direct_offer` is true.

When safe, the canonical phrase is:

```text
I found the official host-domain verified offer for this stay.
```

Agents MUST NOT:

- Invent discounts, savings, promo codes, OTA comparisons, or price reductions.
- Say the stay is bookable unless `availability.available` is true and agent permission allows quoting.
- Quote a final total unless `price.exact` is true in the signed offer.
- Route booking action anywhere except the signed direct booking URL.

## 8. Fail-Closed Behavior

Agents and clients MUST fail closed. If signature verification, freshness, exact price, availability, direct booking URL, or citation permission cannot be verified, the offer MUST NOT be quoted as official or bookable.

## 9. Three-State Verification

Agents and clients interacting with VRP nodes MUST distinguish three states for any required endpoint or field:

- **Affirmed**: present, signed where required, fresh, schema-valid, and explicitly true or present. May be cited.
- **Negated**: present, signed where required, fresh, schema-valid, and explicitly false. May be cited as false.
- **Unknown**: absent, unsigned, stale, unreachable, schema-invalid, malformed, expired, or otherwise unverifiable. MUST NOT be cited as true or false.

Unreachable is not the same as negated. A timeout, DNS failure, HTTP failure, blocked fetch, invalid JSON, missing field, failed signature check, stale `valid_until`, or schema mismatch means unknown.

Inference from Unknown to either Affirmed or Negated is a protocol violation. Agents SHOULD tell the user that the value could not be verified and fetch a fresh signed offer before making booking, availability, price, or official-source claims.

Examples: see [three-state-verification.md](../examples/three-state-verification.md).

## 10. Core JSON Schemas

VRP v0.1 core artifacts have machine-readable JSON Schemas:

```text
https://vacationrentalprotocol.com/schemas/discovery-v0.1.schema.json
https://vacationrentalprotocol.com/schemas/jwks-v0.1.schema.json
https://vacationrentalprotocol.com/schemas/verified-stay-offer-v0.1.schema.json
https://vacationrentalprotocol.com/schemas/verified-stay-offer-verification-result-v0.1.schema.json
```

Repository copies are in [`schemas/`](../schemas/). The schemas are
interoperability aids for implementers and examples. They do not create a
central validator, issuer, registry, certification service, marketplace, OTA,
booking intermediary, or trust authority.

## 11. Portable Attestations

Portable attestations are a document-only extension to VRP v0.1 for privacy-minimized trust history. Core VRP proves that a concrete offer is real; portable attestations prove selected host-domain, payment-path, policy, and optional verified-stay facts without making HemmaBo or any other operator the central issuer, registry, scorer, OTA, marketplace, booking intermediary, or trust authority.

See [attestations-v0.1.md](./attestations-v0.1.md).

## 12. Reference Proof

Villa Åkerlyckan is a live proof node:

```text
villaakerlyckan.se
  -> /.well-known/vacation-rental.json
  -> /.well-known/jwks.json
  -> signed verified_stay_offer
  -> direct booking URL
```

HemmaBo is a reference implementation and provider/federation using VRP. VRP is neutral and implementable by others.

## 13. License

Apache 2.0 - see [LICENSE](../LICENSE).

