Open Markets Protocol

Orders

Private checkout messages, order identity, address handling, status transitions, shipping updates, and their NIP-17 transport envelope.

Scope

An order is a private proposal from a buyer to a merchant to purchase one or more offers. Order data can contain names, addresses, contact details, and commercial terms; it MUST NOT be published as a public Nostr event.

Open Markets preserves Gamma's kind 16 business messages while correcting one important description: kinds 16 and 17 are not defined by NIP-17. They are Open Markets rumor kinds transported by NIP-17, NIP-44, and NIP-59.

Message matrix

Rumor kindTypeDirectionPurpose
14noneeitherHuman-readable order conversation
161buyer → merchantOrder creation
162normally merchant → buyerPayment request
163either, role constrainedOrder status or cancellation
164merchant → buyerShipping update
17nonebuyer → merchantPayment receipt

This page defines order creation, status, shipping, and communication. Payment request and receipt schemas are defined in Payments.

Private transport

The examples below show decrypted unsigned rumors. These objects MUST NOT be published directly.

For every recipient, a sending client MUST:

  1. Construct an unsigned rumor with id, real author pubkey, current created_at, kind, tags, and content.
  2. Compute the rumor ID but omit sig.
  3. Serialize and NIP-44-encrypt the rumor into a kind 13 seal.
  4. Sign the seal with the same key identified by the rumor's pubkey.
  5. Require the seal to have an empty tag array.
  6. NIP-44-encrypt the seal into a kind 1059 gift wrap.
  7. Sign the wrap with a new random one-time key.
  8. Put only the recipient routing p tag on the outer wrap.
  9. Publish the wrap only to relays in the recipient's latest valid kind 10050 inbox event.
  10. Publish a separate wrap to the sender when recoverable history is desired.

The seal and wrap timestamps SHOULD be randomized up to two days into the past as required by NIP-17/NIP-59. The rumor timestamp is the authoritative business-message time.

{
  "kind": 1059,
  "pubkey": "<fresh-one-time-pubkey>",
  "created_at": 1786800000,
  "tags": [["p", "<recipient-pubkey>"]],
  "content": "<nip44-encrypted-kind-13-seal>",
  "id": "<gift-wrap-id>",
  "sig": "<one-time-key-signature>"
}

On receipt, a client MUST validate the outer signature before decrypting, validate the kind 13 signature, require seal.pubkey == rumor.pubkey, recompute the rumor ID, and validate the inner recipient and schema before changing local order state.

Kind 21059 ephemeral gift wraps SHOULD NOT carry orders because an offline recipient cannot retrieve them later.

Order identity

The buyer creates the order value. It MUST be non-empty, stable throughout the order, and unique among orders authored by that buyer. Implementations SHOULD generate at least 128 bits of cryptographic randomness.

For lookup and deduplication, clients MUST scope an order by all three values:

<buyer-pubkey>:<merchant-pubkey>:<order-id>

A bare order string is not globally unique. Every later message MUST carry the original order value.

Order creation

Order creation is a kind 16, type 1 rumor authored by the buyer and addressed to one merchant.

Required tags

TagCardinalityMeaning
pexactly 1Merchant public key
subjectexactly 1Human-readable subject
typeexactly 11
orderexactly 1Buyer-generated identifier
amountexactly 1Proposed total in satoshis
item1 or moreOffer address and quantity

Each item has this shape:

["item", "30402:<merchant-pubkey>:<offer-d>", "<positive-integer-quantity>"]

Optional tags

TagMeaning
shippingSelected kind 30406 shipping address
addressFree-form human-readable delivery address
address_*Structured address components
emailBuyer-provided contact email
phoneBuyer-provided contact telephone
clientOptional NIP-89 software attribution

The rumor content MAY contain private order notes or special requests.

Structured addresses

Gamma PR #5 correctly identifies that an unstructured address is difficult to implement, but its proposed pseudo-JSON is neither valid JSON nor globally applicable. Open Markets preserves the existing address tag and adds optional components:

["address", "Ada Lovelace, 12 Market St, Miami, FL 33101, US"]
["address_name", "Ada Lovelace"]
["address_line1", "12 Market St"]
["address_line2", "Suite 4"]
["address_city", "Miami"]
["address_region", "FL"]
["address_postal", "33101"]
["address_country", "US"]
["address_note", "Leave with reception"]

address_country SHOULD use ISO 3166-1 alpha-2. address_region represents a state, province, territory, or similar administrative area. Clients MUST ignore unknown address_* tags and MAY add jurisdiction-specific fields.

All address and contact tags MUST remain inside the encrypted rumor. Clients MUST NOT copy them to the seal or gift wrap.

Example

{
  "id": "<rumor-id>",
  "pubkey": "<buyer-pubkey>",
  "created_at": 1786924900,
  "kind": 16,
  "tags": [
    ["p", "<merchant-pubkey>"],
    ["subject", "Order coffee-2026-08-17-01"],
    ["type", "1"],
    ["order", "coffee-2026-08-17-01"],
    ["amount", "185000"],
    ["item", "30402:<merchant-pubkey>:coffee-ethiopia-250g", "1"],
    ["shipping", "30406:<merchant-pubkey>:us-standard"],
    ["address_name", "Ada Lovelace"],
    ["address_line1", "12 Market St"],
    ["address_city", "Miami"],
    ["address_region", "FL"],
    ["address_postal", "33101"],
    ["address_country", "US"]
  ],
  "content": "Please leave the package at reception."
}

Order validation

