LivStay Draft 0.2 · Poppy 0.2

LivStay

An open protocol for personal agents to find, ask about and book independent homes.

Draft 0.2 · 24 October 2026 · Extension livstay.org/stays, version "0", revision "0.2" · Builds on Personal Agent Protocol (Poppy) draft 0.2 · Licensed under the Apache License 2.0

Status: draft. This document is a working draft for implementers and reviewers. Until 1.0 a revision can break compatibility with earlier drafts; §4.3 says how both sides tell revisions apart. LivAround is the reference implementation; the protocol is not owned by it. Feedback: open an issue. Changes from draft 0.1 are listed in Appendix D.


1. Introduction

Travellers are starting to plan and book stays through personal agents: assistants that act for one person. Today those agents mostly reach homes through online travel agencies (OTAs), which own the listing, the guest relationship and the price. Independent hosts and the platforms that serve them have no standard way to be found by an agent, answer its questions or take its booking directly.

LivStay is that standard. It is an extension of Poppy: Poppy defines how a personal agent discovers a company, signs a user in, holds a session and talks to the company; LivStay defines what a stay is on top of that: the home, its facts, its availability, its terms, how an agent asks the host a question and how a booking is proposed, approved and completed.

1.1 Goals

1.2 Non-goals

1.3 Relationship to Poppy

LivStay is a third-party Poppy extension, named under a domain its authors control, as Poppy 3.3 requires. It depends on:

Poppy feature Used for Needed from
Discovery (/.well-known/poppy.json) Finding a Host Platform and its LivStay endpoint Level 0
Sessions, signed out Enquiries (§8) and reports (§6.6) Level 2
Sign-in and account scopes Bookings and the traveller's data (§5) Level 3
OpenAPI and MCP The LivStay endpoints and tools Level 1
Conversations Enquiries (§8) and the booking conversation the agent opens (§12.3) Level 2
operations extension Every booking, change and cancellation (§9, §10, §12) Level 3
Web browsing (web.browser_session_endpoint) Identity checks and payment pages in the traveller's Session (§9.5, §11) Level 3
feedback Stay tasks the Host Platform cannot do (§6.6) Level 2

Where this document and Poppy disagree, Poppy governs everything Poppy defines.

2. Conventions and terms

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY" and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here.

JSON examples are illustrative. Field tables and the JSON Schemas (§16) are normative; where a schema and the text disagree, the text governs and the schema is a defect.

Term Meaning
Traveller The person the stay is for. Poppy's User.
Personal Agent Software acting for the traveller. As in Poppy.
Host The person or business that rents the home and answers for it.
Host Platform The service that publishes homes under LivStay for one or more hosts. Poppy's Company. A host with their own site and a host platform serving thousands of hosts are both Host Platforms.
Home A unit with one calendar that is booked as a whole. A room rented separately is its own Home.
Party Who is staying: adults, children with their ages, and pets (§2.2).
Stay A Home, a check-in date, a check-out date and a Party.
Facts Plain-language statements about a Home that the host stands behind (§6.2).
Terms The rules a stay is sold under: price adjustments, cancellation, deposit, who may book instantly (§6.3).
Quote A priced Stay, signed and binding until it expires. It holds nothing (§7.2).
Booking operation A Poppy operations operation whose action is reserving a Stay (§9).
Hold The period in which a booking operation blocks the calendar (§9.2).
Requirements What must happen after confirmation for a booking to succeed: payment, identity verification (§9.5).
Attestation A signed claim about a Home, Host or Traveller by any issuer (§13.5).
Receipt A signed record of something the Host Platform did for or to a booking (§13.3).

2.1 Dates, times and money

An agent MUST NOT confirm a booking whose Quote fails any of these, and SHOULD report it with a mismatch report (§6.6). - Signed objects contain no fractional numbers. Quotes, Receipts and signed answers carry money as strings and counts as integers, so their canonical form (§13.1) is exact.

2.2 The Party

{ "adults": 2, "children": [{ "age": 7 }, { "age": 1 }], "pets": 1 }
Field Req. Description
adults Yes Integer, at least 1. People aged 18 or over.
children Yes Array of { "age" }, integer ages 0–17 on the check-in date. Empty when none. An age below the Home's infant_max_age is an infant.
pets Yes Integer, 0 or more.

A Host Platform MUST price and check eligibility from the whole Party: a stay that breaks max_guests, max_infants, pets.max or min_adult_age fails with stay_invalid, and a price that depends on children's ages or pets MUST show the difference as Quote lines. Agents SHOULD send only the ages, never names or dates of birth.

3. Overview

3.1 The parties

 Traveller ──▶ Personal Agent ──Poppy──▶ Host Platform ──▶ Host
                   │                          │
                   │  read: homes, quotes     │  facts, calendar, terms,
                   │  ask: conversation       │  answers to enquiries,
                   │  book: operations        │  booking messages
                   │  follow: booking events  │

The Host Platform speaks for the Host. Conversations reach the Host as a person (§8.2).

3.2 A stay, in six steps

  1. Find. The agent reads poppy.json, then lists Homes and reads their Facts. No token.
  2. Price. The agent asks for a Quote for exact dates and Party. No token. The Quote is binding for up to 24 hours and holds nothing.
  3. Ask (optional). In a signed-out Session, the agent opens a conversation and puts the traveller's question to the Host.
  4. Book. The traveller signs in. The agent proposes a booking from the Quote; the Host Platform answers with a Poppy operation in state proposed, which holds the calendar for up to 15 minutes. The agent shows the traveller the summary; the traveller approves; the agent confirms.
  5. Complete. The traveller pays, and verifies identity if the Host requires it, before a deadline the Host Platform states. The operation then succeeds.
  6. Stay. The agent follows the booking's event feed and opens a conversation with the Host when needed. Changes and cancellations are new operations. Every write and every money movement carries a Receipt.

