raresats.net API
Market data View as Markdown

Address activity

GET/api/address/{address}/activity

What an address bought and sold (every marketplace), listed and cancelled on raresats.net, extracted, mined and moved, newest first, with filter facets and totals. Transfers and extractions come from the index's per-address history (from the ordinals era) where it has one, read as far as the pages asked for need it; else from the moves it keeps (about 4 weeks); before either, the address's held UTXOs. coverage says which and how far; summary.partial says when the totals cover only the history read so far. Pages follow next (pass it as before), which does not drift when newer activity arrives. Cacheable 15 s. The first page (no before, no to) leads with the address's pending items (pending: true, source: mempool), outside limit, total and the facets; pending=0 leaves them out. A sale here the index shows pending is listed once, as the index's.

Path parameters #

ParameterTypeRequiredDescription
addressstringyesA mainnet address.

Query parameters #

ParameterTypeRequiredDescription
typesstringnoComma-separated activity types: bought, sold, listed, cancelled, extraction, mined, transfer_in, transfer_out, consolidation.
rowstringnoOnly activity of this row (collection) id.
marketplacestringnoOnly sales and listings of this marketplace id (magisat, magic_eden, raresats, …).
yearintegernoOnly activity of this UTC year. (min 2009)
fromstringnoOnly activity on or after this UTC day, YYYY-MM-DD.
tostringnoOnly activity on or before this UTC day, YYYY-MM-DD.
limitintegernoPage size, at most 200. Default: 50. (min 1, max 200)
beforestringnoThe previous page's next.
pendingstringno0 leaves the pending (mempool) items out. One of: 0, 1. Default: 1.

Example request #

cURL
curl 'https://raresats.net/api/address/bc1p5cyxnuxmeuwuvkwfem96lqzszd02n6xdcjrs20cac6yqjjwudpxqkedrcr/activity?types=bought,sold'
JavaScript
const response = await fetch('https://raresats.net/api/address/bc1p5cyxnuxmeuwuvkwfem96lqzszd02n6xdcjrs20cac6yqjjwudpxqkedrcr/activity?types=bought,sold');
const data = await response.json();
Python
import requests

data = requests.get("https://raresats.net/api/address/bc1p5cyxnuxmeuwuvkwfem96lqzszd02n6xdcjrs20cac6yqjjwudpxqkedrcr/activity", params={"types": "bought,sold"}).json()

Response 200 #

