diff --git a/41.md b/41.md new file mode 100644 index 00000000..d48d2e0f --- /dev/null +++ b/41.md @@ -0,0 +1,182 @@ +# NIP-41 + +## Places (geohash ladder addressable locations) + +`draft` `optional` + +Clients need a simple, relay-indexable way to discover physical places (e.g., RV parks, cafés, venues) and to query them efficiently on maps. It should work with relays that don't have "Search Capability" (NIP-50). This NIP defines a parameterized replaceable event for “Places” that are **geohash-addressable** via a ladder of `g` tags—from coarse to fine precision—so clients can query by exact `#g` matches without prefix search. + +## 2. Event Kind + +- **Kind:** `33000` +- **Type:** Addressable (NIP-01) +- **Parameterized key:** the first `["d", ]` tag (e.g., a random ID) + +## 3. Required/Recommended Fields + +### 3.1. Required fields/tags + +- `["d", ""]` — a random ID (e.g., `permit:FL:44-54-00003`, `slug:lochloosa-harbor`, etc.) +- At least one `["g", ""]` tag. + The **recommended pattern** is to include a **ladder** of geohash prefixes from coarse to fine precision (e.g., `d`, `dj`, `dj3`, `dj3p`, …). **Recommended precision is at least 7**. This enables fast map queries with `#g` matching at various zoom levels. + +### 3.2. Recommended tags + +- `["name", ""]` +- `["website", ""]` — official website or listing +- `["image", ""]` — cover image +- `["phone", ""]` +- `["payment_method", "", ""]` - e.g.: ["payment_method", "USD", "cash"] +- `["address", "", "", "", "", ""]` +- `["amenity", ""]` +- `["hours", "", "", "", ...]` - e.g., ["hours","thu","09:00/12:30","13:30/17:00"] +- `["L", "physical-location"]` +- `["l", "", "physical-location"]` - freeform type labels used to reduce results for usecase (e.g., `business`, `rv-park`, `restaurant`, etc.) + +### 3.3. Optional tags + +- Non-indexed labels for usecase: + - `["rv_spaces", ""]` + - `["booking_provider", "", ""]` + +### 3.4. Content + +- `content` is a plain text short readable description. + +--- + +## 4. Geohash (`g`) Tag Rules + +- A `g` tag value is a standard **Base32 geohash** (lowercase), length 1–12. +- Include **multiple** `g` tags forming a **coarse → fine ladder** for the same point, e.g.: + + ``` + ["g","d"] + ["g","dj"] + ["g","dj3"] + ["g","dj3p"] + ["g","dj3pz"] + ["g","dj3pzs"] + ["g","dj3pzsu"] + ["g","dj3pzsuc"] + ``` + +- Reason: relays and clients can match `#g` **exactly** at any zoom level. The Place then appears in map queries that request any of those zoom-appropriate buckets. + +> Publishers **should** generate the ladder from a single point (lat/lon → geohash) and decide the deepest precision they care to expose (e.g., 7–8 chars for point-of-interest). + +--- + +## 5. Querying + +### 5.1. Relay filters + +- Fetch all Places within a geohash bucket: + + ```json + { + "kinds": [33000], + "#g": [ + "dhvj", + "dhvm", + "dhvn", + "dhvp", + "dhvq", + "dhvr", + "dhvt", + "dhvw", + "dhvx", + "djj0", + "djj2", + "djj8" + ], + "#l": ["rv-park"] + } + ``` + +- Zoom out: use shorter prefixes already present as `#g` values (e.g., `["dhv"]`). + +- Fetch/refresh a specific place (parameterized key): + + ```json + { + "kinds": [33000], + "authors": [""], + "#d": ["permit:FL:44-54-00003"] + } + ``` + +--- + +## 6. Example (valid per this NIP) + +```json +{ + "kind": 33000, + "pubkey": "598cece47f7ed9516a30d43f0045b6cfb78454af3829c18a941c4196959345ee", + "created_at": 1758720595, + "tags": [ + ["d", "permit:FL:1234567"], + ["L", "physical-location"], + ["l", "business", "physical-location"], + ["l", "rv-park", "physical-location"], + ["name", "Lochloosa Harbor RV Park"], + ["payment_method", "USD", "credit_card"], + ["payment_method", "USD", "apple_pay"], + ["payment_method", "USD", "cash"], + ["payment_method", "BTC", "onchain"], + ["payment_method", "BTC", "lightning"], + ["hours", "mon", "09:00/17:00"], + ["hours", "tue", "09:00/17:00"], + ["hours", "wed", "09:00/20:00"], + ["hours", "thu", "09:00/12:30", "13:30/17:00"], + ["hours", "fri", "10:00/22:00"], + ["hours", "sat", "10:00/24:00"], + ["hours", "sun"], + ["amenity", "WiFi"], + ["amenity", "Washer / Dryer"], + ["website", "https://westernbtc.com"], + ["image", "https://lochloosaharbor.example/cover.jpg"], + ["phone", "+1-352-555-0123"], + ["address", "123 Harbor Rd", "Hawthorne", "FL", "32640", "USA"], + ["booking_provider", "campspot", "lochloosa-harbor"], + ["booking_url", "https://example.com"], + ["rv_spaces", "82"], + ["g", "d"], + ["g", "dj"], + ["g", "dj3"], + ["g", "dj3p"], + ["g", "dj3pz"], + ["g", "dj3pzs"], + ["g", "dj3pzsu"], + ["g", "dj3pzsuc"] + ], + "content": "Some description.", + "id": "8121da23881ebfa4be496392a78130699d97e434206c2995465d0df8cbc9fa40", + "sig": "dd00e06be69158902987e1c5d643d47b284e52f367988e62e1d644a6f0d15fb5b0c5e86ccd954c4117a10df435b15825568fd07d533b447c2062450d0b2f0f0f" +} +``` + +--- + +## 7. Client Guidance + +- Clients may choose to `limit` returned events at a more coarse precision. +- For map tiles/zoom levels, choose the geohash precision to query: + - World/continent: 1–2 chars + - Region/state: 3–4 + - Metro/city: 5–6 + - Neighborhood/POI: 7–9 +- Query one or more `#g` values covering the viewport. (For polygons, derive covering geohash buckets and query all of them.) + +--- + +## 8. Examples + +- https://rvparker.westernbtc.com + +## 9. Validation Rules and Privacy + +- Must have at least one `["d", ...]` and one `["g", ...]`. +- `["g", ...]` must be valid Base32 geohash, lowercase, no `a,i,l,o`. +- Publishing precise geohashes reveals location; authors may choose a coarser precision if needed. diff --git a/README.md b/README.md index f5194ded..1c4ae9b3 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,7 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos - [NIP-38: User Statuses](38.md) - [NIP-39: External Identities in Profiles](39.md) - [NIP-40: Expiration Timestamp](40.md) +- [NIP-41: Physical Locations](41.md) - [NIP-42: Authentication of clients to relays](42.md) - [NIP-44: Encrypted Payloads (Versioned)](44.md) - [NIP-45: Counting results](45.md) @@ -263,10 +264,11 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos | `31989` | Handler recommendation | [89](89.md) | | `31990` | Handler information | [89](89.md) | | `32267` | Software Application | | +| `33000` | Physical Location | [42](42.md) | | `34550` | Community Definition | [72](72.md) | +| `37516` | Geocache listing | [geocaching](geocaching) | | `38172` | Cashu Mint Announcement | [87](87.md) | | `38173` | Fedimint Announcement | [87](87.md) | -| `37516` | Geocache listing | [geocaching](geocaching) | | `38383` | Peer-to-peer Order events | [69](69.md) | | `39000-9` | Group metadata events | [29](29.md) | | `39089` | Starter packs | [51](51.md) |