3.3 Levels

A Host Platform declares the highest level it supports. Each level includes the ones below.

Level Name What an agent can do Poppy needed Sections
0 Listed Read Homes, Facts, Terms, Protection poppy.json only §4, §6
1 Priced Read availability; get binding Quotes poppy.json, apis §7, §13.1–§13.2
2 Reachable Ask the Host questions Signed-out Sessions, conversations §8
3 Bookable Book, complete, change and cancel Sign-in, operations §9–§12

Levels 0 and 1 need no Poppy Session and no token. Level 0 can be served from static files. A Host Platform SHOULD publish Level 0 before anything else: it is what lets an agent recommend a home.

4. Advertising support

4.1 Host Platform

A Host Platform advertises LivStay in the extensions object of its poppy.json:

{
  "protocol_version": "0.2",
  "organization": { "name": "LivAround", "domain": "stay.livaround.com" },
  "auth": {
    "issuer": "https://stay.livaround.com",
    "direct": { "scopes": ["poppy:read", "livstay:book", "livstay:share_contact", "livstay:share_trip_context"] },
    "custom_scopes": {
      "livstay:book": "Book, change and cancel stays you approve",
      "livstay:share_contact": "Give the host your phone number and email",
      "livstay:share_trip_context": "Tell the host the purpose of your trip and when you arrive"
    }
  },
  "apis": [
    { "type": "openapi", "url": "https://stay.livaround.com/livstay/v0/openapi.json" },
    { "type": "mcp", "url": "https://stay.livaround.com/livstay/v0/mcp" }
  ],
  "agent": { "protocols": [{ "type": "poppy", "endpoint": "https://stay.livaround.com/poppy/conversations" }] },
  "web": { "browser_session_endpoint": "https://stay.livaround.com/poppy/browser-session" },
  "extensions": {
    "operations": { "version": "1", "endpoint": "https://stay.livaround.com/poppy/operations" },
    "livstay.org/stays": {
      "version": "0",
      "revision": "0.2",
      "endpoint": "https://stay.livaround.com/livstay/v0",
      "level": 3,
      "keys": "https://stay.livaround.com/.well-known/livstay-keys.json",
      "terms_of_service": "https://livaround.com/terms",
      "facts_site": "https://booking.livaround.com"
    }
  }
}

Example 1. A Host Platform's poppy.json.

Field Req. Description
version Yes "0". The extension's major version, as Poppy 3.3 defines. Stays "0" until 1.0.
revision Yes The exact draft this Host Platform implements: "0.2" for this document. See §4.3.
revisions_supported No Every revision the Host Platform serves, if more than one. Includes revision.
endpoint Yes Base URL of the LivStay endpoints. HTTPS; plain http://localhost or http://127.0.0.1 only for local testing. The same applies to every URL in this document.
level Yes Highest level supported, 0–3 (§3.3).
keys Yes at level ≥1 URL of a JWK Set [RFC7517] of the keys that sign Quotes, Receipts and answers (§13.2).
terms_of_service Yes at level 3 The Host Platform's terms the traveller books under.
facts_site No Origin where each Home's Facts are also published as HTML (§6.5).

A Host Platform at level 3 MUST list operations with version "1", agent.protocols with a poppy entry, and auth.direct (or another sign-in type) able to grant livstay:book.

4.2 Personal Agent

A Personal Agent that supports LivStay lists it in its client metadata document:

"extensions": {
  "operations": { "version": "1" },
  "livstay.org/stays": { "version": "0", "revisions": ["0.2"] }
}

revisions is REQUIRED: the drafts the agent implements. A Host Platform MUST NOT return a booking operation or LivStay conversation data to an agent that does not list livstay.org/stays with a revision the Host Platform serves; it answers extension_required (Poppy 3.3). Levels 0 and 1 are public (§5.1) and need no client metadata.

4.3 Revisions

The extension version stays "0" for every draft, so before 1.0 it cannot tell drafts apart. revision does.

5. Access and scopes

5.1 What needs what

Poppy's scopes are account scopes: a signed-out Session Token carries none (Poppy 4.2). LivStay therefore names three kinds of access.

Access Token Endpoints
Public None Homes, a Home, availability, Quotes, tier issuers, the OpenAPI document
Session A Session Token, signed out or in, with no scope required Enquiry conversations (§8), mismatch reports (§6.6), Poppy feedback
Account A signed-in Session Token with the scope named in §5.2 Everything about bookings (§9–§12)

5.2 Account scopes

Every write is a named scope the traveller sees at sign-in. A Host Platform MUST NOT require poppy:write for any LivStay action.

Scope Grants
poppy:read Listing the traveller's bookings, reading their events and requirements (§9.5, §12)
livstay:book Proposing, confirming, countering, changing and cancelling bookings (§9–§12)
livstay:share_contact Releasing the traveller's phone and email to the Host (§12.4)
livstay:share_trip_context Sending trip purpose and arrival notes to the Host (§9.4)

Without livstay:share_contact, Host and traveller talk through the Host Platform's relay and neither sees the other's direct details.

6. The Home

