Home How it works
NOSISTER

How Nosister works

Nosister is an Issuer-Specified Expiry (I.S.E.) Nostr Relay for NIP-99 Classified Listings: sellers publish addressable kind 30402 listings, update them by pubkey + d, delete them with NIP-09 kind 5 requests, and expire them with NIP-40 expiration tags.

Listing lifecycle on Nosister

Nosister uses the addressable listing identity 30402:<pubkey>:<d>. The d tag is the listing ID within the seller’s namespace.

Create:
Publish a NIP-99 kind 30402 listing event with a d tag.
Update:
Publish a newer kind 30402 event with the same pubkey and d tag. Nosister serves the newest active version for that addressable listing.
Delete:
Publish a NIP-09 kind 5 deletion request referencing the listing, for example ["a", "30402:<pubkey>:<d>"].
Expire:
Add a NIP-40 expiration tag so the relay stops serving the listing after the issuer-specified timestamp.

Supported Nostr features

  • The relay accepts standard EVENT, REQ, and CLOSE commands over WebSocket.
  • Event validation checks schema, computed event hash, signature, event-size limits, and REQ filter complexity limits.
  • There is no kind allowlist in the relay write path: any valid kind can be persisted.
  • The homepage live listing feed subscribes first to NIP-99 listing lifecycle kinds and then to selected secondary/debug kinds:
    30402, 5, 1, 20, 6, 7, 3, 10002, 14, 9734, 9735, 30023, 30000.

So: relay storage is broader than what the homepage feed displays.

Issuer-Specified Expiry (I.S.E.) for NIP-99 Classified Listings

Non-standard note: Issuer-Specified Expiry is a Nosister relay policy built on top of the standard NIP-40 expiration tag handling.

  • On insert, Nosister reads the first event tag whose name is exactly "expiration".
  • If present, Nosister treats a positive integer value as Unix seconds and ignores invalid values safely.
  • If parsing succeeds, that timestamp is written to events.expires_at; if not, expires_at is NULL.
  • Read/query paths return only rows where deleted_at IS NULL and (expires_at IS NULL OR expires_at > NOW()).
  • The relay does not clamp or override requested expiration based on account plan in current code.

What happens in edge cases?

  • No expiration tag: expires_at stays NULL (archival by default).
  • Malformed expiration tag: parse fails, so expires_at becomes NULL.
  • Expiration in the past: event can still be inserted, but historical REQ queries immediately filter it out as expired.

Example: kind 30402 listing with ~24h expiry

{
  "kind": 30402,
  "content": "{\"title\":\"Vintage boots\"}",
  "tags": [["d", "boots-001"], ["expiration", "1735862400"]]
}

Example: kind 5 delete for an addressable listing

{
  "kind": 5,
  "content": "",
  "tags": [["a", "30402:<pubkey>:boots-001"], ["k", "30402"]]
}
If you omit ["expiration", "..."], current relay behavior is indefinite retention unless later deleted by issuer (kind 5) or removed by operator action.

Relay behavior & policies

  • Rate limiting: per-IP concurrent connection cap and per-IP message-rate window are enforced; over-limit clients get NOTICE and socket close.
  • Blocking: blocked IPs are rejected at connection preflight; blocked pubkeys can connect but their events are rejected with NOTICE + OK false.
  • Deletion: kind 5 events are applied to issuer-owned target ids and set deleted_at in storage.
  • Plan limits: plans enforce per-pubkey daily event and byte quotas on publish. This does not alter event expires_at semantics.

Protocol responses used by Nosister

  • OK: sent for each EVENT publish attempt (accepted or rejected).
  • NOTICE: sent for malformed commands, policy violations, or rate-limit rejections.
  • EOSE: sent after stored historical events are replayed to a new subscription.

HTTP introspection endpoints

  • GET /policy → retention policy object (mode, summary, fields).
  • GET /relay-info (and / with Accept: application/nostr+json) → relay metadata, supported NIPs, retention summary.
  • GET /health → status + DB up/down + retention mode.

Using Nosister in practice

With nosterize

  1. Add wss://relay.nosister.com to your relay set.
  2. Create/sign a kind 30402 listing event (for Issuer-Specified Expiry, include ["expiration", "<unix>"] in tags).
  3. Publish and expect NIP-20 ["OK","<eventid>",true,""] on acceptance.

With wscat / raw WebSocket

wscat -c wss://relay.nosister.com
["EVENT",{
  "id":"<event-id>",
  "pubkey":"<hex-pubkey>",
  "created_at":1735776000,
  "kind":1,
  "tags":[["expiration","1735862400"]],
  "content":"hello Nosister",
  "sig":"<signature>"
}]
["OK","<event-id>",true,""]

With Nostr clients

Any client that can publish to normal relays can use Nosister. Issuer-Specified Expiry is opt-in: add an expiration tag when you want timed expiry.

How the live listing feed works

Nosister’s live feed focuses on NIP-99 classified listing activity. A new listing is a kind 30402 event with a d tag. An update is a newer kind 30402 event from the same seller using the same d. A delete is a kind 5 deletion request targeting the listing address. Expiry is controlled by a NIP-40 expiration tag.

  • The homepage opens a WebSocket to wss://relay.nosister.com and subscribes to listing lifecycle kinds plus selected secondary kinds for operator context.
  • Kind 30402 is the NIP-99 classified-listing kind. The feed identifies each listing as 30402:<seller pubkey>:<d>.
  • Listing updates reuse the same seller pubkey and d value; the feed treats the newest created_at version as the active lifecycle update.
  • NIP-09 delete requests are kind 5 events. The feed shows them as listing deletes only when an a tag targets 30402:<pubkey>:<d>, or an e tag points to a listing event already seen in the live session.
  • NIP-40 expiration tags mark issuer-specified expiry. Listings inside the soon window appear as expiring soon; past-expiration listings are visually marked expired and are not counted as active listings.
  • Generic Nostr activity such as notes, reposts, reactions, relay lists, zaps, articles, and bookmarks remains available in a secondary “Other Nostr activity” area for development and operator debugging.

Hide content suppresses listing titles, descriptions, and images while retaining event type, seller pubkey, listing address, timestamps, and relay metadata.