# Supply, rows and status

The dashboard's own feeds: what its Statistics, Transfers and Extractions views show. Briefly documented; their shapes follow the rare-sat index and may grow.

## Supply

`GET /api/supply`

The latest supply of every row (`supply`: `{height, hash, time, rows}`, each row with `total`, `stats` and `active_non_extracted`), the row definitions (`rows`) and their groups (`groups`). A row the site shows as a sub-category of another although its types do not say so names that row in `sub_of`: the milestone alphas (`kilosat_alpha`, `decasat_alpha`, `centasat_alpha`, `megasat_alpha`), labelled Kilosat, Decasat, Centasat and Megasat uncommon, are sub-categories of `uncommon`, and the milestone omegas (`kilosat_omega`, `decasat_omega`, `centasat_omega`, `megasat_omega`), labelled Kilosat, Decasat, Centasat and Megasat black, of `black`. With `years`, every row's supply over the sats mined in those years (rows with none have zeros), and `years` echoed; with `luck`, over the sats mined in blocks of those lucks, and `luck` echoed (`{min, max}`, `max` null for "or more"); with `month`, over the sats mined in that month, and `month` echoed.

#### Query parameters

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `years` | string | no | Only the sats mined in these years: comma-separated years (YYYY) blocks were mined in, at most 64 (`year` is accepted too). Counters are the years' sums, `total` and `mined` their sats mined so far, `holders` and `extracted_holders` the addresses holding sats of any of them (exact). Needs a rare-sat index with a year breakdown (`fork.status.year_stats` in `/api/status`), else 501. |
| `luck` | string | no | Only the sats mined in blocks of these lucks: `N` (luck N or more) or `N-M`, from 0 to the index's highest luck (31, which also counts any luckier block). A block's luck is the leading zero bits of its hash beyond its target's. Counters are the lucks' sums, `holders` and `extracted_holders` the addresses holding sats of any of them (exact). Not with `years` (400): the supply is broken down by one or the other. Needs a rare-sat index with a luck breakdown (`fork.status.luck_stats` in `/api/status`), else 501. |
| `month` | string | no | Only the sats mined in this month (UTC, `YYYY-MM`), one a block was mined in (`months` is accepted too). Counters, `holders` and `extracted_holders` are the month's own (exact). Not with `years` or `luck` (400): the supply is broken down by one of them. Needs a rare-sat index with a month breakdown (`fork.status.month_stats` in `/api/status`, index schema 7), else 501. |

#### Example request

```bash title="cURL"
curl 'https://raresats.net/api/supply?years=2009,2010&luck=10&month=2017-12'
```
```js title="JavaScript"
const response = await fetch('https://raresats.net/api/supply?years=2009,2010&luck=10&month=2017-12');
const data = await response.json();
```
```python title="Python"
import requests

data = requests.get("https://raresats.net/api/supply", params={"years": "2009,2010", "luck": "10", "month": "2017-12"}).json()
```

#### Response `200`

A JSON object.

#### Errors

`{error}` (a message, no code):

| Status | When |
| --- | --- |
| 400 | Malformed years, a year no block was mined in, a malformed luck or one past the index's highest, a malformed month or one no block was mined in, or more than one of years, a luck and a month. |
| 501 | The rare-sat index has no year (luck, month) breakdown (`years`, `luck` or `month` asked of an older index). |
| 502 | The index answered with an error. |
| 503 | The index is unavailable. |

### By mint year

Every number of the supply can be narrowed to the sats mined in some years: `?years=2009` on `/api/supply` and `/api/rows/{id}`, or several years (`?years=2009,2010`). The counters of a set of years add up, but for the holders, which count each address once however many of the years it holds sats of. `?years=2009` gives the same numbers the 2009 rows did: `uncommon_2009` and `rare_2009` are retired, and `/api/rows/uncommon?years=2009` is what `/api/rows/uncommon_2009` was (the latter now answers 404 with a `retired` field naming the row and years to ask for, as does every route taking `row=`; `/collection/uncommon_2009` redirects to `/collection/uncommon?year=2009`). Every year's numbers at once:

`GET /api/supply/years`

Every row's supply split by the year its sats were mined: `{height, hash, time, years: [{year, from_height, to_height}], rows: [{id, years: {"2009": {total, stats, active_non_extracted}}}]}`, a row listing only the years it has sats of. What the year chips count; cached per block. Needs a rare-sat index with a year breakdown (`fork.status.year_stats` in `/api/status`), else 501.

