raresats.net API
Wallet tools API View as Markdown

List an address's wallet transfers

GET/api/market/transfers

The transfers built with the wallet tools that an address took part in (as payment or ordinals address), newest first. Each names only that address's part (owner_role).

Query parameters #

ParameterTypeRequiredDescription
addressstringyesA payment or ordinals address.
statusstringnopending (what you still have to watch: in the mempool, not yet known, or dropped in a chain of replacements that pays someone else, which a cancel voids) or all (default). One of: pending, all.
limitintegerno1-100, default 20. (min 1, max 100)

Example request #

cURL
curl 'https://raresats.net/api/market/transfers?address=bc1p5cyxnuxmeuwuvkwfem96lqzszd02n6xdcjrs20cac6yqjjwudpxqkedrcr&status=all&limit=5'
JavaScript
const response = await fetch('https://raresats.net/api/market/transfers?address=bc1p5cyxnuxmeuwuvkwfem96lqzszd02n6xdcjrs20cac6yqjjwudpxqkedrcr&status=all&limit=5');
const data = await response.json();
Python
import requests

data = requests.get("https://raresats.net/api/market/transfers", params={"address": "bc1p5cyxnuxmeuwuvkwfem96lqzszd02n6xdcjrs20cac6yqjjwudpxqkedrcr", "status": "all", "limit": 5}).json()

Response 200 #

FieldTypeDescription
transfersarray of objectNewest first.
transfers[].idstringThe prepared transfer's id.
transfers[].txidstringIts transaction id (what /tx/{txid} shows).
transfers[].kindstringOne of: extract, send, send_n, chop, consolidate, multisend, speedup, cancel.
transfers[].statusstringpending in the mempool; confirmed in a block; replaced by a speed-up or cancel built here (replaced_by); conflicted: a block spent its inputs and it was provably not mined (its own outputs never appeared within six blocks); dropped: in no mempool and its inputs unspent (it may still resurface until voided); unknown: the broadcast's outcome is not known yet; rejected: bitcoind refused it, so it was never sent and cannot resurface.
transfers[].created_atintegerUnix seconds.
transfers[].updated_atintegerUnix seconds.
transfers[].ownerobjectThe owner's addresses (one transfer's read).
transfers[].owner.payment_addressstringPaid the fees.
transfers[].owner.ordinals_addressstringThe ordinals address.
transfers[].owner_rolestringThe queried address's part in it (a list read). One of: payment, ordinals, both.
transfers[].destinationstring | nullWhere the moved sats went (null for a multisend).
transfers[].fee_ratenumbersat/vB.
transfers[].network_feeintegerSats.
transfers[].tools_feeintegerThe flat raresats.net fee it paid, in sats.
transfers[].vsizeintegerIts size in vbytes.
transfers[].replacesstring | nullThe transfer it replaced (speed-up, cancel).
transfers[].replaced_bystring | nullThe transaction that replaced it.
transfers[].block_heightinteger | nullThe block it confirmed in.
transfers[].outputsarray of objectIts outputs.
transfers[].outputs[].indexintegervout.
transfers[].outputs[].addressstring | nullWho it pays.
transfers[].outputs[].valueintegerSats.
transfers[].outputs[].rolestringdest, return, plain_return, tools_fee or change.
transfers[].actionsobjectWhat its owner can do now.
transfers[].actions.speedupbooleanIt is pending: a speed-up can replace it.
transfers[].actions.cancelbooleanIt could still confirm (pending, unknown, dropped) and its chain of replacements pays someone else: a cancel (or a void) sends its sources back. It never hides a cancel the prepare would allow; the prepare decides with the mempool (409 nothing_to_cancel).
totalintegerHow many transfers match without limit (with status=pending: everything you still have to watch).
Response
{
  "transfers": [
    {
      "id": "6baec47455bf8df8",
      "txid": "a1edadb9e3b45097d272621ea8adcbee697281bd4d611462db134292d4e1cf9c",
      "kind": "extract",
      "status": "pending",
      "created_at": 1791428236,
      "updated_at": 1791428236,
      "owner_role": "ordinals",
      "destination": "bc1p5cyxnuxmeuwuvkwfem96lqzszd02n6xdcjrs20cac6yqjjwudpxqkedrcr",
      "fee_rate": 3,
      "network_fee": 1059,
      "tools_fee": 1000,
      "vsize": 352,
      "replaces": null,
      "replaced_by": null,
      "block_height": null,
      "outputs": [
        {
          "index": 0,
          "address": "bc1p5cyxnuxmeuwuvkwfem96lqzszd02n6xdcjrs20cac6yqjjwudpxqkedrcr",
          "value": 388,
          "role": "return"
        },
        {
          "index": 1,
          "address": "bc1p5cyxnuxmeuwuvkwfem96lqzszd02n6xdcjrs20cac6yqjjwudpxqkedrcr",
          "value": 330,
          "role": "dest"
        },
        {
          "index": 2,
          "address": "37VucYSaXLCAsxYyAPfbSi9eh4iEcbShgf",
          "value": 9282,
          "role": "plain_return"
        },
        {
          "index": 3,
          "address": "bc1p4hefchfnn06cn2xmk6fq6xcw5ew260q2dptc4c35fcazgedmzlcqkxf057",
          "value": 1000,
          "role": "tools_fee"
        },
        {
          "index": 4,
          "address": "37VucYSaXLCAsxYyAPfbSi9eh4iEcbShgf",
          "value": 22941,
          "role": "change"
        }
      ],
      "actions": {"speedup": true, "cancel": false}
    }
  ],
  "total": 1
}

Errors #

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

StatusCodeMeaning
400bad_addressAn address is not a mainnet address (or not one at all).
400bad_paginglimit or offset out of range.
400bad_statusstatus is not all or a comma-separated list of offer statuses, or (wallet transfers) not pending or all.
422legacy_addressA legacy (P2PKH, 1…) address: use Taproot or SegWit.
422unsupported_addressAn address type the marketplace does not trade (only Taproot, native SegWit and nested SegWit).
503market_unavailableThe marketplace is closed right now (its backends disagree on the network, or are unreachable).
Error (400)
{"error": "address must be an address", "code": "bad_address"}

These are the transfers built with the wallet tools (Prepare a transfer), not the site's feed of notable rare-sat transfers (GET /api/transfers, see Supply, rows and status). Each record shows only the queried address's side (owner_role). This is not a privacy boundary: a transfer spends from both of the wallet's addresses in one transaction, which links them on chain anyway.

status=pending lists what you still have to watch: transfers in the mempool or whose broadcast is not known yet, and dropped transfers of a replacement chain that pays someone else (the transfer itself, or an original it replaced by a speed-up or cancel). A signed transaction that left the mempool can resurface and confirm until something else spends its inputs; a cancel of the listed one spends every input of the chain, so it voids them all. A dropped transfer whose chain pays only your own addresses is not listed: if it resurfaces, the sats still end up in your wallet. total counts the matching transfers without limit.

To follow changes live, listen for the transfer event of Live events: it names the addresses whose transfers changed, then read this again.