draft
optional
author:PatrickGeyer
The purpose of this NIP is to allow nostr users to discover accommodation availability similarly to AirBnB, booking.com or longer-term accommodation finding services.
guest
- NOSTR user that is searching for accommodationhost
- NOSTR user that is providing accommodationlisting
- item of accommodation
Where the host
creates, updates and deletes listings, as well as where they manage bookings, payments and communication with guests
.
The host
admin software can be purely clientside, but for convenience
and uptime, implementations will likely have a server client listening for NOSTR events.
Listing browsing
software should be entirely clientside, either as a stand-alone app, or as a purely frontend webpage. A guest
subscribes to listing events tagged with specific area and availability date range. These become listed and searchable. The browsing client is like any other booking site, with date selector, pricing and eventual payment.
A hoster can publish these events:
Kind | Description | NIP | |
---|---|---|---|
0 |
set_meta |
The merchant description (similar with any nostr public key). |
NIP01 |
30021 |
set_listing |
Create or update a listing. | NIP33 (Parameterized Replaceable Event) |
30022 |
set_booking |
Create or update a booking. | NIP33 (Parameterized Replaceable Event) |
4 |
direct_message |
Communicate with the customer. The messages can be plain-text or JSON. | NIP09 |
5 |
delete |
Delete a product or a stall. | NIP05 |
Event Content:
{
"id": <String, UUID generated by the merchant. Sequential IDs (`0`, `1`, `2`...) are discouraged>,
"name": <String, stall name>,
"description": <String (optional), stall description>,
"amountPerDay": float,
"minStay": "P(n)Y(n)M(n)DT(n)H(n)M(n)S", <String, ISO 8601 duration format>
"checkIn": "T12:00", <String, ISO 8601 time format>
"checkOut": "T12:00", <String, ISO 8601 time format>
"currency": "USD", <String, currency used>,
"location": <String, geohash of 8 digits (accuracy should be 19 meters)>
"discounts": [
{
"P(n)Y(n)M(n)DT(n)H(n)M(n)S": "0.5",
}
],
"quantity": 1, <Integer>
"type": "room" | "studio" | "flat" | "house",
"images": <[String], array of image/video URLs, optional>,
"amenities": <{[String]: any}[], array of standardized amenities this listing offers>,
"private": <String, encrypted JSON encoded properties that should only be shared after a booking request>: {
"address": <String, provide exact address>
}
}
List of amenities: All default to zero or false if not specified
{
"airconditioning": boolean,
"allows_pets": boolean,
"bathtub": integer,
"beds: integer,
"tv": integer,
"crib": boolean,
"tumble_dryer": boolean,
"washer": boolean,
"elevator": boolean,
"free_parking": boolean,
"gym": boolean,
"hair_dryer": boolean,
"heating": boolean,
"high_chair": boolean,
"wireless_internet": boolean,
"iron": boolean,
"jacuzzi": boolean,
"kitchen": boolean,
"outlet_covers": boolean,
"pool": boolean,
"private_entrance": boolean,
"smoking_allowed": boolean,
"breakfast": boolean,
"fireplace": boolean,
"smoke_detector": boolean,
"essentials": boolean,
"shampoo": boolean,
"infants_allowed": boolean,
"children_allowed": boolean,
"hangers": boolean,
"flat_smooth_pathway_to_front_door": boolean,
"grab_rails_in_shower_and_toilet": boolean,
"oven": boolean,
"bbq": boolean,
"balcony": boolean,
"patio": boolean,
"dishwasher": boolean,
"refrigerator": boolean,
"garden_or_backyard": boolean,
"microwave": boolean,
"coffee_maker": boolean,
"dishes_and_silverware": boolean,
"stove": boolean,
"fire_extinguisher": boolean,
"carbon_monoxide_detector": boolean,
"luggage_dropoff_allowed": boolean,
"beach_essentials": boolean,
"beachfront": boolean,
"baby_monitor": boolean,
"babysitter_recommendations": boolean,
"childrens_books_and_toys": boolean,
"game_console": boolean,
"street_parking": boolean,
"paid_parking": boolean,
"hot_water": boolean,
"lake_access": boolean,
"single_level_home": boolean,
"waterfront": boolean,
"first_aid_kit": boolean,
"handheld_shower_head": boolean,
"home_step_free_access": boolean,
"lock_on_bedroom_door": boolean,
"mobile_hoist": boolean,
"path_to_entrance_lit_at_night": boolean,
"pool_hoist": boolean,
"ev_charger": boolean,
"rollin_shower",
shower_chair,
tub_with_shower_bench
wide_clearance_to_bed
wide_clearance_to_shower_and_toilet
wide_hallway_clearance
baby_bath
changing_table
room_darkening_shades
stair_gates
table_corner_guards
extra_pillows_and_blankets
ski_in_ski_out
window_guards
disabled_parking_spot
grab_rails_in_toilet
events_allowed
common_spaces_shared
bathroom_shared
security_cameras
}
Event Tags:
"tags": [["d", <String, id of first issued event of this listing>]]
- the
d
tag is required by NIP33. Its value MUST be the same as the previous listing nostr eventid
.
All checkout/booking enquiry events are sent as JSON strings using (NIP04).
The host
and the guest
can exchange JSON messages that represent different actions. Each JSON
message MUST
have a type
field indicating the what the JSON represents. Possible types:
Message Type | Sent By | Description |
---|---|---|
0 | Guest | New Booking |
1 | Hoster | Payment Request |
2 | Hoster | Order Status Update |
The below json goes in content of NIP04.
"tags": [["escrow": ""]<Optional>, ["e", "" <String, event id of listing publication>], ["type", "booking-enquiry"]], //NIP-XX: Escrow service, type tag required to quickly pull in booking related messages to clients
"kind": 4,
"content":
{
"type": 0,
"contact": {
"phone": <String (optional), if the customer wants to be contacted by phone>,
"email": <String (optional), if the customer wants to be contacted by email>,
},
"start": <Date>,
"stay": <Duration>
}
The below json goes in content
of NIP04.
payment_options
/type
include:
url
URL to a payment page, stripe, paypal, btcpayserver, etcbtc
onchain bitcoin addressln
bitcoin lightning invoicelnurl
bitcoin lnurl-pay
{
"tags": [["e", <String, event id of >]]
"content": {
"type": 1,
"payment_options": [
{
"type": <String, option type>,
"link": <String, url, btc address, ln invoice, etc>
},
{
"type": <String, option type>,
"link": <String, url, btc address, ln invoice, etc>
},
{
"type": <String, option type>,
"link": <String, url, btc address, ln invoice, etc>
}
]
}
}
Once payment has been received and processed, the host will publish a booking event, it will enclude a NIP-04 encrypted pubkey of the guest, so that the guest can be sure the booking is allocated to them.
{
"tags": [["e", <String, event id of NIP04 booking enquiry>,
["listing_id", <String, event id of listing>], ["encrypted_guest_pubkey", <String, encrypted pubkey received as part of booking enquiry>]],
"kind": 4,
"content":
{
"type": 2,
"status": ACCEPTED/REJECTED
}
}
Event Content:
{
"tags": [["e", <String, event id of NIP04 booking enquiry>,
["listing_id", <String, event id of listing>], ["encrypted_guest_pubkey", <String, encrypted pubkey received as part of booking enquiry>]],
"kind": 4,
"content":
{
"start": <Date (optional), product description>,
"stay": <String, ISO 8601 duration format>,
}
}
Event Tags:
"tags": [
["d", <String, id of booking],
["e", <String, id of listing>]
...
]
- the
d
tag is required by NIP33. Its value MUST be the same as the bookingid
.
Messaging the host or guest is handled over whatever communication method was specified. If communicating via nostr, NIP-04 is used https://github.com/nostr-protocol/nips/blob/master/04.md.