Skip to content
184 changes: 184 additions & 0 deletions 41.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
# 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>"]`
- `["email", "<standard email address>"]`
- `["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.)
- `["t", "<further specifics to filter by>"]` - further filter results e.g., `["t", "accepts-bitcoin"]`

### 3.3. Optional tags

- Non-indexed labels for usecase:
- `["meta", "<key>", "<value"]` - e.g., `["meta", "rv-space-capacity", "69"]`

### 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"],
"#t": ["accepts-bitcoin"]
}
```

- 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": ["<string / uuid>"]
}
```

---

## 6. Example (valid per this NIP)

```json
{
"kind": 33000,
"pubkey": "598cece47f7ed9516a30d43f0045b6cfb78454af3829c18a941c4196959345ee",
"created_at": 1758720595,
"tags": [
["d", "d1c31cbe-e6ce-4f7e-a0da-2abd050a857d"],
["L", "physical-location"],
["l", "business", "physical-location"],
["l", "rv-park", "physical-location"],
["t", "accepts-bitcoin"],
["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"],
["email", "[email protected]"],
["address", "123 Harbor Rd", "Hawthorne", "FL", "32640", "USA"],
["meta", "rv-space-capacity", "69"],
["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