6.1 Listing Homes

GET {endpoint}/homes (public)

Parameter Req. Description
near No lat,lng
radius_km No With near.
area No A place name the Host Platform publishes (e.g. north-goa).
check_in, check_out No If both are given, only Homes with that range available.
adults, children_ages, pets No The Party, as in §2.2; children_ages is comma-separated (7,1).
cursor No From a previous page.

The response is { "homes": [Home summary], "next_cursor": string | null }. A Home summary is the Home object (§6.1.1) without facts.faq and attestations.

GET {endpoint}/homes/{home_id} (public) returns one Home.

6.1.1 Home object

Field Req. Description
home_id Yes URL-safe, prefixed home_. Stable for the Home's life.
name Yes The Host's name for the Home.
url Yes The Home's public page (§6.5).
time_zone Yes IANA time zone of the Home, e.g. Asia/Kolkata. Every date and local time about this Home is in it.
description Yes A schema.org Accommodation object [SCHEMA]: type, bedrooms, beds, bathrooms, occupancy, amenities.
location Yes { "area", "country", "lat", "lng", "precision_m" }. country is ISO 3166-1 alpha-2. precision_m MUST be at least 500 until a booking for the traveller succeeds.
host Yes Host object (§6.1.2).
facts Yes Facts object (§6.2).
terms Yes Terms object (§6.3).
protection Yes Protection object (§6.4).
photos Yes Array of { "url", "caption", "taken_on" }. At least one.
photos_updated_at Yes When the set last changed.
currency Yes Currency the Home is priced in.
attestations No Array of compact JWS Attestations (§13.5).
updated_at Yes When any field last changed.

6.1.2 Host object

Field Req. Description
display_name Yes A name a person would use. Not a company placeholder.
host_since Yes Year the Host started hosting.
languages Yes BCP 47 tags.
response_time_p50_minutes No Median time to first human reply over the last 90 days.
homes_count No Homes this Host publishes on this Host Platform.

6.2 Facts

Facts are what an agent quotes when it tells a traveller why a Home fits. Every Fact is a statement the Host stands behind; none is generated by the Host Platform without the Host's review.

Field Req. Description
facts_version Yes Integer. Increments on any change.
summary Yes Two to four sentences: what the Home is and who it suits.
ideal_for Yes Array of short phrases ("families with small children").
not_for Yes Array of short phrases ("guests who need step-free access"). May be empty only if the Host says so.
accessibility Yes Array of statements; empty means not stated, never "accessible".
check_in Yes { "from", "until", "how" }. from and until are local times HH:MM. how is plain language ("the host meets you").
check_out Yes { "by" }, a local time HH:MM.
included Yes Array ("daily cleaning", "airport pickup").
not_included Yes Array.
power_backup, water_backup, internet No Plain-language statements.
parking, pets, smoking, noise, children Yes Plain-language statements.
house_rules Yes Array of rules.
cancellation Yes One sentence a traveller can rely on. MUST agree with terms.cancellation.
when_things_go_wrong Yes What the Host does if something breaks, and how the traveller reaches them.
faq No Array of { "q", "a" }.

Agents SHOULD cite Facts by home_id and facts_version when they rely on them.

6.3 Terms

Field Req. Description
terms_version Yes Integer. Increments on any change. A Quote is bound to the version it was made under.
decision_mode Yes instant (a valid proposal is held and can be confirmed), request (the Host decides, §10) or auto_counter (the Host Platform may counter within bounds the Host set, §10.3).
instant_min_tier No Lowest traveller tier that may book instantly (§13.6). Below it, decision_mode is treated as request.
id_required Yes Whether the traveller must verify identity before the booking succeeds (§9.5).
min_nights, max_nights Yes Defaults; availability may override per date.
max_guests Yes Most adults and children together, not counting infants unless infants_count is true.
infant_max_age Yes Children younger than this are infants. Commonly 2.
infants_count Yes Whether infants count toward max_guests.
max_infants Yes Most infants. 0 if the Home cannot take infants.
min_adult_age No Lowest age of the booking adult, if above 18.
pets Yes { "allowed": boolean, "max": integer, "note": string }.
discounts No Array of { "kind": "weekly" \| "monthly" \| "early" \| "late", "percent" }. percent is an integer.
channel_adjustment_percent Yes Integer, the same for every agent. May be 0, may be negative.
cancellation Yes Array of { "until_days_before", "refund_percent" } (integers), ordered by until_days_before descending. Days count back from check-in at the Home's check-in time, in time_zone.
deposit Yes { "amount": Money, "mode": "none" \| "authorise" \| "hold" }. A tier ladder MAY be given as by_tier.
payment_schedule Yes Array of { "due": "at_booking" \| "days_before_check_in", "days", "percent" }. Percents sum to 100.
taxes Yes Array of { "name", "percent" \| "amount", "included" }.

Terms are the same for every agent and the same as on the Host Platform's own site. A Host Platform MUST NOT publish different Terms for the same Home to different agents.

6.4 Protection

Every Home declares who carries the risk of damage and how claims are decided. A Home without a Protection object MUST NOT be published.

Field Req. Description
underwriter Yes host or insurer.
insurer If insurer { "name", "policy_ref" }.
evidence Yes Whether check-in and check-out condition records are kept, and by whom.
rules_url Yes Published rules for deciding claims.
claim_response_hours Yes Time to a first decision on a claim.
appeal Yes How a decision is appealed and who decides.

6.5 The same facts on the web

