From bf0a0da6a48b96467172414d8e41dc72b0ca379c Mon Sep 17 00:00:00 2001 From: Arc <33088785+arcbtc@users.noreply.github.com> Date: Thu, 13 Apr 2023 11:13:04 +0100 Subject: [PATCH] NIP-15 Nostr marketplace (#330) Co-authored-by: Andrew Camilleri Co-authored-by: Vlad Stan --- 15.md | 214 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 214 insertions(+) create mode 100644 15.md diff --git a/15.md b/15.md new file mode 100644 index 00000000..a3d105da --- /dev/null +++ b/15.md @@ -0,0 +1,214 @@ +NIP-15 +====== + +Nostr Marketplace (for resilient marketplaces) +----------------------------------- + +`draft` `optional` `author:fiatjaf` `author:benarc` `author:motorina0` `author:talvasconcelos` + +> Based on https://github.com/lnbits/Diagon-Alley + +> Implemented here https://github.com/lnbits/nostrmarket + +## Terms + +- `merchant` - seller of products with NOSTR key-pair +- `customer` - buyer of products with NOSTR key-pair +- `product` - item for sale by the `merchant` +- `stall` - list of products controlled by `merchant` (a `merchant` can have multiple stalls) +- `marketplace` - clientside software for searching `stalls` and purchasing `products` + +## Nostr Marketplace Clients + +### Merchant admin + +Where the `merchant` creates, updates and deletes `stalls` and `products`, as well as where they manage sales, payments and communication with `customers`. + +The `merchant` admin software can be purely clientside, but for `convenience` and uptime, implementations will likely have a server client listening for NOSTR events. + +### Marketplace + +`Marketplace` software should be entirely clientside, either as a stand-alone app, or as a purely frontend webpage. A `customer` subscribes to different merchant NOSTR public keys, and those `merchants` `stalls` and `products` become listed and searchable. The marketplace client is like any other ecommerce site, with basket and checkout. `Marketplaces` may also wish to include a `customer` support area for direct message communication with `merchants`. + +## `Merchant` publishing/updating products (event) + +A merchant can publish these events: +| Kind | | Description | NIP | +|---------|------------------|---------------------------------------------------------------------------------------------------------------|-----------------------------------------| +| `0 ` | `set_meta` | The merchant description (similar with any `nostr` public key). | [NIP01 ](https://github.com/nostr-protocol/nips/blob/master/01.md) | +| `30017` | `set_stall` | Create or update a stall. | [NIP33](https://github.com/nostr-protocol/nips/blob/master/33.md) (Parameterized Replaceable Event) | +| `30018` | `set_product` | Create or update a product. | [NIP33](https://github.com/nostr-protocol/nips/blob/master/33.md) (Parameterized Replaceable Event) | +| `4 ` | `direct_message` | Communicate with the customer. The messages can be plain-text or JSON. | [NIP09](https://github.com/nostr-protocol/nips/blob/master/09.md) | +| `5 ` | `delete` | Delete a product or a stall. | [NIP05](https://github.com/nostr-protocol/nips/blob/master/05.md) | + +### Event `30017`: Create or update a stall. + +**Event Content**: +```json +{ + "id": , + "name": , + "description": , + "currency": , + "shipping": [ + { + "id": , + "name": , + "cost": , + "countries": [], + } + ] +} +``` + +Fields that are not self-explanatory: + - `shipping`: + - an array with possible shipping zones for this stall. The customer MUST choose exactly one shipping zone. + - shipping to different zones can have different costs. For some goods (digital for examle) the cost can be zero. + - the `id` is an internal value used by the merchant. This value must be sent back as the customer selection. + +**Event Tags**: +```json + "tags": [["d", , + "stall_id": , + "name": , + "description": , + "images": <[String], array of image URLs, optional>, + "currency": , + "price": , + "quantity": , + "specs": [ + [ , ] + ] +} +``` + +Fields that are not self-explanatory: + - `specs`: + - an array of key pair values. It allows for the Customer UI to present present product specifications in a structure mode. It also allows comparison between products + - eg: `[["operating_system", "Android 12.0"], ["screen_size", "6.4 inches"], ["connector_type", "USB Type C"]]` + +_Open_: better to move `spec` in the `tags` section of the event? + +**Event Tags**: +```json + "tags": [ + ["d", , + "type": 0, + "name": , + "address": + "message": ", + "contact": { + "nostr": <32-bytes hex of a pubkey>, + "phone": , + "email": , + }, + "items": [ + { + "product_id": , + "quantity": + } + ], + "shipping_id": +} + +``` + +_Open_: is `contact.nostr` required? + + +### Step 2: `merchant` request payment (event) + +Sent back from the merchant for payment. Any payment option is valid that the merchant can check. + +The below json goes in `content` of [NIP04](https://github.com/nostr-protocol/nips/blob/master/04.md). + +`payment_options`/`type` include: + +- `url` URL to a payment page, stripe, paypal, btcpayserver, etc +- `btc` onchain bitcoin address +- `ln` bitcoin lightning invoice +- `lnurl` bitcoin lnurl-pay + +```json +{ + "id": , + "type": 1, + "message": , + "payment_options": [ + { + "type": , + "link": + }, + { + "type": , + "link": + }, + { + "type": , + "link": + } + ] +} +``` + +### Step 3: `merchant` verify payment/shipped (event) + +Once payment has been received and processed. + +The below json goes in `content` of [NIP04](https://github.com/nostr-protocol/nips/blob/master/04.md). + +```json +{ + "id": , + "type": 2, + "message": , + "paid": , + "shipped": , +} +``` + +## Customer support events + +Customer support is handled over whatever communication method was specified. If communicating via nostr, NIP-04 is used https://github.com/nostr-protocol/nips/blob/master/04.md. + +## Additional + +Standard data models can be found here here