raresats.net API
Trading API View as Markdown

Submit a listing

POST/api/market/listings

Step 3 of listing: the PSBT from POST /api/market/listings/prepare, every input signed SIGHASH_SINGLE|ANYONECANPAY (0x83). Everything is checked again against the chain and every signature verified before anything is stored. A new listing of an outpoint already listed replaces the old one (whose signature is deleted).

Request body #

content-type: application/json

FieldTypeRequiredDescription
psbtstringyesThe listing PSBT, every input signed with SIGHASH_SINGLE|ANYONECANPAY (0x83). Base64. Partially signed or finalized inputs are both accepted.

Example request #

cURL
curl -X POST 'https://raresats.net/api/market/listings' \
  -H 'content-type: application/json' \
  -d '{
  "psbt": "cHNidP8BAF4CAAAAAWroye3nyLiwpcNzDMmz2aV449rKtugMlDF04UqR1gmLAAAAAAD9////AfhvAQAAAAAAIlEgqC8plE1luGrmteXMdeKU6tbFk5Gh7cXgFuNJjGf8e7sAAAAAAAEBK4gYAAAAAAAAIlEgqC8plE1luGrmteXMdeKU6tbFk5Gh7cXgFuNJjGf8e7sBAwSDAAAAARNBTRvH6V6M7UvHRHSt9rxehNgXWjFx339UPLBrpakZUHtJWYdSEjJcKWGz0mMAzAntUr45lEpONbwi2QRK4vGr6IMBFyCD3+haMVHSUXKQ2kYf4oFVke9p8rGKLOY/AWl6izExRQAA"
}'
JavaScript
const response = await fetch('https://raresats.net/api/market/listings', {
  method: 'POST',
  headers: { 'content-type': 'application/json' },
  body: JSON.stringify({
    "psbt": "cHNidP8BAF4CAAAAAWroye3nyLiwpcNzDMmz2aV449rKtugMlDF04UqR1gmLAAAAAAD9////AfhvAQAAAAAAIlEgqC8plE1luGrmteXMdeKU6tbFk5Gh7cXgFuNJjGf8e7sAAAAAAAEBK4gYAAAAAAAAIlEgqC8plE1luGrmteXMdeKU6tbFk5Gh7cXgFuNJjGf8e7sBAwSDAAAAARNBTRvH6V6M7UvHRHSt9rxehNgXWjFx339UPLBrpakZUHtJWYdSEjJcKWGz0mMAzAntUr45lEpONbwi2QRK4vGr6IMBFyCD3+haMVHSUXKQ2kYf4oFVke9p8rGKLOY/AWl6izExRQAA"
  })
});
const data = await response.json();
Python
import requests

data = requests.post("https://raresats.net/api/market/listings", json={
    "psbt": "cHNidP8BAF4CAAAAAWroye3nyLiwpcNzDMmz2aV449rKtugMlDF04UqR1gmLAAAAAAD9////AfhvAQAAAAAAIlEgqC8plE1luGrmteXMdeKU6tbFk5Gh7cXgFuNJjGf8e7sAAAAAAAEBK4gYAAAAAAAAIlEgqC8plE1luGrmteXMdeKU6tbFk5Gh7cXgFuNJjGf8e7sBAwSDAAAAARNBTRvH6V6M7UvHRHSt9rxehNgXWjFx339UPLBrpakZUHtJWYdSEjJcKWGz0mMAzAntUr45lEpONbwi2QRK4vGr6IMBFyCD3+haMVHSUXKQ2kYf4oFVke9p8rGKLOY/AWl6izExRQAA"
}).json()

Response 200 #

FieldTypeDescription
listingsarray of ListingThe new listings, active, in input order.
warningstringPresent when a listing replaced here had a public signature (see exposed).
exposedarray of stringIds of replaced listings whose signature a broadcast purchase made public: their old price can still be taken until the UTXO moves.
Response
{
  "listings": [
    {
      "id": "3324d08569806818",
      "outpoint": "8b09d6914ae17431940ce8b6cadae378a5d9b3c90c73c3a5b0b8c8e7edc9e86a:0",
      "value": 6280,
      "price": 94200,
      "unit_price": 14,
      "row": "block9",
      "count": 6280,
      "rows": {"block9": 6280, "block9_1st_tx": 6280},
      "types": [
        {
          "types": ["block9", "nakamoto", "vintage"],
          "count": 6280,
          "sats": [45100023043, 45100023044, 45100023045]
        }
      ],
      "sats": 6280,
      "ranges": [[45100023043, 45100029322]],
      "years": {"2009": 6280},
      "seller_address": "bc1p4qhjn9zdvkux4e44uhx8tc55attvtyu358kutcqkudyccelu0was9fqzwh",
      "payout_address": "bc1p4qhjn9zdvkux4e44uhx8tc55attvtyu358kutcqkudyccelu0was9fqzwh",
      "status": "active",
      "created_at": 1790952985,
      "updated_at": 1790952985,
      "txid": null,
      "signature_public": false,
      "sold_via": null,
      "offer_id": null,
      "best_offer": null
    }
  ]
}

