# Get listings by outpoint

Look up whether UTXOs are listed, one or up to 100 at a time. Both forms return only **live** listings: `active`, or `pending` while a purchase is in the mempool. A sold, cancelled or moved listing is no longer the outpoint's.

## One outpoint

`GET /api/market/listings/by-outpoint/{outpoint}`

The live listing (active, or pending while a purchase is in the mempool) of one outpoint, or 404 `not_listed`.

#### Path parameters

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `outpoint` | string | yes | The UTXO, `txid:vout`. |

#### Example request

```bash title="cURL"
curl 'https://raresats.net/api/market/listings/by-outpoint/8b09d6914ae17431940ce8b6cadae378a5d9b3c90c73c3a5b0b8c8e7edc9e86a:0'
```
```js title="JavaScript"
const response = await fetch('https://raresats.net/api/market/listings/by-outpoint/8b09d6914ae17431940ce8b6cadae378a5d9b3c90c73c3a5b0b8c8e7edc9e86a:0');
const data = await response.json();
```
```python title="Python"
import requests

data = requests.get("https://raresats.net/api/market/listings/by-outpoint/8b09d6914ae17431940ce8b6cadae378a5d9b3c90c73c3a5b0b8c8e7edc9e86a:0").json()
```

#### Response `200`

| Field | Type | Description |
| --- | --- | --- |
| `id` | string | The listing id: 16 lowercase hex characters. |
| `outpoint` | string | The listed UTXO, `txid:vout`. |
| `value` | integer | The UTXO's own value in sats (it moves to the buyer whole). |
| `price` | integer | The listing price in sats: exactly what the seller receives. The buyer pays this plus the platform fee and the network fee. |
| `unit_price` | number | Price per sat of the listing's own row: `(price - value) / count`, to the hundredth of a sat. Floors and the `unit` sort use it. |
| `row` | string | The listing's own row (collection): the rarest market row holding every tracked sat of the UTXO, else the rarest market row present. Never a label row. |
| `count` | integer | How many sats of `row` the UTXO holds (the "×N" of a bulk listing). |
| `rows` | map of integer | Every row the UTXO's tracked sats count toward, with their counts (label rows included). |
| `types` | array of [TypeGroup](https://raresats.net/docs/listing-object.md) \| null | The UTXO's sats grouped by exact type combination, rarest first. |
| `sats` | integer \| null | Tracked sats in the UTXO (all rows). |
| `ranges` | array of array of integer \| null | The tracked sats as inclusive `[first, last]` ranges, ascending. |
| `years` | map of integer \| null | Tracked sats per mint year (UTC year of the block that mined them). |
| `seller_address` | string | The address that holds the UTXO and signed the listing. |
| `payout_address` | string | Where the price is paid (the seller's payment output). |
| `status` | string | `active` (for sale), `pending` (a purchase is in the mempool), `sold`, `cancelled` (or replaced by a newer listing of the same UTXO), `moved` (spent elsewhere). A listing whose UTXO was sold through an accepted offer ends `sold` with `sold_via: "offer"`. |
| `created_at` | integer | Unix seconds. |
| `updated_at` | integer | Unix seconds of the last status change. |
| `txid` | string \| null | The purchase transaction, while `pending` and once `sold`; otherwise `null`. |
| `signature_public` | boolean | `true` once a broadcast purchase put the seller's signature on the network: the listing can then be bought at this price anywhere until the UTXO moves, even after a cancel here. |
| `sold_via` | string \| null | `offer` when the listing ended `sold` through an accepted offer of its UTXO: `price` and `unit_price` are then the offer's (what was paid), `offer_id` names it. `null` otherwise. |
| `offer_id` | string \| null | The accepted offer it was sold through (`sold_via: "offer"`), else `null`. |
| `best_offer` | [BestOffer](https://raresats.net/docs/offer-object.md) \| null | The best active offer on the UTXO, or `null`. |
| `spent_by_pending` | object | A transaction still in the mempool that spends an output (`spent_by_pending`). Absent when nothing pending spends it. |
| `spent_by_pending.txid` | string | The spending transaction. |
| `spent_by_pending.vin` | integer \| null | Its input that spends the output. |
| `spent_by_pending.first_seen` | integer \| null | When the transaction was first seen in the mempool (bitcoind's entry time), unix seconds. |
| `spent_by_pending.fee_rate` | number \| null | Its fee rate, sat/vB (one decimal). |
| `spent_by_pending.sale` | boolean | Whether the spend sells this output (a pending sale with it as the seller's input). |
| `spent_by_pending.replaceable` | boolean | Always true (full RBF): the spend may still be replaced. |
| `in_bundle` | boolean | Only on a listing read for a row it holds some sats of among others (in bundle: `contains=1`'s `contains`, or a row's activity): `true`. Its `price` is the whole UTXO's and its `unit_price` its own row's, never the row asked for. |
| `contains_count` | integer \| null | With `in_bundle`: how many sats of the row asked for it holds. |

```json title="Response"
{
  "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](https://raresats.net/docs/errors.md) for every code.

| Status | Code | Meaning |
| --- | --- | --- |
| 400 | `bad_outpoint` | Not an outpoint (`txid:vout`). |
| 400 | `bad_path` | The path is not valid percent-encoding. |
| 404 | `not_listed` | That outpoint has no live listing. |

```json title="Error (400)"
{"error": "not an outpoint (txid:vout)", "code": "bad_outpoint"}
```

## Many outpoints

`GET /api/market/listings/by-outpoint`

The batch form: the live listings of up to 100 outpoints at once, keyed by outpoint. Outpoints that are not listed are simply absent.

#### Query parameters

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `outpoints` | string | yes | 1-100 outpoints (`txid:vout`), comma-separated. |

#### Example request

```bash title="cURL"
curl 'https://raresats.net/api/market/listings/by-outpoint?outpoints=8b09d6914ae17431940ce8b6cadae378a5d9b3c90c73c3a5b0b8c8e7edc9e86a:0,2fb6fb60ece3672924a373d7479d144d9ce4d3591185bfb5a00e62aedd53d3a9:0'
```
```js title="JavaScript"
const response = await fetch('https://raresats.net/api/market/listings/by-outpoint?outpoints=8b09d6914ae17431940ce8b6cadae378a5d9b3c90c73c3a5b0b8c8e7edc9e86a:0,2fb6fb60ece3672924a373d7479d144d9ce4d3591185bfb5a00e62aedd53d3a9:0');
const data = await response.json();
```
```python title="Python"
import requests

data = requests.get("https://raresats.net/api/market/listings/by-outpoint", params={"outpoints": "8b09d6914ae17431940ce8b6cadae378a5d9b3c90c73c3a5b0b8c8e7edc9e86a:0,2fb6fb60ece3672924a373d7479d144d9ce4d3591185bfb5a00e62aedd53d3a9:0"}).json()
```

#### Response `200`

| Field | Type | Description |
| --- | --- | --- |
| `listings` | map of [Listing](https://raresats.net/docs/listing-object.md) | The live (active or pending) listing of each outpoint asked for, keyed by outpoint. Outpoints with none are absent. |
| `as_of` | object \| null | When the marketplace last checked every live listing against the chain: the block height and unix seconds. `null` until the first check. |
| `as_of.height` | integer \| null | Block height |
| `as_of.checked_at` | integer | Unix seconds |

```json title="Response"
{
  "listings": {
    "8b09d6914ae17431940ce8b6cadae378a5d9b3c90c73c3a5b0b8c8e7edc9e86a:0": {
      "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
    }
  },
  "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_outpoint` | Not an outpoint (`txid:vout`). |
| 400 | `bad_outpoints` | `outpoints` lists none, or more than 100. |

```json title="Error (400)"
{"error": "outpoints must list 1-100 outpoints", "code": "bad_outpoints"}
```

An outpoint with no live listing is simply absent from `listings`; one malformed outpoint fails the whole request (400 `bad_outpoint`).
