# Prepare a listing

`POST /api/market/listings/prepare`

Step 1 of listing: checks each UTXO (confirmed, unspent, yours, tracked rare sats, no inscription or rune, a valid price) and returns the PSBT to sign with SIGHASH_SINGLE|ANYONECANPAY. Nothing is stored yet.

#### Request body

`content-type: application/json`

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `seller_address` | string | yes | The address holding the UTXOs: Taproot (`bc1p…`), native SegWit (`bc1q…`) or nested SegWit (`3…`, P2SH-P2WPKH). Legacy `1…` is refused. |
| `seller_public_key` | string | yes | The public key of `seller_address`, hex: for Taproot the internal (untweaked) key, 32-byte x-only or 33-byte compressed; for SegWit the 33-byte compressed key. |
| `payout_address` | string | no | Where the price is paid. Optional: defaults to `seller_address`. Any standard mainnet address. |
| `items` | array of object | yes | 1 to 50 UTXOs, each listed at its own price. One PSBT, one wallet prompt. (1-50 items) |
| `items[].outpoint` | string | yes | The UTXO to list, `txid:vout`. |
| `items[].price` | integer | yes | Its price in sats: what you receive. Above the UTXO's own value, at least 546 and at least the payout output's dust limit. |

#### Example request

```bash title="cURL"
curl -X POST 'https://raresats.net/api/market/listings/prepare' \
  -H 'content-type: application/json' \
  -d '{
  "seller_address": "bc1p4qhjn9zdvkux4e44uhx8tc55attvtyu358kutcqkudyccelu0was9fqzwh",
  "seller_public_key": "0283dfe85a3151d2517290da461fe2815591ef69f2b18a2ce63f01697a8b313145",
  "payout_address": "bc1p4qhjn9zdvkux4e44uhx8tc55attvtyu358kutcqkudyccelu0was9fqzwh",
  "items": [
    {
      "outpoint": "8b09d6914ae17431940ce8b6cadae378a5d9b3c90c73c3a5b0b8c8e7edc9e86a:0",
      "price": 94200
    }
  ]
}'
```
```js title="JavaScript"
const response = await fetch('https://raresats.net/api/market/listings/prepare', {
  method: 'POST',
  headers: { 'content-type': 'application/json' },
  body: JSON.stringify({
    "seller_address": "bc1p4qhjn9zdvkux4e44uhx8tc55attvtyu358kutcqkudyccelu0was9fqzwh",
    "seller_public_key": "0283dfe85a3151d2517290da461fe2815591ef69f2b18a2ce63f01697a8b313145",
    "payout_address": "bc1p4qhjn9zdvkux4e44uhx8tc55attvtyu358kutcqkudyccelu0was9fqzwh",
    "items": [
      {
        "outpoint": "8b09d6914ae17431940ce8b6cadae378a5d9b3c90c73c3a5b0b8c8e7edc9e86a:0",
        "price": 94200
      }
    ]
  })
});
const data = await response.json();
```
```python title="Python"
import requests

data = requests.post("https://raresats.net/api/market/listings/prepare", json={
    "seller_address": "bc1p4qhjn9zdvkux4e44uhx8tc55attvtyu358kutcqkudyccelu0was9fqzwh",
    "seller_public_key": "0283dfe85a3151d2517290da461fe2815591ef69f2b18a2ce63f01697a8b313145",
    "payout_address": "bc1p4qhjn9zdvkux4e44uhx8tc55attvtyu358kutcqkudyccelu0was9fqzwh",
    "items": [{
        "outpoint": "8b09d6914ae17431940ce8b6cadae378a5d9b3c90c73c3a5b0b8c8e7edc9e86a:0",
        "price": 94200
    }]
}).json()
```

#### Response `200`

| Field | Type | Description |
| --- | --- | --- |
| `psbt` | string | The unsigned listing PSBT, base64: input i is UTXO i (with `witnessUtxo`, `sighashType` 0x83, `tapInternalKey` or `redeemScript`), output i pays its price to the payout address; version 2, locktime 0, sequence 0xfffffffd. |
| `sign` | array of object | The inputs to sign: every input, with `sighash: 131`. |
| `sign[].index` | integer | The input to sign. |
| `sign[].address` | string | The address whose key signs it. |
| `sign[].sighash` | integer | The sighash type to sign with, when it is not the default: 131 (`0x83`, SIGHASH_SINGLE\|ANYONECANPAY) for listings. Absent on purchase inputs: sign with the default (SIGHASH_DEFAULT for Taproot, SIGHASH_ALL for SegWit v0). |
| `items` | array of object | What each listed UTXO will show. |
| `items[].outpoint` | string | The UTXO. |
| `items[].value` | integer | Its value in sats. |
| `items[].price` | integer | Its listing price in sats. |
| `items[].unit_price` | number | `(price - value) / count`. |
| `items[].row` | string | Its own row. |
| `items[].count` | integer | Sats of that row it holds. |