Errors #

{error, code}; see Errors for every code.

StatusCodeMeaning
400bad_itemsitems is not a list of 1-50 UTXOs (or the PSBT lists more), or an item's sats is not null or a list of sat numbers.
400bad_jsonThe body is not valid JSON.
400bad_priceA price is not a whole number of sats.
400bad_psbtNot a base64 PSBT, or one that does not parse.
400bad_requestThe body is not a JSON object, or the engine refused a malformed request (e.g. a purchase submitted without its signed setup PSBT).
400, 422bad_signature400: signature is missing or too long. 422: a signature does not verify (cancel or registration message, listing or purchase input).
400duplicate_outpointThe same UTXO twice in one listing.
403cross_originA POST from a browser on another site (a foreign Origin, or sec-fetch-site: cross-site). Server-side clients send no Origin and are not affected.
405method_not_allowedWrong method for the route; the allow header lists the right ones.
409changedThe UTXO's value is not what the PSBT says, or (wallet tools) a UTXO, its sats or the transaction being replaced changed since prepare: prepare again.
409pendingThe UTXO's listing is being bought, or an offer of it accepted, right now.
409spentThe UTXO (or a listing's UTXO) is spent or does not exist.
409unconfirmedThe UTXO is not confirmed yet.
409unindexedThe ord indexer does not know the UTXO yet.
409utxo_mismatchThe PSBT's amount or script of a UTXO is not the chain's.
413too_largeThe body is over 256 KiB.
415not_jsonA POST without content-type: application/json.
422bad_payoutA listed input is paired with an output that pays no address, or the payout address is the marketplace's fee address.
422bad_sequenceA listed input is not signed with sequence 0xfffffffd.
422bad_sighashA signature uses the wrong sighash type (listings: 0x83; purchases: DEFAULT or ALL).
422bad_structureThe listing PSBT is not the expected layout (pairing, version 2, locktime 0, one seller, sequences), or a purchase would pay the fee address.
422inscribedThe UTXO carries an inscription: only rare sats are listed; the wallet tools only send it whole.
422legacy_addressA legacy (P2PKH, 1…) address: use Taproot or SegWit.
422missing_signatureAn input that must be signed is not.
422no_rowThe UTXO holds no sat of a market row.
422not_ownerThe UTXO does not belong to the seller address, or (wallet tools) to the owner's addresses, or the transfer was made by another wallet.
422price_too_highThe price is above 21,000,000 BTC.
422price_too_lowThe price is at most the UTXO's own value, below 546 sats, or below the payout output's dust limit.
422runesThe UTXO carries runes (the wallet tools only send it whole).
422too_many_itemsToo many UTXOs in a listing, or listings in a purchase (max_bulk); for a wallet transfer, too many rare sats (and the runs between them) to lay out in one UTXO: choose fewer.
422unsupported_addressAn address type the marketplace does not trade (only Taproot, native SegWit and nested SegWit).
422unsupported_scriptThe trade engine met a script type it does not support.
422untrackedThe UTXO holds no rare sat the index tracks (send it whole instead).
429rate_limitedOver 30 POSTs a minute from your IPv4 address or IPv6 /64 (in chat, counted per IPv4 address or IPv6 /64: 30 writes and 20 login nonces a minute, 20 sign-ins and 10 display-name changes an hour; one message every 3 s and 20 a minute per address); wait retry-after seconds. With the AI moderation on, at most 6 messages and names a minute are checked per address and per IPv4 address or IPv6 /48.
503bitcoind_unavailablebitcoind is not available.
503engine_unavailableThe trade engine is not available.
503fork_behindThe rare-sat index has not caught up with bitcoind: try again in a minute.
503fork_unavailableThe rare-sat index is not available.
503indexer_behindThe ord indexer is catching up: try again shortly.
503market_unavailableThe marketplace is closed right now (its backends disagree on the network, or are unreachable).
503oracle_unavailableThe ord oracle is not available.
Error (400)
{
  "error": "Listing signature (input 0): the signature does not verify",
  "code": "bad_signature"
}
  • Every rule of prepare is checked again, and each signature is verified against the chain's amount and script of its UTXO: Schnorr over the BIP341 sighash for Taproot (65 bytes, ending in 0x83), low-S ECDSA over the BIP143 sighash for SegWit v0 (DER, ending in 0x83).
  • Listing a UTXO that is already listed replaces the old listing: it becomes cancelled and its signature is deleted. That is how a price is changed.
  • warning and exposed appear when a replaced listing's signature was already public (see Cancel listings).