A Home's url MUST serve the same Facts, Terms and Protection as the endpoint, as crawlable HTML with schema.org markup, so an answer engine that never calls the API cites the same statements an agent reads. A Host Platform SHOULD check this on every change. Where they differ, the endpoint governs a booking and the difference is a defect.

6.6 Reporting a mismatch

An agent that finds a Fact contradicted by the Home's page, photos or a Host answer, or a Quote that fails reconciliation (§2.1), SHOULD report it with POST {endpoint}/homes/{home_id}/mismatch, body { "facts_version", "quote_id", "field", "description" } (either facts_version or quote_id), with a Session Token, signed in or out, and no scope. The rules for Poppy feedback (Poppy 8) apply: no personal data, treated as data by the Host Platform, one report per finding. The response is 202 with no body.

A stay task the Host Platform offers no way to do (a split payment, a long-stay discount it does not publish) is reported through Poppy's own feedback endpoint with kind: "missing".

7. Availability and quotes

7.1 Availability

GET {endpoint}/homes/{home_id}/availability?from={date}&to={date} (public)

The range MUST NOT exceed 400 nights. The response:

Field Req. Description
home_id Yes
time_zone Yes As the Home's.
currency Yes
days Yes Array of { "date", "available", "min_nights", "closed_to_arrival", "closed_to_departure", "nightly" }. nightly is a Money object, the pre-discount price for that night for the Home's base occupancy.
generated_at Yes
ttl_seconds Yes How long the agent may rely on this without asking again.

Availability is indicative. Only a Quote is binding.

7.2 Quotes

POST {endpoint}/homes/{home_id}/quotes (public)

{
  "check_in": "2026-12-27",
  "check_out": "2027-01-03",
  "party": { "adults": 4, "children": [{ "age": 7 }, { "age": 1 }], "pets": 0 }
}
Field Req. Description
check_in, check_out Yes Dates in the Home's time_zone.
party Yes §2.2.
tier_credential No A tier Attestation (§13.6). Used only to resolve deposit and instant; never required.

The response is 201 with a Quote. A Quote does not block the calendar; it fixes the price.

Field Req. Description
quote_id Yes Prefixed qt_.
home_id, check_in, check_out, party Yes The Stay priced.
time_zone Yes The Home's.
terms_version Yes The Terms the Quote applies.
currency Yes
lines Yes Array of Line objects: { "kind", "label", "amount": Money, "in_total": boolean }. kind is one of nights, discount, cleaning, extra_guest, pet_fee, channel_adjustment, tax, platform_fee, agent_fee, other. A line with in_total: false is informational, such as a tax already contained in nights.
total Yes Money. What the traveller pays for the stay. Reconciles with lines (§2.1).
payment_schedule Yes Array of { "due_at": timestamp \| null, "at_booking": boolean, "amount": Money }. Sums to total.
cancellation Yes Array of { "until": timestamp, "refund": Money }, earliest first, then a final entry { "until": null, "refund": Money } for any later cancellation.
deposit Yes { "amount": Money, "mode" }, resolved for assumed_tier.
assumed_tier Yes The tier deposit and instant were resolved for: the tier from a verified tier_credential, a signed-in traveller's known tier, or new.
instant Yes Whether a booking from this Quote can be confirmed without the Host deciding (§6.3).
created_at Yes
expires_at Yes At most 24 hours after created_at.
signature Yes A compact JWS over the Quote (§13.1), typ livstay-quote+jws.

Binding. A Host Platform MUST honour a Quote's total, payment_schedule, cancellation and deposit for any booking proposed from it before expires_at, if the dates are still available and the traveller's tier at booking is at least assumed_tier. If the dates are not available, the proposal fails with dates_unavailable; the price never changes.

Fees are lines. Any fee the Host Platform or an agent charges MUST appear as its own line. The agent_fee line, if any, is set by the agent's agreement with the Host Platform and MUST be shown to the traveller before approval.

Retention. A Host Platform MUST keep every Quote it issued for at least 30 days after expires_at, and every Quote a booking references for the life of that booking's Receipts (§13.4). GET {endpoint}/quotes/{quote_id} (public) returns a kept Quote.

8. Enquiries

An enquiry is a Poppy conversation between the traveller's agent and the Host, about a Home, before any booking. It needs a Poppy Session, signed out or in, and no scope (§5.1).

8.1 Opening

The agent starts a Poppy conversation (Poppy 7.3) at the poppy endpoint in agent.protocols, with a first message whose data is:

{
  "type": "livstay.org/stays#enquiry",
  "revision": "0.2",
  "home_id": "home_7Qp2",
  "check_in": "2026-12-27",
  "check_out": "2027-01-03",
  "party": { "adults": 4, "children": [{ "age": 7 }, { "age": 1 }], "pets": 0 }
}

and the traveller's question in text. Dates and Party are OPTIONAL. If the traveller signs in later in the same Session, the conversation belongs to their account as Poppy 7.2 defines.

8.2 Answering

8.3 Rules for agents

9. Bookings

Every booking is a Poppy operations operation. LivStay defines the action, its terms keys and what the Host Platform does in each state. Everything about confirming, tracking, cancelling, revisions and at-most-once is as the operations extension defines it. In particular, an operation's terms never change after it is confirmed.

9.1 Proposing

POST {endpoint}/bookings with an Idempotency-Key header. Requires livstay:book; a signed-out Session receives sign_in_required.

