Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
182 changes: 182 additions & 0 deletions 41.md
Original file line number Diff line number Diff line change
@@ -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", <identifier>]` tag (e.g., a random ID)

## 3. Required/Recommended Fields

### 3.1. Required fields/tags

- `["d", "<stable-id>"]` — a random ID (e.g., `permit:FL:44-54-00003`, `slug:lochloosa-harbor`, etc.)
- At least one `["g", "<geohash>"]` 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", "<display name>"]`
- `["website", "<website url>"]` — official website or listing
- `["image", "<absolute url>"]` — cover image
- `["phone", "<E.164 or human>"]`
- `["payment_method", "<currency code>", "<type>"]` - e.g.: ["payment_method", "USD", "cash"]
- `["address", "<street>", "<city>", "<region>", "<postal>", "<country>"]`
- `["amenity", "<amenity type>"]`
- `["hours", "<day of week abbrevation>", "<shift one>", "<shift two>", ...]` - e.g., ["hours","thu","09:00/12:30","13:30/17:00"]
- `["L", "physical-location"]`
- `["l", "<physical-location-type>", "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", "<count>"]`
- `["booking_provider", "<booking provider name>", "<specific booking provider id>"]`

### 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": ["<pubkey>"],
"#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.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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) |
Expand Down