mirror of
https://github.com/nostr-protocol/nips.git
synced 2024-12-22 08:25:53 -05:00
NIP-15 Nostr marketplace (#330)
Co-authored-by: Andrew Camilleri <evilkukka@gmail.com> Co-authored-by: Vlad Stan <stan.v.vlad@gmail.com>
This commit is contained in:
parent
fb39455804
commit
bf0a0da6a4
214
15.md
Normal file
214
15.md
Normal file
|
@ -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": <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 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", <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 whats to be contacted by phone>,
|
||||
"email": <String (optional), if the customer whats to be contacted by email>,
|
||||
},
|
||||
"items": [
|
||||
{
|
||||
"product_id": <String, UUID of the product>,
|
||||
"quantity": <int, how many products have been ordered>
|
||||
}
|
||||
],
|
||||
"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>
|
Loading…
Reference in New Issue
Block a user