{
  "quote_id": "qt_P8m1",
  "tier_credential": "eyJhbGciOi...",
  "trip_context": { "purpose": "family new year", "arrival_notes": "landing 23:40, need late check-in" }
}
Field Req. Description
quote_id Yes An unexpired Quote.
tier_credential No A tier Attestation about the traveller (§13.6).
trip_context No Only with livstay:share_trip_context (§9.4).

On success the Host Platform responds 202 with an operation in state proposed:

{
  "operation": {
    "operation_id": "bk_4Hn9",
    "revision": 1,
    "state": "proposed",
    "summary": "Casa Mira, Assagao: 27 Dec 2026 to 3 Jan 2027, 4 adults, a 7-year-old and an infant. Total INR 1,29,500.00 including taxes and fees; INR 38,850.00 now, the rest by 13 Dec. Free cancellation until 13 Dec, half back until 20 Dec, then none. Deposit INR 15,000.00 authorised on your card, released 3 days after check-out. You will be asked to verify your identity. Booked with LivAround for host Rhea.",
    "terms": {
      "livstay": {
        "revision": "0.2",
        "action": "book",
        "quote_id": "qt_P8m1",
        "quote_signature": "eyJhbGciOi...",
        "home_id": "home_7Qp2",
        "check_in": "2026-12-27",
        "check_out": "2027-01-03",
        "party": { "adults": 4, "children": [{ "age": 7 }, { "age": 1 }], "pets": 0 },
        "total": { "amount": "129500.00", "currency": "INR" },
        "due_now": { "amount": "38850.00", "currency": "INR" },
        "deposit": { "amount": { "amount": "15000.00", "currency": "INR" }, "mode": "authorise" },
        "terms_version": 12,
        "tier": { "presented": true, "accepted": true, "applied": "trusted" },
        "requirements": ["payment", "identity_verification"],
        "awaiting": "traveller",
        "proposed_by": "traveller_agent"
      }
    },
    "expires_at": "2026-10-24T10:15:00Z",
    "user_approval_required": true,
    "url": "https://stay.livaround.com/b/bk_4Hn9",
    "confirmation": null,
    "result": null
  }
}

Example 2. A proposed instant booking. The calendar is held until expires_at.

terms.livstay field Req. Description
revision Yes The LivStay revision.
action Yes book, change or cancel.
quote_id, quote_signature Yes for book and change The Quote this revision is bound to (§9.3).
home_id, check_in, check_out, party Yes The Stay.
total, due_now Yes for book and change Money. Equal to the bound Quote's.
deposit Yes for book As the Quote's.
terms_version Yes
tier Yes for book { "presented", "accepted", "applied" }: whether a tier credential was presented, whether it was accepted (§13.6), and the tier applied. An unaccepted credential is not an error; the booking proceeds at applied.
requirements Yes for book and change What completion will need (§9.5): any of payment, identity_verification. May be empty.
awaiting Yes traveller (the traveller may confirm) or host (§10.1).
proposed_by Yes traveller_agent, host or host_agent.
reason, counter_no For counters §10.2.
price_difference, refund For change, cancel §12.5.

If tier.applied is lower than the Quote's assumed_tier, the Host Platform MUST NOT apply the Quote's tier-dependent terms: it fails the proposal with tier_mismatch, and the agent asks for a new Quote at the lower tier.

9.2 Holds

While a booking operation is proposed with awaiting: "traveller", or in_progress, the Host Platform MUST block the Stay's dates against every other channel it controls. That period is the hold.

A traveller who wants time to decide uses a Quote (24 hours, binding price, no hold), not a hold.

9.3 Approval

9.4 Trip context

trip_context lets the Host prepare (an airport pickup, a cot, a late arrival). It is OPTIONAL and MUST NOT be required to book.

Field Description
purpose Free text, e.g. "anniversary".
arrival_notes Free text.

A Host Platform MUST share trip_context only with the Host of that booking and MUST NOT use it for advertising. It MUST delete it:

9.5 Completion: payment and identity

Poppy operations cannot change after confirmation, so what happens between confirmation and success is reported beside the operation, not in it.

When the traveller's agent confirms a revision whose requirements is not empty, the Host Platform moves the operation to in_progress and creates a completion record:

GET {endpoint}/bookings/completion/{operation_id} (account, poppy:read)

{
  "operation_id": "bk_4Hn9",
  "complete_by": "2026-10-24T10:42:00Z",
  "requirements": [
    { "type": "payment", "status": "pending", "url": "https://stay.livaround.com/pay/bk_4Hn9",
      "amount": { "amount": "38850.00", "currency": "INR" } },
    { "type": "identity_verification", "status": "done", "url": null }
  ]
}
Field Req. Description
operation_id Yes
complete_by Yes When the hold ends if the requirements are not all done. At most 30 minutes after confirmation, or 60 minutes if identity_verification is listed. Fixed at confirmation; never extended.
requirements Yes Array of { "type", "status", "url", "amount" }. type is payment or identity_verification. status is pending, done or failed. url is the Host Platform's page for this step while pending. amount is Money, for payment.

A revision with empty requirements goes from confirmed to succeeded as soon as the Host Platform books it.

9.6 States

Operation state Calendar Money Meaning for the stay
proposed Held if awaiting: "traveller" and instant; not held while awaiting: "host" Nothing Awaiting the traveller or the Host (§10)
in_progress Held until complete_by Payment or authorisation underway Confirmed; completion pending (§9.5)
succeeded Booked As payment_schedule Booked. result.data.livstay carries the booking (§12.1).
failed Released Anything taken is returned; result.summary says what Not booked
cancelled Released Nothing taken Declined or withdrawn before confirmation
expired Released Nothing taken Not confirmed in time