```json title="Response"
{
  "psbt": "cHNidP8BAF4CAAAAAWroye3nyLiwpcNzDMmz2aV449rKtugMlDF04UqR1gmLAAAAAAD9////AfhvAQAAAAAAIlEgqC8plE1luGrmteXMdeKU6tbFk5Gh7cXgFuNJjGf8e7sAAAAAAAEBK4gYAAAAAAAAIlEgqC8plE1luGrmteXMdeKU6tbFk5Gh7cXgFuNJjGf8e7sBAwSDAAAAARcgg9/oWjFR0lFykNpGH+KBVZHvafKxiizmPwFpeosxMUUAAA==",
  "sign": [
    {
      "index": 0,
      "address": "bc1p4qhjn9zdvkux4e44uhx8tc55attvtyu358kutcqkudyccelu0was9fqzwh",
      "sighash": 131
    }
  ],
  "items": [
    {
      "outpoint": "8b09d6914ae17431940ce8b6cadae378a5d9b3c90c73c3a5b0b8c8e7edc9e86a:0",
      "value": 6280,
      "price": 94200,
      "unit_price": 14,
      "row": "block9",
      "count": 6280
    }
  ]
}
```

#### 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_items` | `items` is not a list of 1-50 UTXOs (or the PSBT lists more), or an item's `sats` is not null or a list of sat numbers. |
| 400 | `bad_json` | The body is not valid JSON. |
| 400 | `bad_outpoint` | Not an outpoint (`txid:vout`). |
| 400 | `bad_price` | A price is not a whole number of sats. |
| 400 | `bad_public_key` | A public key is not hex, or not a valid secp256k1 key of the right size. |
| 400 | `bad_request` | The body is not a JSON object, or the engine refused a malformed request (e.g. a purchase submitted without its signed setup PSBT). |
| 400 | `duplicate_outpoint` | The same UTXO twice in one listing. |
| 403 | `cross_origin` | A POST from a browser on another site (a foreign `Origin`, or `sec-fetch-site: cross-site`). Server-side clients send no `Origin` and are not affected. |
| 405 | `method_not_allowed` | Wrong method for the route; the `allow` header lists the right ones. |
| 409 | `pending` | The UTXO's listing is being bought, or an offer of it accepted, right now. |
| 409 | `spent` | The UTXO (or a listing's UTXO) is spent or does not exist. |
| 409 | `unconfirmed` | The UTXO is not confirmed yet. |
| 409 | `unindexed` | The ord indexer does not know the UTXO yet. |
| 413 | `too_large` | The body is over 256 KiB. |
| 415 | `not_json` | A POST without `content-type: application/json`. |
| 422 | `bad_payout` | A listed input is paired with an output that pays no address, or the payout address is the marketplace's fee address. |
| 422 | `inscribed` | The UTXO carries an inscription: only rare sats are listed; the wallet tools only send it whole. |
| 422 | `key_mismatch` | The public key does not control the address. |
| 422 | `legacy_address` | A legacy (P2PKH, `1…`) address: use Taproot or SegWit. |
| 422 | `no_row` | The UTXO holds no sat of a market row. |
| 422 | `not_owner` | The UTXO does not belong to the seller address, or (wallet tools) to the owner's addresses, or the transfer was made by another wallet. |
| 422 | `price_too_high` | The price is above 21,000,000 BTC. |
| 422 | `price_too_low` | The price is at most the UTXO's own value, below 546 sats, or below the payout output's dust limit. |
| 422 | `pubkey_mismatch` | The trade engine found the public key is not the address's key. |
| 422 | `runes` | The UTXO carries runes (the wallet tools only send it whole). |
| 422 | `too_many_items` | Too many UTXOs in a listing, or listings in a purchase (`max_bulk`); for a wallet transfer, too many rare sats (and the runs between them) to lay out in one UTXO: choose fewer. |
| 422 | `unsupported_address` | An address type the marketplace does not trade (only Taproot, native SegWit and nested SegWit). |
| 422 | `unsupported_script` | The trade engine met a script type it does not support. |
| 422 | `untracked` | The UTXO holds no rare sat the index tracks (send it whole instead). |
| 429 | `rate_limited` | Over 30 POSTs a minute from your IPv4 address or IPv6 /64 (in chat, counted per IPv4 address or IPv6 /64: 30 writes and 20 login nonces a minute, 20 sign-ins and 10 display-name changes an hour; one message every 3 s and 20 a minute per address); wait `retry-after` seconds. With the AI moderation on, at most 6 messages and names a minute are checked per address and per IPv4 address or IPv6 /48. |
| 503 | `bitcoind_unavailable` | bitcoind is not available. |
| 503 | `engine_unavailable` | The trade engine is not available. |
| 503 | `fork_behind` | The rare-sat index has not caught up with bitcoind: try again in a minute. |
| 503 | `fork_unavailable` | The rare-sat index is not available. |
| 503 | `indexer_behind` | The ord indexer is catching up: try again shortly. |
| 503 | `market_unavailable` | The marketplace is closed right now (its backends disagree on the network, or are unreachable). |
| 503 | `oracle_unavailable` | The ord oracle is not available. |

```json title="Error (422)"
{
  "error": "8b09d6914ae17431940ce8b6cadae378a5d9b3c90c73c3a5b0b8c8e7edc9e86a:0 carries an inscription: only rare sats are listed here",
  "code": "inscribed",
  "outpoint": "8b09d6914ae17431940ce8b6cadae378a5d9b3c90c73c3a5b0b8c8e7edc9e86a:0"
}
```

Sign every input listed in `sign` with sighash `0x83` (SIGHASH_SINGLE|ANYONECANPAY), then [submit the listing](https://raresats.net/docs/submit-listing.md). The whole flow, with code: [List a UTXO](https://raresats.net/docs/guide-list.md).

- Nothing is stored at this step; preparing twice is harmless.
- For SegWit v0 sellers, small previous transactions are included as `nonWitnessUtxo` (some hardware wallets want them).
