Public API reference

v2 marketplace contract

A clean wire format for buying dried goods.

Nine public handlers cover catalog discovery, culinary conversion, ounce pricing, RFQs, firm quotes, and order verification. The order section also documents one founder-only payment reconciliation handler. Examples below are representative contract-valid payloads; ids and timestamps marked in examples are dynamic values returned by the server.

Authentication expectation
Public handlers do not require an Authorization header. Catalog and RFQ submission are public. Public reads and quote acceptance use the returned record id as a bearer-style possession token, so treat those ids like secrets. The founder-only mark-paid handler is separately protected by x-founder-key.
Ounce rules, once
Use the same rule for previews and RFQs.
Whole ounces only, inclusive 1..1000. RFQ JSON sends requestedOz as a number, never a string. Server grams are floor(oz * 28.349523125).
Pricing authority and wire units
Pricing is server-only: landed subtotal + fixed 25% margin (marginVersion: 2) + interpolated shipping (tierTableVersion: 1). Money is always integer USD cents. Price previews expire through validUntilIso quote reads expose the same validity moment as validUntil.

01 / catalog

Catalog

Start with public lot metadata, then ask the server for an exact weight preview.

GET
/api/listings
Browse the public catalog with three price anchors per lot.
Public. No Authorization header is required.

Optional filters

{
  "category": "spice",
  "availability": "illustrative_seed"
}

Both query parameters are optional. Category is tea, herb, spice, or grain; availability is illustrative_seed, confirmed, or withdrawn.

Shell request

curl -s /api/listings?category=spice&availability=illustrative_seed

GET
/api/listings/{listingIdOrSlug}
Read one catalog detail record by id or slug.
Public. The stable example slug is lst-anamalai-cardamom-a1.

CatalogDetail

HTTP 200
{
  "id": "lst-anamalai-cardamom-a1",
  "slug": "lst-anamalai-cardamom-a1",
  "name": "Bold Green Cardamom, A1 Grade",
  "category": "spice",
  "origin": "Anamalai Hills, Tamil Nadu, IN · 1,100–1,400 m elevation",
  "grade": "A1 — extra bold (8+ mm)",
  "harvestDate": "2025-11",
  "availableGrams": 1250000,
  "certifications": [
    "USDA Organic",
    "Fair Trade",
    "Rainforest Alliance",
    "Spices Board India GI"
  ],
  "seller": {
    "id": "slr-anamalai-cardamom-a1",
    "name": "Anamalai Hills",
    "location": "Anamalai Hills · Tamil Nadu · IN · 1,100–1,400 m elevation"
  },
  "pricePerKgUsd": 32.4,
  "availability": "illustrative_seed",
  "isDemo": true,
  "culinary": {
    "form": "whole green pods",
    "formNote": "whole green pods",
    "usage": "about 10 pods yield 1.5 tsp seeds or 1 tsp ground; ground runs 2.0 g/tsp",
    "approximate": true,
    "measures": {
      "tsp": {
        "grams": 2,
        "approximate": true,
        "formNote": "whole green pods"
      },
      "tbsp": {
        "grams": 6,
        "approximate": true,
        "formNote": "whole green pods"
      },
      "piece": {
        "grams": 0.3,
        "approximate": true,
        "formNote": "whole green pods"
      }
    }
  },
  "imageAlt": "Bright green extra-bold cardamom pods from a smallholder co-op in the Anamalai Hills.",
  "description": "Extra-bold single-origin green cardamom from the Anamalai Hills — hand-sorted at the estate, sun-dried on raised racks, and shipped in food-grade aluminum-lined bags. A1 grade pods (8+ mm) deliver an intensely aromatic, camphor-clean cup when cracked fresh."
}

Shell request

curl -s /api/listings/lst-anamalai-cardamom-a1

GET
/api/listings/{listingIdOrSlug}/quote?oz={wholeOz}
Get a server-authoritative price preview for one whole-ounce quantity.
Public. No Authorization header is required.

CatalogPricePreviewResponse

HTTP 200
{
  "listingId": "lst-anamalai-cardamom-a1",
  "slug": "lst-anamalai-cardamom-a1",
  "requestedOz": 100,
  "pricedGrams": 2834,
  "landedSubtotalCents": 11246,
  "marginTotalCents": 2812,
  "marginRateBp": 2500,
  "shippingTotalCents": 2490,
  "totalCents": 16548,
  "currency": "USD",
  "marginVersion": 2,
  "tierTableVersion": 1,
  "validUntilIso": "2026-09-10T00:00:00.000Z"
}

Shell request

curl -s '/api/listings/lst-anamalai-cardamom-a1/quote?oz=100'

GET
/api/convert?listing={slug}&qty={n}&from={unit}&to={unit}
Convert a catalog measure into grams, ounces, and a price preview.
Public. No Authorization header is required.

Query parameters

{
  "listing": "lst-anamalai-cardamom-a1",
  "qty": 1,
  "from": "tsp",
  "to": "g"
}

listing accepts a catalog id or slug; from is tsp, tbsp, cup, or piece; to is g or oz. Range-only measures return 422 because they cannot produce a priceable quantity.

Shell request

curl -s 'https://leafandlarder.com/api/convert?listing=lst-anamalai-cardamom-a1&qty=1&from=tsp&to=g'

02 / rfq

RFQ

Submit buyer intent as a non-transactional request that issues a dated quote.

POST
/api/rfq
Validate and record a request for quote against a catalog lot.
Public. Record ids returned by the server become bearer-style access tokens.

RfqSubmit JSON body

{
  "listingId": "lst-anamalai-cardamom-a1",
  "requestedOz": 100,
  "buyerEmail": "procurement@example.com",
  "shipTo": "Warehouse 4, Rotterdam",
  "notes": "Palletized delivery preferred.",
  "buyerAgentId": "agent-demo-01"
}