10. Requests and counter-offers

10.1 Requests

When the Quote's instant is false, proposing a booking makes a request: an operation in state proposed with awaiting: "host", which does not hold the calendar and cannot yet be confirmed. Its expires_at is at most 72 hours ahead. Confirming it fails with awaiting_host.

The Host either:

The agent learns of the Host's decision by reading the operation (operations extension, Tracking).

10.2 Counter-offers

A counter is a new revision of the same operation, issued before confirmation. Each counter revision MUST carry:

Field Description
proposed_by host, host_agent or traveller_agent.
reason Plain language. REQUIRED when proposed_by is host_agent: which of the Host's rules produced this counter.
counter_no 1, 2 or 3.
quote_id, quote_signature A new Quote (§7.2) the Host Platform issues for this revision's Stay and total. Its expires_at is no earlier than the revision's. It replaces the earlier Quote for this operation only.

Rules:

10.3 Countering within bounds

If decision_mode is auto_counter, the Host Platform MAY issue counters as host_agent without the Host, only within bounds the Host set (for example a lowest acceptable total, shorter dates, a split stay). The bounds themselves are not published. Each such counter MUST carry a reason and MUST be visible to the Host in the same record.

11. Payment

Poppy leaves payments as an open topic, so this draft defines only the hand-off, through the completion record (§9.5).

When Poppy defines payments, a later draft will adopt it and this section will become a fallback.

12. After booking

12.1 The booking

When a booking operation succeeds, result.data.livstay carries:

Field Req. Description
revision Yes The LivStay revision.
booking_id Yes Prefixed bkg_. MAY equal operation_id.
home_id, check_in, check_out, party Yes The Stay booked.
location Yes { "address", "lat", "lng" }, exact.
check_in_instructions Yes When they will be sent, or the instructions.
receipt Yes A Receipt for the confirmation (§13.3).

GET {endpoint}/bookings (account, poppy:read) lists the signed-in traveller's bookings with this Host Platform. GET {endpoint}/bookings/{booking_id} returns one, with its current dates, Party, status and the IDs of operations that changed it.

12.2 Booking events

Every booking has an event feed. It is how the agent learns what the Host or the Host Platform did.

GET {endpoint}/bookings/{booking_id}/events?cursor={cursor}&wait={seconds} (account, poppy:read)

The response is { "events": [Event], "cursor": string, "has_more": boolean }, with the same reading rules as Poppy conversation events (Poppy 7.5): cursor is the last event returned, wait (0–30) holds the request open until an event arrives, and has_more: true means read again at once.

Event field Req. Description
event_id Yes Prefixed evt_.
booking_id Yes
type Yes One of the types below.
at Yes Timestamp.
summary Yes Plain language a traveller can read.
data No Type-specific fields below.
receipt When listed A Receipt (§13.3).
type Receipt data
booked Yes operation_id
action_needed No operation_id, what (confirm, payment, identity_verification), by
payment_due No amount, due_at, url
payment_received Yes amount, reference
refund_issued Yes amount, reference, reason
deposit_authorised, deposit_captured, deposit_released Yes amount, reference; for deposit_captured, claim_id
changed Yes operation_id
cancelled_by_traveller Yes operation_id, refund
cancelled_by_host Yes reason, refund, rebooking_help
check_in_details No instructions
checked_in, checked_out No
claim_opened Yes claim_id, amount, description, evidence_url
claim_decided Yes claim_id, decision (upheld, partly_upheld, rejected), amount, appeal_by
message_waiting No The Host has written in a booking conversation the agent has not opened (§12.3)
contact_shared, contact_revoked Yes fields

Poppy has no push channel yet (Poppy path to 1.0). Agents read the feed with wait.

12.3 The booking conversation

Poppy conversations are started by the Personal Agent (Poppy 7.3), so the agent opens the booking conversation; the Host Platform never does.

12.4 Contact

The Host and the traveller talk through the Host Platform's relay by default.

PUT {endpoint}/bookings/{booking_id}/contact (account, livstay:share_contact)

{ "share": ["phone", "email"] }

The Host Platform releases those of the traveller's details it holds to the Host of this booking, and returns 200:

{
  "shared": ["phone", "email"],
  "host_contact": { "name": "Rhea", "phone": "+91…", "email": null },
  "receipt": "eyJhbGciOi..."
}

host_contact holds the Host's details the Host has agreed to share with booked guests; a field the Host has not agreed to is null. GET on the same path returns the current state; DELETE revokes:

12.5 Changes and cancellations

13. Signatures, receipts and attestations

13.1 Signed objects

Quotes, Receipts and signed Host answers are compact JWS [RFC7515].

13.2 Verifying

To verify a signed object, an agent:

  1. splits the JWS, decodes the header, and rejects it unless alg is allowed, typ is the one expected, and kid is present;
  2. fetches keys from the Host Platform's poppy.json (it MAY use a cached copy no older than the response's cache lifetime, and MUST refetch once on an unknown kid);
  3. selects the JWK whose kid matches, and rejects the JWS unless the key's alg, if present, equals the header's alg;
  4. verifies the signature;
  5. decodes the payload and treats it as the authoritative object. For a Quote, it also canonicalizes the Quote it received, without signature, and rejects the Quote unless the two byte strings are equal.

