NIP-15
Nostr Marketplace (for resilient marketplaces)
Nostrクライアント同士で商店を開けるようになる仕組み。
用語
出店者(merchant) - Nostr鍵ペアを持つ、商品の売り手
顧客(customer) - Nostr鍵ペアを持つ、商品の買い手
商品(product) - 出店者が販売するもの
商店(stall) - 出店者の管理下にある商品のリスト(1人の出店者が複数の商店を出店できる)
マーケットプレイス(marketplace) - 商店を検索し、商品を購入するためのクライアントソフト
Nostrマーケットプレイス クライアント
出店者向け管理画面(Merchant admin)
出店者が商店や商品を作成・更新・削除したり、売上・支払・顧客とのやり取りを行うための場所。
出店者向け管理ソフトは純粋なクライアントサイド実装であってもよいが、利便性と動作可能時間(の向上)の目的で、Nostrイベントをlistenするサーバを持つことになるだろう。
マーケットプレイス
マーケットプレイスソフトは100%クライアントサイド実装(スタンドアロンアプリ、またはフロントエンドのみで成立するWebページ)となるだろう。顧客が出店者のNostr公開鍵を使って出店者・商店・商品をリストアップ・検索できるようにする。マーケットプレイスクライアントは、買い物かごや精算機能を持つ他のEコマースサイトに似たものとなる。マーケットプレイスは、出店者とのダイレクトメッセージを使ったやり取りを行う顧客サポート機能を持つことが望ましい。
出店者による商品の公開・更新
出店者は、以下のイベントを発行できる:
table:出店関連イベント
kind 説明
0 set_meta 出店者の説明]
30017 set_stall 商店の作成・更新
30018 set_product 商品の作成・更新
4 direct_message 顧客とのやり取り メッセージはプレーンテキストまたはJSON
5 delete 商品や商店の削除
イベント 30017: 商店の作成・更新
Content:
code:30017_content.json
{
"id": <String, UUID(出店者が生成)。連続的なID(0, 1, 2...)は推奨されない>,
"name": <String, 商店の名前>,
"description": <String (任意), 商店の説明>,
"currency": <String, 通用する通貨>,
"shipping": [
{
"id": <String, 配送区分のUUID。出店者が生成する>,
"name": <String (任意), 配送区分の名前>,
"cost": <float, 基本送料。 通貨は商店レベルで定義>,
}
]
}
要説明のフィールド:
shipping
商店が対応している配送区分の配列。
顧客はちょうど1つの配送区分を選択しなければならない(MUST)
区分ごとに送料は異なる。送料無料の商品もある(例: デジタルなもの)
idは出店者が使う内部的な値。この値を顧客の選択として(出店者に)送り返すこと。
各配送区分は、その区分への注文に対する基本送料を持つが、特定の商品の送料が基本送料よりも高額になる場合、商品ごとの送料を設定することもできる。
Tags:
code:30017_tags.json
"tags": "d", <String, 商店のID>
dタグが必須。この値は(content内の)商店のidと同じでなければならない(MUST)。
イベント 30018: 商品の作成・更新
Content:
code:30018_content.json
{
"id": <String, UUID(出店者が生成)。連続的なID(0, 1, 2...)は推奨されない>,
"stall_id": <String, この商品が陳列される商店のUUID>,
"name": <String, 商品名>,
"description": <String (任意), 商品の説明>,
"images": <String, 画像URLの配列。任意>, "currency": <String, 通貨>,
"price": <float, 商品の価格>,
"quantity": <int, 商品の数量>,
"specs": [
],
"shipping": [
{
"id": <String, 配送区分のUUID。商店(イベント)で定義された地域のどれか1つに一致しなければならない>,
"cost": <float, 追加送料。通貨は商店(イベント)で定義される>
}
]
}
要説明のフィールド:
specs
key-valueペアの配列(任意)。製品仕様を構造化された形で表示できるようにする。商品間の比較も可能となる。
例: [["operating_system", "Android 12.0"], ["screen_size", "6.4 inches"], ["connector_type", "USB Type C"]]
shipping:
配送区分ごとの追加送料(任意)。商店(イベント)で決められた基本送料に追加で特別な配送コストが必要となる商品のみに対し使われる
idは商店のshippingフィールドで定義された配送区分のIDのどれかに一致しなければならない
ユーザは精算時に配送方法を選択する。その後、ある注文に対する送料の合計を計算するにあたり、クライアントは以下のコストを考慮しなければならない:
選択された配送方法における、商店の基本送料
商品に対し設定された(追加)送料に購入数を掛けた結果(あれば)
Tags:
code:30018_tags.json
"tags": [
...
]
dタグが必須。この値は(content内の)商品のidと同じでなければならない(MUST)。
tタグは検索用のタグ(NIP-12)。商品のカテゴリを表す(food, fruitsなど)。複数のtタグを含めることができる 精算イベント(Checkout events)
全ての精算イベントは、NIP-04を用いてJSON文字列として送信される。 出店者と顧客は、様々なアクションを表現するJSONメッセージを交換する。それぞれのJSONメッセージは、それが何を表現するかを表すtypeフィールドを持たなければならない(MUST)。
table:精算イベントのtype
type 送信者 説明
0 顧客 新しい注文
1 出店者 支払い請求
2 出店者 注文のステータス更新
ステップ1: 顧客による注文
以下のJSONをNIP-04メッセージのcontentに含める。 code:order.json
{
"id": <String, UUID(顧客が生成)>,
"type": 0,
"name": <String (任意), ???>,
"address": <String (任意), 物理的な商品の場合は住所(配送先?)を含める>
"message": <String (任意), 出店者へのメッセージ>,
"contact": {
"nostr": <(顧客の)公開鍵(32バイト・16進文字列)>,
"phone": <String (任意), 顧客が電話での連絡を希望する場合>,
"email": <String (任意), 顧客がEメールでの連絡を希望する場合>,
},
"items": [
{
"product_id": <String, 商品のUUID>,
"quantity": <int, 注文数量>
}
],
"shipping_id": <String, 配送区分のUUID>
}
ステップ2: 出店者による支払い請求
支払い請求のために出店者から折返し送信される。出店者が確認できる限り、任意の支払い手段が有効。
以下のJSONをNIP-04メッセージのcontentに含める。 payment_optionsの要素のtype:
url: 支払いページ(stripe, paypal, btcpayserverなど)のURL
btc: オンチェーンビットコインアドレス
ln: ビットコインライトニングインボイス
lnurl: ビットコインLNURL-Pay
code:request_payment.json
{
"id": <String, 注文のUUID>,
"type": 1,
"message": <String, 顧客へのメッセージ, 任意>,
"payment_options": [
{
"type": <String, 支払い手段>,
"link": <String, URL、BTCアドレス、LNインボイス ほか>
},
{
"type": <String, 支払い手段>,
"link": <String, URL、BTCアドレス、LNインボイス ほか>
}
]
}
ステップ3: 出店者による支払い確認・出荷
出店者が支払いを領収・処理した時点で送信。
以下のJSONをNIP-04メッセージのcontentに含める。 code:verify_payment.json
{
"id": <String, 注文のUUID>,
"type": 2,
"message": <String, 顧客へのメッセージ>,
"paid": <Bool, true/false 支払い領収済みか>,
"shipped": <Bool, true/false 出荷済みか>,
}
顧客サポートイベント(Customer support events)
顧客サポートに用いる連絡手段は何でもよい。Nostrを使ってやり取りする場合は、NIP-04を用いる。 追加情報