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": <String, UUID generated by the merchant. Sequential IDs (`0`, `1`, `2`...) are discouraged>,
    "name": <String, stall name>,
    "description": <String (optional), stall description>,
    "currency": <String, currency used>,
    "shipping": [
        {
            "id": <String, UUID of the shipping zone, generated by the merchant>,
            "name": <String (optional), zone name>,
            "cost": <float, cost for shipping. The currency is defined at the stall level>,
            "countries": [<String, countries included in this zone>],
        }
    ]
}
```

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 example) 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", <String, id of stall]]
```
 - the `d` tag is required by [NIP33](https://github.com/nostr-protocol/nips/blob/master/33.md). Its value MUST be the same as the stall `id`.

### Event `30018`: Create or update a product

**Event Content**:
```json
{
    "id": <String, UUID generated by the merchant.Sequential IDs (`0`, `1`, `2`...) are discouraged>,
    "stall_id": <String, UUID of the stall to which this product belong to>,
    "name": <String, product name>,
    "description": <String (optional), product description>,
    "images": <[String], array of image URLs, optional>,
    "currency": <String, currency used>,
    "price": <float, cost of product>,
    "quantity": <int, available items>,
    "specs": [
      [ <String, spec key>, <String, spec value>]
     ]
}
```

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", <String, id of product],
       ["t", <String (optional), product category],
       ["t", <String (optional), product category],
       ...
    ]
```

 - the `d` tag is required by [NIP33](https://github.com/nostr-protocol/nips/blob/master/33.md). Its value MUST be the same as the product `id`.
 - the `t` tag is as searchable tag ([NIP12](https://github.com/nostr-protocol/nips/blob/master/12.md)). It represents different categories that the product can be part of (`food`, `fruits`). Multiple `t` tags can be present.

## Checkout events

All checkout events are sent as JSON strings using ([NIP04](https://github.com/nostr-protocol/nips/blob/master/04.md)).

The `merchant` and the `customer` can exchange JSON messages that represent different actions. Each `JSON` message `MUST` have a `type` field indicating the what the JSON represents. Possible types:

| Message Type | Sent By  | Description         |
|--------------|----------|---------------------|
| 0            | Customer | New Order           |
| 1            | Merchant | Payment Request     |
| 2            | Merchant | Order Status Update |


### Step 1: `customer` order (event)
The below json goes in content of [NIP04](https://github.com/nostr-protocol/nips/blob/master/04.md).

```json
{
    "id": <String, UUID generated by the customer>,
    "type": 0,
    "name": <String (optional), ???>,
    "address": <String (optional), for physical goods an address should be provided>
    "message": "<String (optional), message for merchant>,
    "contact": {
        "nostr": <32-bytes hex of a pubkey>,
        "phone": <String (optional), if the customer wants to be contacted by phone>,
        "email": <String (optional), if the customer wants to be contacted by email>,
    },
    "items": [
        {
            "product_id": <String, UUID of the product>,
            "quantity": <int, how many products the customer is ordering>
        }
    ],
    "shipping_id": <String, UUID of the shipping zone>
}

```

_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": <String, UUID of the order>,
    "type": 1,
    "message": <String, message to customer, optional>,
    "payment_options": [
        {
            "type": <String, option type>,
            "link": <String, url, btc address, ln invoice, etc>
        },
        {
            "type": <String, option type>,
            "link": <String, url, btc address, ln invoice, etc>
        },
                {
            "type": <String, option type>,
            "link": <String, url, btc address, ln invoice, etc>
        }
    ]
}
```

### 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": <String, UUID of the order>,
    "type": 2,
    "message": <String, message to customer>,
    "paid": <Bool, true/false has received payment>,
    "shipped": <Bool, true/false has been 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 <a href="https://raw.githubusercontent.com/lnbits/nostrmarket/main/models.py">here</a>