The merchant MUST treat a received order as a proposal. Before requesting payment, the merchant MUST:

  1. Verify the buyer's transport, rumor ID, author, and recipient.
  2. Require exactly one type 1, order, amount, subject, and merchant p tag.
  3. Require at least one valid item.
  4. Require every quantity to be a positive base-10 integer.
  5. Resolve every item to a valid kind 30402 offer.
  6. Require each item's offer author to match the recipient merchant unless multi-merchant checkout is explicitly supported.
  7. Recalculate stock, price, recurrence, shipping eligibility, shipping cost, and the total.
  8. Treat the buyer's amount as a proposed total, not as an authoritative price.
  9. Reject an invalid or unavailable shipping option.
  10. Handle personal data according to applicable privacy and retention requirements.

Gamma order amounts are integer satoshis even when offers are priced in fiat. When conversion is necessary, the client MUST show the buyer the rate, source, resulting satoshi amount, and time of calculation. Open Markets does not standardize exchange-rate policy.

Order status

A status update is kind 16, type 3.

Recognized states are:

pending → confirmed → processing → completed
     └──────────────→ cancelled
StatusMeaningAuthorized author
pendingOrder received, payment not verifiedMerchant
confirmedPayment independently verifiedMerchant
processingFulfillment is underwayMerchant
completedMerchant considers fulfillment completeMerchant
cancelledOrder will not continueMerchant; buyer as constrained below

pending is optional. A merchant MUST NOT publish confirmed merely because a syntactically valid receipt arrived; the payment proof must be verified.

{
  "id": "<rumor-id>",
  "pubkey": "<merchant-pubkey>",
  "created_at": 1786925700,
  "kind": 16,
  "tags": [
    ["p", "<buyer-pubkey>"],
    ["subject", "order-info"],
    ["type", "3"],
    ["order", "coffee-2026-08-17-01"],
    ["status", "confirmed"]
  ],
  "content": "Payment received."
}

The p tag always identifies the recipient. This retains merged Gamma PR #3: merchant updates point to the buyer, while a buyer cancellation points to the merchant.

Clients MUST deduplicate updates by rumor ID. To display current state, they MUST consider only valid, role-authorized transitions and order them by rumor created_at, using rumor ID as a deterministic tie-breaker. Relay arrival order is not authoritative.

Unknown status values MUST be displayed as unsupported and MUST NOT be mapped silently to a known state.

Cancellation

A buyer MAY send type 3 with status=cancelled, preferably before confirmation. The merchant MAY cancel by addressing the buyer.

{
  "id": "<rumor-id>",
  "pubkey": "<buyer-pubkey>",
  "created_at": 1786925200,
  "kind": 16,
  "tags": [
    ["p", "<merchant-pubkey>"],
    ["subject", "order-info"],
    ["type", "3"],
    ["order", "coffee-2026-08-17-01"],
    ["status", "cancelled"]
  ],
  "content": "I do not accept the revised total."
}

For an unpaid order, cancellation is terminal. After payment or confirmation, a cancellation records the sender's position but does not reverse a payment or compel the other party. Open Markets currently defines no refund, chargeback, escrow, arbitration, or forced rollback event.

Shipping updates

Shipping updates use kind 16, type 4, authored by the merchant.

Recognized shipping states are processing, shipped, delivered, and exception. The required tags are recipient p, subject, type 4, order, and status. Optional tags are tracking, carrier, and Unix eta.

{
  "id": "<rumor-id>",
  "pubkey": "<merchant-pubkey>",
  "created_at": 1787011200,
  "kind": 16,
  "tags": [
    ["p", "<buyer-pubkey>"],
    ["subject", "shipping-info"],
    ["type", "4"],
    ["order", "coffee-2026-08-17-01"],
    ["status", "shipped"],
    ["tracking", "TRACK123456"],
    ["carrier", "Example Post"],
    ["eta", "1787356800"]
  ],
  "content": "The package has left the warehouse."
}

Shipping state is independent of order state. delivered does not automatically create completed; the merchant publishes the corresponding order update explicitly.

General communication

Parties SHOULD use NIP-17 kind 14 rumors for questions, clarifications, delivery problems, and other human conversation. The subject SHOULD contain the order ID. An e tag MAY identify the direct parent message for reply UX.

{
  "id": "<rumor-id>",
  "pubkey": "<buyer-pubkey>",
  "created_at": 1786924950,
  "kind": 14,
  "tags": [
    ["p", "<merchant-pubkey>"],
    ["subject", "coffee-2026-08-17-01"]
  ],
  "content": "Can I change the delivery day?"
}

The order tag remains the required machine-readable correlation key on structured kind 16 and 17 messages. Reply tags do not replace it.

NIP-69 boundary

NIP-69 kind 38383 is a public P2P Bitcoin/fiat liquidity advertisement with premiums, payment methods, optional bonds, and its own statuses. It MUST NOT be treated as an Open Markets purchase order.

An application supporting both protocols MUST keep their state machines, identities, ratings, and expiration behavior separate. Open Markets does not import NIP-69 bonds or imply escrow.

Security requirements

  • Clients MUST use NIP-44 v2 inside NIP-59 wrapping and MUST NOT fall back to NIP-04 for new orders.
  • Clients MUST enforce encrypted-payload size limits before expensive decoding.
  • Inbox relays SHOULD require NIP-42 authorization for gift-wrap retrieval.
  • Clients MUST deduplicate rumors and reject role-invalid transitions.
  • Contact information, addresses, invoices, payment proofs, and eCash tokens MUST never appear in public events.
  • A client tag is optional attribution and MUST NOT grant authority.
  • Implementations SHOULD minimize retention of decrypted personal data and provide deletion controls.

Sources