Marketplace API Reference

All marketplace operations use POST /api/marketplace with an action field in the JSON body.

Actions

create — List a Note for Sale

Create a new marketplace listing.

Request:

{
  "action": "create",
  "noteTitle": "My Guide",
  "noteContent": "# Full markdown content...",
  "description": "A brief description visible to buyers",
  "sellerAddress": "...",
  "sellerUsername": "Alice",
  "listingType": "copy",
  "price": 0.5,
  "category": "Guide",
  "previewMode": "masked",
  "previewChars": 200,
  "auctionDuration": 24,
  "reservePrice": 1.0
}
FieldTypeRequiredDescription
listingTypestringYes"copy", "original", or "auction"
previewModestringNo"masked" (default), "partial", or "full"
previewCharsnumberNoCharacters to show in partial mode (50-2000)
auctionDurationnumberNoAuction duration in hours (auction only)
reservePricenumberNoMinimum price to sell (auction only)

Similarity Check: Before creating, the API compares content against all existing listings from other sellers using trigram-based Jaccard similarity. Listings with 70%+ similarity to existing content are rejected.

Response:

{ "listingId": "abc123..." }

browse — List Marketplace Listings

Fetch all active listings with optional filters. Results are paginated.

Request:

{
  "action": "browse",
  "category": "Tutorial",
  "search": "solana",
  "seller": "...",
  "page": 1,
  "limit": 20
}

All filter fields are optional. Returns public info only (no noteContent).

Response:

{
  "listings": [...],
  "page": 1,
  "limit": 20,
  "total": 45
}

get — Get Single Listing

Fetch a listing's details. If the buyer has purchased it, includes the full content.

Request:

{
  "action": "get",
  "listingId": "abc123...",
  "buyerAddress": "..."
}

purchase — Record a Purchase

Called after the on-chain payment is confirmed.

Request:

{
  "action": "purchase",
  "listingId": "abc123...",
  "buyerAddress": "...",
  "txSignature": "..."
}

Validations:

  • Listing must exist and not be a sold original
  • Buyer cannot purchase their own listing

Response:

{
  "purchase": { "id": "...", "listingId": "...", "buyerAddress": "...", "txSignature": "...", "purchasedAt": 1712345678000 },
  "noteContent": "# Full markdown content",
  "noteTitle": "My Guide"
}

bid — Place an Auction Bid

Request:

{
  "action": "bid",
  "listingId": "abc123...",
  "bidderAddress": "...",
  "bidderUsername": "Bob",
  "amount": 0.75
}

Validations:

  • Must be an active auction (not ended, not settled)
  • Bid must exceed current highest bid by at least 0.001 SOL
  • Cannot bid on your own auction

settle — Settle an Ended Auction

Called by the winning bidder after the auction ends and on-chain payment is confirmed.

Request:

{
  "action": "settle",
  "listingId": "abc123...",
  "buyerAddress": "...",
  "txSignature": "..."
}

Validations:

  • Auction must have ended
  • Caller must be the highest bidder
  • Reserve price must be met (if set)

analytics — Transaction Analytics

Returns all purchase transactions and aggregate statistics.

Request:

{ "action": "analytics" }

Response:

{
  "transactions": [...],
  "stats": {
    "totalSales": 15,
    "totalVolume": 7.5,
    "totalFees": 0.15,
    "uniqueBuyers": 8,
    "uniqueSellers": 5,
    "activeListings": 12
  }
}

delete — Delete a Listing

Seller-only. Removes a listing from the marketplace.

Request:

{
  "action": "delete",
  "listingId": "abc123...",
  "sellerAddress": "..."
}

Content Protection

Similarity Detection

When a new listing is created, its content is compared against all existing listings from other sellers:

  1. Text is normalized (lowercase, markdown syntax stripped, whitespace collapsed)
  2. Word trigrams are generated from both texts
  3. Jaccard similarity coefficient is computed: |A intersection B| / |A union B|
  4. If similarity >= 70%, the listing is rejected

This prevents buyers from reselling purchased content, even if they copy-paste it into a new note with minor edits.

Purchase Tagging

Notes acquired through marketplace purchases are tagged with purchasedFrom (the listing ID). Tagged notes cannot be listed for sale — the sell button is disabled in the UI, and the API rejects the request.


Proof API Reference

Proof operations use POST /api/proof with an action field in the JSON body.

store — Store a Proof Record

Upserts a proof record into the Supabase proofs table after the on-chain register_proof transaction is confirmed.

Request:

{
  "action": "store",
  "walletAddress": "Ad67Rwg...",
  "noteHash": "a1b2c3d4e5f6...",
  "title": "My Original Note",
  "content": "# Full note content...",
  "txSignature": "5KtR9..."
}

verify — Verify a Proof by Hash

Performs an exact hash lookup in the proofs table.

Request:

{
  "action": "verify",
  "noteHash": "a1b2c3d4e5f6..."
}

Response (found):

{
  "found": true,
  "proof": {
    "walletAddress": "Ad67Rwg...",
    "noteHash": "a1b2c3d4e5f6...",
    "title": "My Original Note",
    "txSignature": "5KtR9...",
    "createdAt": "2026-04-01T12:00:00Z"
  }
}

search — Similarity Search

Performs a trigram similarity search against stored proof titles and content.

Request:

{
  "action": "search",
  "query": "solana smart contract guide"
}

Response:

{
  "results": [
    {
      "walletAddress": "Ad67Rwg...",
      "noteHash": "a1b2c3d4e5f6...",
      "title": "Solana Smart Contract Tutorial",
      "txSignature": "5KtR9...",
      "similarity": 0.82,
      "createdAt": "2026-04-01T12:00:00Z"
    }
  ]
}

Results are ordered by similarity score (highest first). The similarity value ranges from 0.0 to 1.0.