FieldTypeDescription
addressstringThe address.
as_ofobject | null{height, time} of the index.
explorerstring | nullBlock explorer base URL.
coverageobjectHow complete each source is.
coverage.salesstringSales: every one, from the sales index. One of: complete, loading, unavailable.
coverage.transfersstringsince block N: transfers and extractions from block N on (the history's start, or the retained moves'), and before it only the held UTXOs; complete (a history from genesis, read whole); holdings (only the held UTXOs); or unavailable.
coverage.transfers_sinceinteger | nullN of since block N; null when complete.
coverage.sourcestring | nullWhere transfers come from. One of: fork_history, moves_window, holdings, null.
coverage.history_fromobjectWhere the per-address history begins (the ordinals era, the fork's address_history_from_height): {height, time}.
coverage.history_from.heightinteger
coverage.history_from.timeinteger | null
coverage.history_completebooleanWhether the whole history has been read (the fork has no more pages). Until then the totals and facets cover the history read so far, and pages read further as they go.
coverage.loaded_sinceinteger | nullWhile the history is read in part: the oldest block read so far.
coverage.loaded_since_timeinteger | nullIts time, unix seconds.
coverage.marketstringraresats.net listings. One of: complete, off, unavailable.
coverage.errorstringSet when the index could not be read: transfers may be missing.
summaryobjectTotals over all of the address's activity known (no filter): sales and listings whole, the history as far as read.
summary.boughtobject
summary.bought.countinteger
summary.bought.volumeintegerSats.
summary.soldobject
summary.sold.countinteger
summary.sold.volumeintegerSats.
summary.extractionsinteger
summary.listedinteger
summary.transfersintegerTransfers, consolidations and mined.
summary.first_timeinteger | nullUnix seconds of the first activity shown.
summary.last_timeinteger | nullUnix seconds of the last.
summary.partialbooleanTrue while the history is read in part: the extraction and transfer counts and the first activity cover the history read so far.
facetsobjectCounts for the filters, each under every other filter set, over the activity known (the history as far as read).
facets.typesmap of integerBy type.
facets.rowsmap of integerBy row id.
facets.yearsmap of integerBy UTC year.
facets.marketplacesmap of integerBy marketplace id.
rowsmap of objectThe rows named on the page and in the facets: label and types.
rows.<key>.labelstring
rows.<key>.all_ofarray of string
queryobjectThe filters applied.
totalintegerEvents matching the filters among those known (the history as far as read; see summary.partial).
itemsarray of objectOne page, newest first.
items[].idstringStable id (the cursor names it).
items[].typestringWhat happened, from the address's side. One of: bought, sold, listed, cancelled, extraction, mined, transfer_in, transfer_out, consolidation.
items[].timeintegerUnix seconds: the block's time, or the marketplace event's.
items[].heightinteger | nullBlock height; null for an event off the chain (a listing).
items[].tx_indexinteger | nullPlace in the block (null while pending).
items[].txidstring | nullTransaction id; null for a listing.
items[].tx_urlstring | nullThe transaction on the block explorer.
items[].satobject | nullThe lead sat (the rarest moved, the first sold).
items[].sat.satinteger
items[].sat.typesarray of string
items[].countinteger | nullTracked sats involved.
items[].rowstring | nullThe main row id (its rarest).
items[].rowsarray of stringEvery row id the event counts toward (the category filter).
items[].priceinteger | nullSale or listing price, sats.
items[].unit_pricenumber | nullPrice per sat of row, over the sold output's own value.
items[].marketplacestring | nullMarketplace id, for sales and listings.
items[].inscribedboolean | nullA sale of an inscribed sat.
items[].outlierboolean | nullA sale far from its row's median.
items[].secondarymap of integerA sale's secondary rows: the market rows of the other sats it sold (not its own row, a row it is a sub-category of, or a label row), each with its sats, primary-first: {"black_omega": 1} for a black omega sold with an alpha uncommon; {} for none. A sale never counts in its secondary rows' markets (the primary-sat rule, in Concepts).
items[].valueinteger | nullSats in the UTXOs received or sent, for a transfer.
items[].extractedboolean | nullThe rare sats arrived in (or left) an extracted UTXO.
items[].counterpartystring | nullThe other side's main address: the seller of a purchase, the buyer of a sale, the sender or recipient of a transfer.
items[].counterpartiesinteger | nullHow many addresses were on the other side.
items[].sourcestringWhere it comes from: the sales index, the marketplace, the per-address history, the retained moves, a held UTXO's creation, or the index's mempool overlay (pending). One of: sales, market, history, moves, holdings, mempool.
items[].seqintegerThe sale's sequence number (sales only).
items[].outpointstring | nullThe listed UTXO (listings only).
items[].burnbooleanA transfer_out to an unspendable output.
items[].pendingbooleanNot yet in a block: a pending transaction (source: mempool, with first_seen and fee_rate, no height), or a sale bought or sold on raresats.net the index has not read yet (source: market). Only the first page lists the former, first.
items[].first_seeninteger | nullWhen the transaction was first seen in the mempool (bitcoind's entry time), unix seconds.
items[].fee_ratenumber | nullIts fee rate, sat/vB (one decimal).
nextstring | nullThe cursor of the next page (pass as before), or null at the end. While the history is read in part, a page may hold fewer events than limit, even none, with a next that reads further.
pending_totalintegerPending items leading items (first page only; outside total, the facets and the summary).

Errors #

{error} (a message, no code):

StatusWhen
400Not an address, or a malformed parameter or cursor.
404A retired row (uncommon_2009, rare_2009): its retired field names the row and years to ask for instead.
503Too many lookups at once.

The address page's Activity tab reads this route. One list, newest first, merges:

TypeFromComplete
bought, soldthe sales index (every marketplace)yes
listed, cancelledraresats.netyes
extraction, mined, transfer_in, transfer_out, consolidationthe index's per-address history, else the moves it keepssee coverage

A transaction that is one of the address's sales is shown once, as the sale; a sale of a bundle names its secondary rows (the other sats sold with its row). A raresats.net purchase shows as pending until its block is read.

Pending. The first page (no before, no to) leads with the address's transactions still in the mempool: sales it is selling or buying, transfers in and out, extractions. Each has pending: true, source: "mempool", first_seen, fee_rate, and no height. They match the type, row and date filters but sit outside limit, total, the facets and summary (pending_total counts them); once mined they come back as ordinary items. A raresats.net purchase the index already shows pending is listed once, as the index's item. pending=0 leaves them out. See Pending.

coverage.transfers is since block N: transfers and extractions are whole from block N, where the index's per-address history starts (the ordinals era, coverage.history_from). Before block N, only the UTXOs the address still holds are listed, as transfer_in items with source: "holdings". Until the index serves the history, transfers cover the moves it keeps, about 4 weeks.

A busy address has tens of thousands of entries, so the history is read lazily: each page reads as much of it as it needs, newest first. Until all of it has been read, coverage.history_complete is false, coverage.loaded_since says how far back it goes so far, and summary.partial is true. In that case the extraction and transfer counts, the facets and total cover the history read so far. Sales and listings are always whole. Type, row and date filters are passed down to the index, so a filtered page skips what cannot match.

facets count each filter's values under the other filters, so a chip can say what choosing it would show. summary totals everything known, whatever the filters.

To page, pass next as before with the same filters. The cursor names the last event shown, so newer activity arriving at the top shifts nothing. While the history is still being read, a page may hold fewer events than limit, even none, with a next that reads further. Keep following next until it is null.

curl 'https://raresats.net/api/address/bc1p5cyxnuxmeuwuvkwfem96lqzszd02n6xdcjrs20cac6yqjjwudpxqkedrcr/activity?types=bought,sold&limit=20'