requestedOz is a JSON number, not a string. shipTo and buyerEmail are required; notes and buyerAgentId are optional and bounded.

Shell request

curl -s -X POST /api/rfq -H 'content-type: application/json' -d '{"listingId":"lst-anamalai-cardamom-a1","requestedOz":100,"buyerEmail":"procurement@example.com","shipTo":"Warehouse 4, Rotterdam","notes":"Palletized delivery preferred.","buyerAgentId":"agent-demo-01"}'

GET
/api/rfq/{rfqId}
Verify RFQ status without exposing buyer contact or destination data.
Public bearer-style read. The 26-character Crockford ULID is the possession token.

RfqPublicRead

HTTP 200
{
  "id": "01ARZ3NDEKTSV4RRFFQ69G5FAV",
  "quoteId": "01ARZ3NDEKTSV4RRFFQ69G5FAW",
  "status": "received",
  "createdAt": "2026-09-03T00:00:00.000Z",
  "nonTransactional": true,
  "isDemo": true
}

Shell request

curl -s /api/rfq/01ARZ3NDEKTSV4RRFFQ69G5FAV

03 / quote

Quote

Inspect the dated quote, then accept it idempotently if it is still eligible.

GET
/api/quotes/{quoteId}
Read the issued price, validity timestamp, and pricing version stamps.
Public bearer-style read by 26-character quote ULID; no Authorization header.

QuoteRead

HTTP 200
{
  "id": "01ARZ3NDEKTSV4RRFFQ69G5FAW",
  "rfqId": "01ARZ3NDEKTSV4RRFFQ69G5FAV",
  "listingId": "lst-anamalai-cardamom-a1",
  "listingName": "Bold Green Cardamom, A1 Grade",
  "requestedOz": 100,
  "pricedGrams": 2834,
  "pricePerGramMilliCents": 3240,
  "freightPerGramMilliCents": 410,
  "dutyPerGramMilliCents": 81,
  "insurancePerGramMilliCents": 16,
  "inboundHandlingPerGramMilliCents": 220,
  "unitLandedMilliCentsPerGram": 3967,
  "landedSubtotalCents": 11246,
  "shippingTotalCents": 2490,
  "marginTotalCents": 2812,
  "marginRateBp": 2500,
  "totalCents": 16548,
  "currency": "USD",
  "marginVersion": 2,
  "tierTableVersion": 1,
  "validUntil": "2026-09-10T00:00:00.000Z",
  "status": "received",
  "createdAt": "2026-09-03T00:00:00.000Z",
  "nonTransactional": true,
  "isDemo": true
}

Shell request

curl -s /api/quotes/01ARZ3NDEKTSV4RRFFQ69G5FAW

POST
/api/quotes/{quoteId}/accept
Accept an eligible quote and create or return its real unpaid order; this does not collect payment or create a payment link.
Public possession-of-id flow. Send no request body or Authorization header.

OrderAcceptedResponse

HTTP 200
{
  "id": "01ARZ3NDEKTSV4RRFFQ69G5FAX",
  "quoteId": "01ARZ3NDEKTSV4RRFFQ69G5FAW",
  "rfqId": "01ARZ3NDEKTSV4RRFFQ69G5FAV",
  "buyerEmail": "procurement@example.com",
  "shipTo": "Warehouse 4, Rotterdam",
  "notes": "Palletized delivery preferred.",
  "status": "accepted",
  "paymentState": "unpaid",
  "totalCents": 16548,
  "currency": "USD",
  "createdAt": "2026-09-03T00:00:00.000Z"
}

Shell request

curl -s -X POST /api/quotes/01ARZ3NDEKTSV4RRFFQ69G5FAW/accept

04 / order

Order verification

Verify the accepted order using a redacted response safe for public possession links.

GET
/api/orders/{orderId}
Verify lifecycle state, payment state, total, ids, and timestamps.
Public bearer-style read by 26-character order ULID; no Authorization header.

OrderVerificationRead

HTTP 200
{
  "id": "01ARZ3NDEKTSV4RRFFQ69G5FAX",
  "quoteId": "01ARZ3NDEKTSV4RRFFQ69G5FAW",
  "rfqId": "01ARZ3NDEKTSV4RRFFQ69G5FAV",
  "status": "accepted",
  "paymentState": "unpaid",
  "totalCents": 16548,
  "currency": "USD",
  "createdAt": "2026-09-03T00:00:00.000Z"
}

Shell request

curl -s /api/orders/01ARZ3NDEKTSV4RRFFQ69G5FAX

POST
/api/orders/{orderId}/mark-paid
Reconcile an unpaid order as paid and return its redacted verification state.
Founder-only. Send the configured FOUNDER_REVIEW_KEY in the x-founder-key header.

OrderMarkPaid JSON body

{
  "note": "Settled by founder review"
}

The note is optional and capped at 240 characters. The x-founder-key header is required; never expose its value in client code or logs.

Shell request

curl -s -X POST /api/orders/01ARZ3NDEKTSV4RRFFQ69G5FAX/mark-paid -H "x-founder-key: $FOUNDER_REVIEW_KEY" -H 'content-type: application/json' -d '{"note":"Settled by founder review"}'

Live workflow surfaces

Ids become verification links.

Use the ids from the RFQ receipt, quote read, and accepted order response to populate the live human-readable surfaces. The ids in this page are illustrative only; do not treat them as live records. The order verification view intentionally omits buyer email, shipTo, notes, and payment notes.

/quote/{quoteId}Review the issued quote.
/verify/rfq/{rfqId}Verify RFQ status.
/verify/quote/{quoteId}Verify quote status.
/verify/order/{orderId}Verify the redacted order.