#### Example request

```bash title="cURL"
curl 'https://raresats.net/api/supply/years'
```
```js title="JavaScript"
const response = await fetch('https://raresats.net/api/supply/years');
const data = await response.json();
```
```python title="Python"
import requests

data = requests.get("https://raresats.net/api/supply/years").json()
```

#### Response `200`

A JSON object.

#### Errors

`{error}` (a message, no code):

| Status | When |
| --- | --- |
| 501 | The rare-sat index has no year breakdown. |
| 502 | The index answered with an error. |
| 503 | The index is unavailable. |

### By block luck

The same numbers can be narrowed to the sats mined in lucky blocks instead: `?luck=10` (blocks of luck 10 or more) or `?luck=10-12` on `/api/supply` and `/api/rows/{id}`. A block's luck is the leading zero bits of its hash beyond its target's: most blocks are luck 0 to 3, about one in eight hundred is 10 or more. The holders count each address once, as for years; a luck lists no top holders. Years and a luck do not combine in the supply (a 400): the index breaks it down by one or the other. Every luck's numbers at once, with the blocks of each luck:

`GET /api/supply/lucks`

Every row's supply split by the luck of the blocks its sats were mined in: `{height, hash, time, lucks: [{luck, blocks}], rows: [{id, lucks: {"12": {total, stats, active_non_extracted}}}]}`, a row listing only the lucks it has sats of (`lucks`: the blocks of each luck). What the luck selects count; cached per block. Needs a rare-sat index with a luck breakdown (`fork.status.luck_stats` in `/api/status`), else 501.

#### Example request

```bash title="cURL"
curl 'https://raresats.net/api/supply/lucks'
```
```js title="JavaScript"
const response = await fetch('https://raresats.net/api/supply/lucks');
const data = await response.json();
```
```python title="Python"
import requests

data = requests.get("https://raresats.net/api/supply/lucks").json()
```

#### Response `200`

A JSON object.

#### Errors

`{error}` (a message, no code):

| Status | When |
| --- | --- |
| 501 | The rare-sat index has no luck breakdown. |
| 502 | The index answered with an error. |
| 503 | The index is unavailable. |

### By mint month

Or to the sats mined in one month (UTC): `?month=2017-12` on `/api/supply` and `/api/rows/{id}`. A month is one at a time, with its own holders (exact) and top holders; it does not combine with years or a luck (a 400). A month is counted as its year is, by the running latest block time, so a year's months add up to it; five blocks of mainnet (272,376 to 272,380) whose own time is 30 November 2013 count in December 2013, where the chain's time already was. Every month's numbers at once, compactly (an array of counters per month, in the order `fields` names them):

`GET /api/supply/months`

Every row's supply split by the month (UTC) its sats were mined in, compactly: `{height, hash, time, months: [{month, from_height, to_height}], fields: ["mined", "located", "burned", "lost", "overwritten", "extracted", "holders", "extracted_holders", "inscribed"], rows: [{id, months: {"2017-12": [counts in the order of fields]}}]}`, a row listing only the months it has sats of. What a collection's month select counts; cached per block. Needs a rare-sat index with a month breakdown (`fork.status.month_stats` in `/api/status`), else 501.

#### Example request

```bash title="cURL"
curl 'https://raresats.net/api/supply/months'
```
```js title="JavaScript"
const response = await fetch('https://raresats.net/api/supply/months');
const data = await response.json();
```
```python title="Python"
import requests

data = requests.get("https://raresats.net/api/supply/months").json()
```

#### Response `200`

A JSON object.

#### Errors

`{error}` (a message, no code):

| Status | When |
| --- | --- |
| 501 | The rare-sat index has no month breakdown. |
| 502 | The index answered with an error. |
| 503 | The index is unavailable. |