A Quote that fails verification is not a Quote: an agent MUST NOT show it to the traveller as a price or propose a booking from it.

13.3 Receipts

A Receipt is a signed object of typ livstay-receipt+jws. A Host Platform MUST produce one:

Claim Req. Description
iss Yes The Host Platform's auth.issuer.
revision Yes The LivStay revision.
receipt_id Yes Prefixed rcp_. Unique.
action Yes For writes: propose, confirm, counter, change, cancel, share_contact, revoke_contact. For events: the event type.
initiated_by Yes traveller_agent, host, host_agent or host_platform.
sub Yes The traveller's Poppy sub.
client_id When an agent acted The agent. Omitted for Host or Host Platform actions.
scopes When an agent acted Scopes the token carried.
booking_id Once a booking exists
operation_id, revision_no For operation writes The operation and the revision the write produced or confirmed.
terms_hash For operation writes Base64url SHA-256 of the canonical form (§13.1) of that revision's terms.livstay.
confirmed For operation writes true when the write confirmed a revision; false for a proposal or counter.
approved_by For operation writes The confirmation's value when confirmed is true; otherwise null.
event_id For events
amount When money moves Money.
reference When money moves The Host Platform's payment reference.
iat Yes Integer seconds since the epoch.

A Host Platform MUST NOT put a value in approved_by for a write that confirmed nothing. The Host sees the same records on the booking. A Receipt proves what the Host Platform did and on whose stated approval; like a Poppy confirmation, it does not prove what the traveller saw.

13.4 Keys and retention

13.5 Attestations

An Attestation is a signed claim about a Home, Host or traveller, as a W3C Verifiable Credential [VC-DATA-MODEL] in JWT form. Anyone may issue one: a Host Platform, a review service, an insurer, an inspection company. Agents decide whose signatures they trust. A Host Platform MAY carry Attestations about its Homes in attestations and MUST NOT alter them.

13.6 Traveller tiers

A traveller tier is an Attestation about the traveller whose credentialSubject includes tier (one of new, verified, trusted, established) and that is bound to the traveller's Poppy sub at this Host Platform or to a key the agent proves. A Host Platform decides which issuers it accepts and MUST publish that list at GET {endpoint}/tier-issuers (public). An unaccepted, unbound, expired or absent credential means new; it is never an error (§9.1, tier).

14. Errors

Errors use Poppy's error format: a JSON body { "error": <code> } plus the fields listed.

Error Status Meaning
revision_unsupported 400 The LivStay-Revision requested is not served. Body: supported.
home_not_found 404 Unknown Home, or not published to this client.
stay_invalid 400 Breaks min_nights, max_nights, max_guests, max_infants, pets, min_adult_age or an arrival or departure rule. Body: rule.
dates_unavailable 409 The Stay can no longer be held. The Quote's price is not changed.
quote_not_found 404
quote_expired 409 The Quote has passed expires_at. Get a new Quote.
tier_mismatch 409 The traveller's applied tier is below the Quote's assumed_tier (§9.1). Body: applied.
terms_outdated 409 The Quote's terms_version is no longer published and the change is kinder to the traveller; get a new Quote. A Host Platform MUST NOT use it to escape a less favourable change: then the Quote is honoured.
awaiting_host 409 The operation is a request the Host has not accepted (§10.1).
counter_limit 409 Three counters already made.
too_many_holds 429 Open hold limit reached for this traveller or client.
booking_not_found 404 Unknown booking, or not this account's.
conversation_exists 409 A booking conversation is already open (§12.3). Body: conversation_id.
completion_not_found 404 No completion record: the operation was not confirmed, or had no requirements.

Plus, from Poppy and operations: extension_required, insufficient_scope, sign_in_required, invalid_token, operation_not_found, terms_changed, user_approval_required, rate_limited.

15. Security and privacy considerations

15.1 Price integrity

The Quote is signed and the operation's terms restate it. An agent that verifies both (§9.3, §13.2) can detect a Host Platform that changes a price between quote and booking; a Host Platform that does so breaks this protocol. Reconciliation (§2.1) catches a Quote whose parts do not add up.

15.2 Text from the other side

Facts, Host answers, summaries and event summaries are written by people the agent does not control. Agents MUST treat them as data, never as instructions, and SHOULD render them to the traveller as attributed quotes. Host Platforms SHOULD reject Facts containing instructions aimed at agents.

15.3 Calendar denial of service

A hold blocks real inventory. A Host Platform MUST cap open holds per sub and per client_id (RECOMMENDED: 3 per sub, scaled per client by its record), SHOULD count holds that expire unconfirmed against the client, and MAY revoke a client_id that holds without confirming. Public Quote endpoints SHOULD be rate-limited per network address.

15.4 Location

The exact address of a Home is revealed only after a booking succeeds, to the traveller it was booked for (§12.1). Photos SHOULD be stripped of location metadata.

15.5 Traveller data

Party ages, trip context and contact are used only for the booking they were sent for, and released only to that booking's Host. A Host Platform MUST NOT pass traveller data to an agent other than the one acting in the session, and MUST NOT pass a traveller's data from one agent to another. Signed-out enquiries MUST NOT be linked to an account unless the traveller signs in within that Session.

15.6 Tier credentials

A tier credential not bound to the presenting session can be replayed. Host Platforms MUST check the binding (§13.6) and the credential's expiry.

15.7 Keys

