Chapter 99 - Commerce
99
Nostr Implementation Possibility - Hex № 99

Classified Listings

One addressable event that puts anything up for sale or offer: goods, services, jobs, rentals, giveaways, or personals.

1 Overview

A classified listing is a public offer. It can list a physical good, a service, a work opportunity, a rental, a free giveaway, or a personal ad. This NIP defines kind:30402, an addressable event that describes one listing. The event carries enough structured metadata to make the listing useful to clients.

The .pubkey field of a listing is the party that creates the listing. The event structure is very similar to NIP-23 long-form content events. Because the event is addressable (see NIP-01), the seller can edit the listing later. The relay keeps only the latest version per pubkey + kind + d tag value.

NIP-15 defines a strictly structured marketplace. NIP-99 emerged as a simpler and more flexible alternative. For interoperable e-commerce on top of NIP-99, the spec points to an extension proposal by GammaMarkets. The extension standardizes the e-commerce use case and keeps the base spec lightweight.

Hint!

Think of NIP-99 as the corkboard at the general store. One pin, one card, one price. NIP-15 is the full cash register in the back. Pick the card first; upgrade only when you need carts and checkout.

Seller client Relay 1 Relay 2 Buyer client kind 30402 REQ {"kinds":[30402]}
Fig. 99-1 — Listing flow. The seller publishes one addressable listing. Buyers query relays by kind and tag.

2 Listing Events

This NIP defines two kinds. Both are addressable events with the same structure:

Kinds defined by this NIP
KindNamePurpose
30402Classified listingA published listing. Describes any product, service, or other thing for sale or offer.
30403Draft / inactive listingSaves a draft or inactive listing. Same structure as kind:30402.

The .content field is a description of what is offered and by whom. Write it as one string in Markdown syntax. The .pubkey field is the party that creates the listing.

kind 30403 draft / inactive kind 30402 status: active kind 30402 status: sold publish edit Addressable: each edit replaces the previous version with the same d tag value.
Fig. 99-2 — Listing lifecycle. Draft as kind:30403, publish as kind:30402, mark as sold with the status tag.

3 Metadata Tags

Structured metadata lives in the tags array. The following tags are standardized. Clients SHOULD include them. Other tags may be added as necessary.

Standardized metadata tags
TagValueRule
titlestringA title for the listing.
summarystringA short tagline or summary for the listing.
published_atstringThe unix timestamp, in seconds, of the first time the listing was published. Converted to a string.
locationstringThe location of the listing.
pricearrayThe price of the thing being listed. See the price format below.
statusstringOptional. The status of the listing. SHOULD be either active or sold.
Other useful tags
TagValueRule
tstringA category, keyword, or hashtag of relevance for the listing. Use one t tag per keyword.
imageURL + dimensionsAn image of the listing, whether included in the Markdown content or not. Clients SHOULD use image tags as described in NIP-58. This lets clients display images in carousel format more easily.
ggeohashA geohash for a more precise location.

The price tag

The price tag is an array with two to four elements:

Price tag format
["price", <number>, <currency>, <frequency>]
  • price is the name of the tag.
  • <number> is the amount in numeric format, but included in the tag as a string.
  • <currency> is the currency unit in 3-character ISO 4217 format, or an ISO 4217-like currency code such as btc or eth.
  • <frequency> is optional. It describes recurring payments. It SHOULD be in noun format: hour, day, week, month, year, and so on.
Price examples
["price", "50", "USD"]             $50, one-time payment
["price", "15", "EUR", "month"]    €15 per month
["price", "50000", "GBP", "year"]  £50,000 per year
Tech Note

Two oddities in the source spec. First, the image tag format is defined in NIP-58, the Badges NIP — an unusual home for a general-purpose image tag. Second, in the spec's own example event, published_at (1296962229, year 2011) predates created_at (1675642635, year 2023). Treat those values as placeholders. The e-commerce extension is also an external document outside the NIPs repository.

4 Worked Example

The event below lists an item for 100 USD in NYC. The d tag makes the event addressable, so the seller can edit it later. The e and a tags reference a related event and a related article, as defined in NIP-01. The Markdown content may embed nostr: links.

Example - kind 30402 listing
{
  "kind": 30402,
  "created_at": 1675642635,
  "content": "Lorem [ipsum][nostr:nevent1qqst8cujky046…] dolor sit amet,
    consectetur adipiscing elit…\n\nRead more at nostr:naddr1qqzkjurnw4ksz…",
  "tags": [
    ["d", "lorem-ipsum"],
    ["title", "Lorem Ipsum"],
    ["published_at", "1296962229"],
    ["t", "electronics"],
    ["image", "https://url.to.img", "256x256"],
    ["summary", "More lorem ipsum that is a little more than the title"],
    ["location", "NYC"],
    ["price", "100", "USD"],
    ["e", "b3e392b11f5d4f28321cedd09303a748…", "wss://relay.example.com"],
    ["a", "30023:a695f6b60119d9521934a691347d9f78…:ipsum", "wss://relay.nostr.org"]
  ],
  "pubkey": "…",
  "id": "…"
}

Publishing and browsing use the plain NIP-01 flow. The seller publishes; a buyer filters by kind and category:

Session transcript - wss://relay.example.com
-- Seller publishes the listing --
→ ["EVENT", {"kind":30402, "tags":[["d","lorem-ipsum"], …], …}]
← ["OK", "a91f52c3…", true, ""]

-- Buyer browses electronics listings --
→ ["REQ", "market", {"kinds":[30402], "#t":["electronics"], "limit":20}]
← ["EVENT", "market", {"kind":30402, "id":"a91f52c3…", …}]
← ["EOSE", "market"]

-- Later: seller marks the item as sold (same d tag replaces the event) --
→ ["EVENT", {"kind":30402, "tags":[["d","lorem-ipsum"], ["status","sold"], …], …}]
← ["OK", "c07de1b8…", true, ""]

5 Version History

NIP-99 started as a classifieds draft by Jeff Gardner in July 2023. The core has stayed stable since. Notable changes, newest first:

  • 20252025-07Linked the GammaMarkets e-commerce extension proposal for interoperable market use.
  • 20242024-08Renamed "parameterized replaceable event" to "addressable event" across the repository.
  • 20242024-01Added the status tag (active / sold).
  • 2023-26variousFormatting passes: JSON reformat, relative links, author list removed, list fixes, code-fence style.
  • 20232023-07-18Renumbered and retitled as NIP-99; price array format settled after review feedback.
  • 20232023-07-14Added image tags; changed the price tag to array format.
  • Origin2023-07-13Jeff Gardner published the initial draft for the classifieds NIP.

Original Proposal - Credits

AuthorJeff Gardner
First commit2023-07-13 — “Add initial draft for classifieds NIP”
Statusdraft - optional — clients pick it up as needed
Source99.md on GitHub - full change history

6 See Also

  • NIP-01 — the base protocol; addressable events, the d tag, and the e/a reference tags.
  • NIP-15 — the strictly structured Nostr Marketplace; the heavier alternative.
  • NIP-23 — long-form content; listings share its event structure and Markdown content.
  • NIP-58 — badges; the source of the image tag format used here.