# List active listings

`GET /api/market/listings`

Active listings, one page at a time, filtered by row and seller and sorted by unit price, price or age. Read-only, no rate limit beyond the edge's.

#### Query parameters

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `row` | string | no | Only listings of this row (collection), e.g. `uncommon`, `block9`, `black_rare`. A label row (e.g. `block9_1st_tx`) lists every listing lying in it. |
| `sub` | string | no | With `row`: `1` also lists the row's rarer sub-categories (listings whose sats the row holds whole, e.g. alpha uncommons under `uncommon`). One of: `0`, `1`. Default: `0`. |
| `contains` | string | no | With `row`: `1` also answers, apart, the listings holding only some sats of the row among others (in bundle: a Block 9 chunk holding one Block 9 palindrome under `block9_palindrome`) as `contains` (the first `limit`, in the asked `sort` and `order`; `sort=unit` orders them by total price, a bundle having no unit price of this row) and `contains_total`; `only` answers those alone as `listings`/`total`, paged by `limit` and `offset`. They are priced as the whole UTXO, never in the row's floor. One of: `0`, `1`, `only`. Default: `0`. |
| `sort` | string | no | `unit` (unit price), `price` (listing price) or `new` (creation time). One of: `unit`, `price`, `new`. Default: `unit`. |
| `order` | string | no | `asc` or `desc`. Default: `asc`, except `desc` for `sort=new`. Ties: newest first, then by id. One of: `asc`, `desc`. |
| `limit` | integer | no | Page size, 1-200. Default: `50`. (min 1, max 200) |
| `offset` | integer | no | Listings to skip, 0-1,000,000. Default: `0`. (min 0, max 1000000) |
| `seller` | string | no | Only listings by this seller address. |

#### Example request

```bash title="cURL"
curl 'https://raresats.net/api/market/listings?row=black_rare&sort=unit&order=asc&limit=2'
```
```js title="JavaScript"
const response = await fetch('https://raresats.net/api/market/listings?row=black_rare&sort=unit&order=asc&limit=2');
const data = await response.json();
```
```python title="Python"
import requests

data = requests.get("https://raresats.net/api/market/listings", params={"row": "black_rare", "sort": "unit", "order": "asc", "limit": 2}).json()
```

#### Response `200`

| Field | Type | Description |
| --- | --- | --- |
| `listings` | array of [Listing](https://raresats.net/docs/listing-object.md) | One page of active listings, in the requested order. |
| `total` | integer | Active listings matching the filters (all pages). |
| `as_of` | object \| null | When every live listing was last checked against the chain (`{height, checked_at}`), or `null`. |
| `as_of.height` | integer \| null | Block height |
| `as_of.checked_at` | integer | Unix seconds |
| `contains` | array of [Listing](https://raresats.net/docs/listing-object.md) | Only with `row` and `contains=1`: the first `limit` active listings holding some sats of the row among others (in bundle, each `in_bundle: true`), by total price, the cheapest first. Never in `listings`, `total` or the row's floor. |
| `contains_total` | integer | Only with `contains=1`: how many such listings there are (all pages; `contains=only` pages them). |

```json title="Response"
{
  "listings": [
    {
      "id": "1031931af1592e1c",
      "outpoint": "2fb6fb60ece3672924a373d7479d144d9ce4d3591185bfb5a00e62aedd53d3a9:0",
      "value": 546,
      "price": 60546,
      "unit_price": 60000,
      "row": "black_rare",
      "count": 1,
      "rows": {"black_rare": 1},
      "types": [
        {
          "types": ["black_rare", "omega"],
          "count": 1,
          "sats": [1657319999999999]
        }
      ],
      "sats": 1,
      "ranges": [[1657319999999999, 1657319999999999]],
      "years": {"2017": 1},
      "seller_address": "bc1qcr8te4kr609gcawutmrza0j4xv80jy8z306fyu",
      "payout_address": "bc1qcr8te4kr609gcawutmrza0j4xv80jy8z306fyu",
      "status": "active",
      "created_at": 1790952985,
      "updated_at": 1790952985,
      "txid": null,
      "signature_public": false,
      "sold_via": null,
      "offer_id": null,
      "best_offer": null
    }
  ],
  "total": 1,
  "as_of": {"height": 969001, "checked_at": 1790952985}
}
```

#### Errors

`{error, code}`; see [Errors](https://raresats.net/docs/errors.md) for every code.

| Status | Code | Meaning |
| --- | --- | --- |
| 400 | `bad_address` | An address is not a mainnet address (or not one at all). |
| 400 | `bad_contains` | `contains` is not 0, 1 or `only`, or is set without `row`. |
| 400 | `bad_order` | `order` is not `asc` or `desc`. |
| 400 | `bad_paging` | `limit` or `offset` out of range. |
| 400 | `bad_row` | `row` is not a row id. |
| 400 | `bad_sort` | `sort` is not `unit`, `price` or `new`. |
| 400 | `bad_sub` | `sub` is not 0 or 1. |
| 404 | `retired_row` | `row` is a row the site retired (`uncommon_2009`, `rare_2009`): its listings are its parent row's. `retired` names the row and the parent and years to ask for. |

```json title="Error (400)"
{"error": "sort must be unit, price or new", "code": "bad_sort"}
```

## Sorting and paging

- `sort=unit` (the default) orders by `unit_price`, the price per sat of the listing's own row: the way to find a collection's cheapest sats. `sort=price` orders by the listing price, `sort=new` by creation time.
- `order` defaults to `asc`, except `desc` for `sort=new` (newest first). Equal values come newest first, then by id, so pages are stable.
- Page with `limit` (1-200) and `offset`; `total` counts every match. Listings can sell or move between two pages; re-read the first page when it matters.

## Filters

- `row` filters by a listing's own row. With `sub=1` it also lists the row's rarer sub-categories (listings whose sats the row holds whole). A label row such as `block9_1st_tx` lists every listing lying in it.
- `contains=1` (with `row`) adds, apart, the listings that hold only some sats of the row among others (in bundle: a 330-sat Block 9 chunk holding one Block 9 palindrome, under `block9_palindrome`) as `contains`, the first `limit` by total price, with `contains_total`. Each is marked `in_bundle: true` with `contains_count`, its sats of the row. They are priced as the whole UTXO: their `unit_price` is their own row's, so they are never in `listings`, `total` or the row's floor. `contains=only` answers them alone as `listings` and `total`, paged by `limit` and `offset`.
- `seller` lists one seller's active listings (the site's "My listings").
- Only `active` listings are listed. A `pending`, sold, cancelled or moved listing is still readable by id ([Get a listing](https://raresats.net/docs/get-listing.md)).

To filter listings by mint year, mint day, birthday (month-day) or one rarer sub-category, use [Query listings](https://raresats.net/docs/get-listings-query.md); see [Filtering & birthday sats](https://raresats.net/docs/guide-filters.md).