The sales beside these numbers (the Statistics' Last, 30-day median and volume, and a row's sales chart) follow the same filter: `/api/sales/stats?years=2009` and `/api/sales?row=alpha_uncommon&years=2009` count only the sales of the row's sats mined in 2009, the very sales the collection's Activity lists with `?year=2009` (see [Sales stats](https://raresats.net/docs/get-sales-stats.md)). So does a month (`?month=2017-12`), on any index: the sales are matched on this side, by each block's own day.

## Sat type explainers

The text of the site's `/types` pages: what each sat type, category and concept is, with its categories' live numbers.

`GET /api/types`

Every explainer page of `/types` (one per sat type, category and concept), by section: `sections` (`[{id, label, pages: [{slug, title, summary, href}]}]`), and which page explains each row (`rows`: `{rowId: slug}`) and each sat type (`badges`: `{type: slug}`). The text comes from the site's own pages; the page is `/types/{slug}`.

#### Example request

```bash title="cURL"
curl 'https://raresats.net/api/types'
```
```js title="JavaScript"
const response = await fetch('https://raresats.net/api/types');
const data = await response.json();
```
```python title="Python"
import requests

data = requests.get("https://raresats.net/api/types").json()
```

#### Response `200`

A JSON object.

```json title="Response"
{
  "sections": [
    {
      "id": "rarity",
      "label": "Rarity tiers",
      "pages": [
        {
          "slug": "uncommon",
          "title": "Uncommon",
          "summary": "The first sat of a block: the lowest rarity tier above common in ordinal theory, one per block bar the few whose first sat ranks higher.",
          "href": "/types/uncommon"
        }
      ]
    }
  ],
  "rows": {"uncommon": "uncommon"},
  "badges": {"uncommon": "uncommon"}
}
```

#### Errors

None of its own.

`GET /api/types/{slug}`

One explainer: `slug`, `title`, `summary`, `kind` and `kind_label` (its section), `badges` (the sat types it explains), `body` (its text as a tree of blocks: `{t: 'h3'|'h4', id, c}`, `{t: 'p', c}`, `{t: 'ul'|'ol', items: [c]}`, where `c` lists inlines: a string, `{t: 'a', href, c, ext?}`, `{t: 'b'|'i', c}`, `{t: 'code', text}` or `{t: 'n', row, field}`, a live number found in `numbers[row][field]`), `rows` (the categories it explains, each with `total`, `mined`, `extracted`, `holders`, `inscribed` and `market`: `last_unit_price`, `median_30d`, `sales`, and while the marketplace is on `floor_unit` and `listed`), `also_in` (other categories holding its types), `related` pages and `as_of` (the block the numbers are of).

#### Path parameters

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `slug` | string | yes | The page's slug, as `/api/types` lists them. |

#### Example request

```bash title="cURL"
curl 'https://raresats.net/api/types/uncommon'
```
```js title="JavaScript"
const response = await fetch('https://raresats.net/api/types/uncommon');
const data = await response.json();
```
```python title="Python"
import requests

data = requests.get("https://raresats.net/api/types/uncommon").json()
```

#### Response `200`

A JSON object.

#### Errors

`{error}` (a message, no code):

| Status | When |
| --- | --- |
| 404 | No such page. |

## A row

`GET /api/rows/{id}`

One row: `row` (its supply stats, extracted and non-extracted top holders, label, group and definition) and `history` (extracted and located counts over time). With `years`, over the sats mined in those years (`years` echoed): one year lists its own top holders (at most 100 per list), a set of years none (`null`), and the history's holder counts are `null` for a set. With `luck`, over the sats mined in blocks of those lucks (`luck` echoed): no top holders (`null`), and the history's holder counts are `null` but for a single luck or every luck. With `month`, over the sats mined in that month (`month` echoed): its own top holders (at most 100 per list) and holder counts in its history.

#### Path parameters

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | yes | The row id. |

#### Query parameters

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `range` | string | no | History range. One of: `all`, `4y`, `1y`, `90d`, `30d`. Default: `all`. |
| `top` | integer | no | Holders per list, 1-1000. Default: `100`. (min 1, max 1000) |
| `years` | string | no | Only the sats mined in these years: comma-separated years (YYYY) blocks were mined in, at most 64 (`year` is accepted too). Counters are the years' sums, `total` and `mined` their sats mined so far, `holders` and `extracted_holders` the addresses holding sats of any of them (exact). Needs a rare-sat index with a year breakdown (`fork.status.year_stats` in `/api/status`), else 501. |
| `luck` | string | no | Only the sats mined in blocks of these lucks: `N` (luck N or more) or `N-M`, from 0 to the index's highest luck (31, which also counts any luckier block). A block's luck is the leading zero bits of its hash beyond its target's. Counters are the lucks' sums, `holders` and `extracted_holders` the addresses holding sats of any of them (exact). Not with `years` (400): the supply is broken down by one or the other. Needs a rare-sat index with a luck breakdown (`fork.status.luck_stats` in `/api/status`), else 501. |
| `month` | string | no | Only the sats mined in this month (UTC, `YYYY-MM`), one a block was mined in. Not with `years` or `luck` (400). Needs a rare-sat index with a month breakdown (`fork.status.month_stats`), else 501. |

#### Example request

```bash title="cURL"
curl 'https://raresats.net/api/rows/uncommon?years=2009&luck=10&month=2017-12'
```
```js title="JavaScript"
const response = await fetch('https://raresats.net/api/rows/uncommon?years=2009&luck=10&month=2017-12');
const data = await response.json();
```
```python title="Python"
import requests

data = requests.get("https://raresats.net/api/rows/uncommon", params={"years": "2009", "luck": "10", "month": "2017-12"}).json()
```

#### Response `200`

A JSON object.

#### Errors

`{error}` (a message, no code):

| Status | When |
| --- | --- |
| 400 | A malformed parameter, or both years and a luck, a malformed month or one no block was mined in, or more than one of years, a luck and a month. |
| 404 | No such row. A retired row (`uncommon_2009`, `rare_2009`) answers 404 too, its `retired` field naming the row and years to ask for instead. |
| 501 | The rare-sat index has no year (luck, month) breakdown. |
| 503 | The index is unavailable. |

## Notable transfers

The first page of both feeds (no `before`, `offset` 0) also has `pending`: the notable events of transactions still in the mempool, judged by the same rules as if mined in the next block, outside `total` ([Pending](#pending-the-mempool)).

`GET /api/transfers`

Notable transfers of rare sats, newest first: `{total, offset, items}`. Page with `before` (an event id) or `offset`. The first page (no `before`, `offset` 0) also has `pending`: the notable transfers of transactions still in the mempool, newest first, outside `total`.

#### Query parameters

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `before` | string | no | An event id: the events after it. |
| `offset` | integer | no | Events to skip. Default: `0`. (min 0) |
| `limit` | integer | no | Events, 1-1000. Default: `200`. (min 1, max 1000) |

#### Example request

```bash title="cURL"
curl 'https://raresats.net/api/transfers'
```
```js title="JavaScript"
const response = await fetch('https://raresats.net/api/transfers');
const data = await response.json();
```
```python title="Python"
import requests

data = requests.get("https://raresats.net/api/transfers").json()
```

#### Response `200`

A JSON object.

#### Errors

`{error}` (a message, no code):

| Status | When |
| --- | --- |
| 400 | A malformed parameter. |
| 404 | `before` is no longer held: reload. |

## Notable extractions

`GET /api/extractions`

Notable extractions (rare sats newly isolated), newest first, paged like transfers. The first page also has `pending`, as transfers.

#### Query parameters

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `before` | string | no | An event id: the events after it. |
| `offset` | integer | no | Events to skip. Default: `0`. (min 0) |
| `limit` | integer | no | Events, 1-1000. Default: `200`. (min 1, max 1000) |

#### Example request

```bash title="cURL"
curl 'https://raresats.net/api/extractions'
```
```js title="JavaScript"
const response = await fetch('https://raresats.net/api/extractions');
const data = await response.json();
```
```python title="Python"
import requests

data = requests.get("https://raresats.net/api/extractions").json()
```

#### Response `200`

A JSON object.

#### Errors

`{error}` (a message, no code):

| Status | When |
| --- | --- |
| 400 | A malformed parameter. |
| 404 | `before` is no longer held: reload. |

## Pending (the mempool)

`GET /api/pending`

Every pending sale, notable transfer and extraction of transactions still in the mempool, the live listings being spent, and the transactions that left the mempool lately, from the index's mempool overlay (polled every 5 s). Pending items are marked `pending: true` with `first_seen` and `fee_rate`, and count in no stat. A pending sale is `txid:vin`, a move its `txid`: the confirmed record with the same key replaces it. The SSE `mempool` event says when to read it again. `available` is false against an index without the overlay.

#### Example request

```bash title="cURL"
curl 'https://raresats.net/api/pending'
```
```js title="JavaScript"
const response = await fetch('https://raresats.net/api/pending');
const data = await response.json();
```
```python title="Python"
import requests

data = requests.get("https://raresats.net/api/pending").json()
```

#### Response `200`

| Field | Type | Description |
| --- | --- | --- |
| `available` | boolean | Whether the index serves the mempool overlay and it has been read. |
| `seq` | integer \| null | The overlay's change counter: it moves with every change. |
| `height` | integer \| null | The index tip the overlay is consistent with; pending items are judged as of the next block. |
| `txs` | integer | Pending transactions that move tracked sats. |
| `sales` | array of object | Pending sales, newest first. |
| `sales[].seq` | null | No sequence number until it confirms. |
| `sales[].t` | integer \| null | `first_seen`: sorted by time, it leads the confirmed sales. |
| `sales[].h` | null | No block yet. |
| `sales[].row` | string | The sale's own row. |
| `sales[].u` | number \| null | Unit price: premium per sat of the row. |
| `sales[].c` | integer | Sats of the row sold. |
| `sales[].p` | integer \| null | Price in sats. |
| `sales[].n` | integer | Tracked sats the sale sold. |
| `sales[].s` | integer \| null | The first special sat sold. |
| `sales[].sh` | integer \| null | The block that mined it. |
| `sales[].sd` | integer \| null | The day it was mined (UTC days since 1970). |
| `sales[].m` | string | Marketplace id (`magisat`, `magic_eden`, `unknown`, …). |
| `sales[].x` | string \| null | The txid's first 8 and last 4 hex digits. |
| `sales[].ins` | boolean | An inscription was on a sold sat. |
| `sales[].out` | boolean | Always false: a pending sale is judged by no median. |
| `sales[].secondary` | map of integer | A 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). |
| `sales[].seller` | string \| null | The seller's address. |
| `sales[].buyer` | string \| null | The buyer's address. |
| `sales[].key` | string | `txid:vin`: its identity. The confirmed sale has the same txid and vin and replaces it. |
| `sales[].pending` | `true` | Always true: the sale is still in the mempool. |
| `sales[].first_seen` | integer \| null | When the transaction was first seen in the mempool (bitcoind's entry time), unix seconds. |
| `sales[].fee_rate` | number \| null | Its fee rate, sat/vB (one decimal). |
| `sales[].txid` | string | The sale transaction, whole. |
| `sales[].vin` | integer \| null | The seller's input. |
| `sales[].seller_outpoint` | string \| null | The output it sells. |
| `sales[].buyer_outpoint` | string \| null | The output the sold sats go to. |
| `sales[].rows` | array of string | Its own row, then the rows of which it is a rarer sub-category. |
| `sales[].led_rows` | array of string | The rows of its other sats (it is led by `row` there). |
| `sales[].labels` | array of string | The label rows it lies in. |
| `sales[].kind` | string \| null | The fork's sale kind (`listing`, `offer`, …). |
| `transfers` | array of object | Pending notable transfers, newest first. |
| `transfers[].id` | string | `pending:transfer:<txid>` or `pending:extraction:<txid>`. |
| `transfers[].kind` | string | One of: `transfer`, `extraction`. |
| `transfers[].txid` | string |  |
| `transfers[].pending` | `true` |  |
| `transfers[].first_seen` | integer \| null | When the transaction was first seen in the mempool (bitcoind's entry time), unix seconds. |
| `transfers[].fee_rate` | number \| null | Its fee rate, sat/vB (one decimal). |
| `transfers[].height` | null |  |
| `transfers[].time` | integer \| null | `first_seen`. |
| `transfers[].reasons` | array of object | Why it is notable. |
| `extractions` | array of object | Pending notable extractions, newest first. |
| `extractions[].id` | string | `pending:transfer:<txid>` or `pending:extraction:<txid>`. |
| `extractions[].kind` | string | One of: `transfer`, `extraction`. |
| `extractions[].txid` | string |  |
| `extractions[].pending` | `true` |  |
| `extractions[].first_seen` | integer \| null | When the transaction was first seen in the mempool (bitcoind's entry time), unix seconds. |
| `extractions[].fee_rate` | number \| null | Its fee rate, sat/vB (one decimal). |
| `extractions[].height` | null |  |
| `extractions[].time` | integer \| null | `first_seen`. |
| `extractions[].reasons` | array of object | Why it is notable. |
| `listings` | map of `PendingSpend` | Live marketplace listings whose UTXO a pending transaction spends, by outpoint: they show as pending. |
| `removed` | array of object | Transactions that left the mempool lately (the live event: those since the last one). |
| `removed[].txid` | string |  |
| `removed[].status` | string | `confirmed`: in a block (its confirmed items replace the pending ones); `replaced` (RBF, `replaced_by` set), `conflicted` (a block spent an input otherwise) or `evicted`: its pending items are dropped. |
| `removed[].height` | integer \| null | The block, when confirmed. |
| `removed[].replaced_by` | string \| null | The replacement, when replaced. |
| `removed[].at` | integer \| null | When it left, unix seconds. |

#### Errors

None of its own.

The index watches the mempool (its overlay, polled every 5 s and right after each block): a transaction still waiting there that moves tracked sats is shown wherever confirmed activity is, marked `pending: true` with `first_seen` (unix seconds) and `fee_rate` (sat/vB). The site shows it with a **Pending** chip.

- **Identity.** A pending sale is `txid:vin` (its `key`), a pending transfer or extraction its `txid` (`id: pending:<kind>:<txid>`). When the transaction confirms, the confirmed record with the same key replaces the pending one at once; nothing is listed twice.
- **Leaving.** `removed` names the transactions that left the mempool: `confirmed` (now in a block), `replaced` (RBF; `replaced_by`), `conflicted` (a block spent an input otherwise) or `evicted`. Their pending items are gone from the lists.
- **Never counted.** Pending sales are in no stat, median, volume, floor, leaderboard or supply until they confirm.
- **Where else.** `pending` in [Sales](https://raresats.net/docs/get-sales.md) and the [market overview](https://raresats.net/docs/get-market.md); the first page of `/api/transfers` and `/api/extractions`; the first page of [Address activity](https://raresats.net/docs/get-address-activity.md); `spent_by_pending` and `pending_outputs` on [Address](https://raresats.net/docs/get-address.md); `pending` on [Sat](https://raresats.net/docs/get-sat.md); `spent_in` and `pending` on [UTXO](https://raresats.net/docs/get-utxo.md); `spent_by_pending` on the listing of a sat or UTXO page.
- **Live.** The SSE stream sends `mempool` whenever what is pending changes: an invalidation, `{version, keys: {sales, transfers, extractions, rows, addresses, outpoints}, counts}`, naming what changed (the rows, addresses and outpoints of the transactions added, removed or changed), never the items. Read this route, or the answer you show, again when a key you care about is set.
- Against an index without the mempool overlay, `available` is false and every list is empty.

## Everything at once

`GET /api/state`

Everything the site shows at once: `thresholds`, `limits`, `fork`, `feed`, `rows`, `groups`, `supply`, `sales`, and the newest `transfers` and `extractions`. `pending` is everything pending in the mempool (`/api/pending`).

#### Query parameters

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `limit` | integer | no | Events per list, 1-1000. Default: `500`. (min 1, max 1000) |

#### Example request

```bash title="cURL"
curl 'https://raresats.net/api/state'
```
```js title="JavaScript"
const response = await fetch('https://raresats.net/api/state');
const data = await response.json();
```
```python title="Python"
import requests

data = requests.get("https://raresats.net/api/state").json()
```

#### Response `200`

A JSON object.

#### Errors

`{error}` (a message, no code):

| Status | When |
| --- | --- |
| 400 | A malformed limit. |

## Live events

Every change the site shows (blocks, sales, listings, offers, floors, activity, prices, chat) comes down one Server-Sent Events stream: see [Live events](https://raresats.net/docs/live-events.md).

## Status

`GET /api/status`

The rare-sat index's reachability, mode and progress (`fork`) and the dashboard's tip (`feed`).

#### Example request

```bash title="cURL"
curl 'https://raresats.net/api/status'
```
```js title="JavaScript"
const response = await fetch('https://raresats.net/api/status');
const data = await response.json();
```
```python title="Python"
import requests

data = requests.get("https://raresats.net/api/status").json()
```

#### Response `200`

A JSON object.

#### Errors

None of its own.

## Health

`GET /healthz`

`{ok, fork, mode, height, tip}`: `fork` is `up`, `stale` or `down`.

#### Example request

```bash title="cURL"
curl 'https://raresats.net/healthz'
```
```js title="JavaScript"
const response = await fetch('https://raresats.net/healthz');
const data = await response.json();
```
```python title="Python"
import requests

data = requests.get("https://raresats.net/healthz").json()
```

#### Response `200`

| Field | Type | Description |
| --- | --- | --- |
| `ok` | boolean | Always true when the dashboard answers. |
| `fork` | string | The index. One of: `up`, `stale`, `down`. |
| `mode` | string \| null | The index's mode. |
| `height` | integer \| null | The index's height. |
| `tip` | integer \| null | The dashboard's tip. |

```json title="Response"
{"ok": true, "fork": "up", "mode": "live", "height": 969001, "tip": 969001}
```

#### Errors

None of its own.