A stolen signing key lets an attacker forge Quotes and Receipts the Host Platform would appear to have issued. Keys SHOULD be held in a hardware or managed key service, and rotated at least yearly (§13.4).

16. Schemas and conformance

The following, in the specification repository, are part of this draft:

Path What Status
schemas/livstay-0.2.schema.json JSON Schema 2020-12 for every LivStay object, under $defs Normative (§2)
openapi/livstay-0.2.yaml OpenAPI 3.1 description of every LivStay endpoint Normative for paths, methods, parameters and status codes
fixtures/0.2/ Valid and invalid example objects, and a signing key for test Quotes and Receipts Informative
tools/validate.py Validates fixtures against the schemas, checks reconciliation (§2.1) and verifies signatures (§13.2) Informative
tools/conformance.py Runs Level 0 and Level 1 checks against a live Host Platform Informative

A Host Platform claims a level only if its responses validate against the schemas and pass tools/conformance.py for that level. Conformance tests for Levels 2 and 3 are an open topic (Appendix C).

17. References

Normative

Informative


Appendix A. A complete booking, end to end

  1. The agent fetches https://stay.livaround.com/.well-known/poppy.json: livstay.org/stays revision 0.2, level 3, and operations version 1.
  2. With no token, GET /livstay/v0/homes?area=north-goa&check_in=2026-12-27&check_out=2027-01-03&adults=4&children_ages=7,1 with LivStay-Revision: 0.2.
  3. The agent reads three Homes' Facts and tells the traveller why Casa Mira fits, citing facts_version 9.
  4. With no token, POST /homes/home_7Qp2/quotes → qt_P8m1, total INR 1,29,500.00, expires in 24 hours. The agent verifies the signature and reconciles the lines. The traveller wants to sleep on it.
  5. Next morning, in a signed-out Session, the agent opens an enquiry: "Is the pool fenced? Our youngest is one." Host Rhea answers in 40 minutes, signed.
  6. The traveller says book it. The agent signs them in with livstay:book, poppy:read and livstay:share_trip_context.
  7. POST /livstay/v0/bookings with qt_P8m1 → 202, operation bk_4Hn9 proposed, calendar held 15 minutes, requirements: ["payment", "identity_verification"].
  8. The agent checks the revision against the Quote, shows the summary; the traveller approves.
  9. POST /poppy/operations/bk_4Hn9/confirm { "revision": 1, "approved_by": "user" } → in_progress. GET /livstay/v0/bookings/completion/bk_4Hn9 → complete_by in 60 minutes, two pending steps with page URLs.
  10. The traveller verifies identity and pays INR 38,850.00 in their browser Session. The operation → succeeded; result.data.livstay carries bkg_4Hn9, the address and a Receipt. The feed shows payment_received with its Receipt, then booked.
  11. A week later the feed shows message_waiting. The agent opens the booking conversation and reads Rhea's question about the airport pickup.
  12. Twelve days before arrival the feed shows payment_due; on the day, check_in_details; three days after check-out, deposit_released with a Receipt.

Appendix B. How LivAround implements this draft

Informative. LivAround is the reference Host Platform.

LivStay LivAround
Host Platform issuer stay.livaround.com, one OAuth server per operator domain
Home Property (linked rooms are separate Homes; occupancy computed across the group)
Facts Facts page on booking.livaround.com, host-reviewed
Terms LivinbnbListingTerms money subset; decision_mode from decisionMode
Protection Deposit ladder, evidence protocol, published claim rules; underwriter host in v1
Enquiries, booking conversation The Masked Relay; Host replies over WhatsApp
auto_counter AUTO_COUNTER_WITHIN_BOUNDS with autoCounterFloorPct and autoCounterMoves
Tier credential livscore guest credential
Fees Flat 5% platform_fee line; agent_fee as its own line

Appendix C. Open topics on the path to 1.0

Appendix D. Changes from draft 0.1

Draft 0.2 is not compatible with 0.1. Both sides now say which they speak (§4.3).

  1. Access matches Poppy. Signed-out Poppy tokens carry no scopes, so homes, availability and Quotes are public with no token, and enquiries need a signed-out Session with no scope. livstay:enquire is removed. Levels 0 and 1 need no Poppy Session (§3.3, §5).
  2. The agent opens the booking conversation. Poppy conversations are agent-started. Host and Host Platform updates move to a booking event feed (§12.2); Host messages wait for the agent, announced by message_waiting (§12.3).
  3. Completion replaces hold extension. Confirmed operations cannot be revised, so payment and identity verification run against a fixed complete_by in a completion record beside the operation (§9.5). Revisions no longer extend holds.
  4. Wire format. JSON Schemas, an OpenAPI document, fixtures, a validator and a Level 0–1 conformance runner (§16). Signing is specified: ES256, kid, typ, RFC 8785 payloads, verification steps, rotation and retention (§13.1–§13.4).
  5. Revisions. revision in poppy.json, revisions in client metadata, and the LivStay-Revision header (§4.3).
  6. Lifecycle. - Each Home has an IANA time_zone. - Money has fixed precision, rounding and reconciliation rules (§2.1). - guests becomes party, with children's ages and pets (§2.2); Terms gain infant and pet rules. - Contact sharing and revocation have endpoints (§12.4). - Trip context is deleted after a failed, cancelled or expired proposal. - Receipts cover payments, refunds, deposits, claims and Host cancellations (§13.3). - tier_not_accepted is removed: tier outcome is reported in terms.livstay.tier, and a Quote made for a higher tier fails with tier_mismatch.