Accept an offer
POST/api/market/offers/{id}/accept
Step 2 of accepting: the PSBT from accept/prepare with input 0 signed. The server rechecks everything (the UTXO unspent at the same address and value, the bidder's funding unspent and plain cardinal), verifies your signature (SIGHASH_DEFAULT or ALL), adds the bidder's, finalizes, rechecks every rule, then testmempoolaccept and broadcasts. The offer becomes pending (and your listing of the UTXO, if any), accepted once confirmed; other offers on the UTXO become invalid. Resubmitting is idempotent: use it to settle broadcast_unknown.
Path parameters #
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | yes | The offer id (16 hex characters). |
Request body #
content-type: application/json
| Field | Type | Required | Description |
|---|---|---|---|
psbt | string | yes | The PSBT from accept/prepare with input 0 signed (not finalized), base64. |
Example request #
curl -X POST 'https://raresats.net/api/market/offers/dbf866a1e7e209e7/accept' \
-H 'content-type: application/json' \
-d '{
"psbt": "cHNidP8BAP0fAQIAAAACfxBUfmD8FgvLWC+rhhI7HaW1ncmmlqpbSg8h3N/usyQAAAAAAP3///9Bihr4H2G1iZuygx3BHzwLSWfyqpoJAv/W0tpPJYLJAQAAAAAA/f///wUQJwAAAAAAACJRIKgvKZRNZbhq5rXlzHXilOrWxZORoe3F4BbjSYxn/Hu7sK0BAAAAAAAiUSCmCGnw288dxlnJzsuvgFATXqnozcSHBT8dxogJSdxoTL4KAAAAAAAAIlEgrfKcXTOb9Ymo27aSDRsOplytPApoV4riNE46JGW7F/AvJxUAAAAAACJRIKgvKZRNZbhq5rXlzHXilOrWxZORoe3F4BbjSYxn/Hu7AAAAAAAAAAAOagxyYXJlc2F0cy5uZXQAAAAAAAEBKxAnAAAAAAAAIlEgpghp8NvPHcZZyc7Lr4BQE16p6M3EhwU/HcaICUncaEwBE0AH22HiJwQjhGYmUScuZwJAaaRczyxViuzB4L48meWqATwLvJ3xPAgrv7MqmcxjqeR+Oe+frCEqFAKj0AZy4BF1ARcgzIpLxk2Je93F+8L2cPeougs4Z3kQbPEiPG/F181vwRUAAQErYOMWAAAAAAAiUSCoLymUTWW4aua15cx14pTq1sWTkaHtxeAW40mMZ/x7uwAAAAAAAA=="
}'const response = await fetch('https://raresats.net/api/market/offers/dbf866a1e7e209e7/accept', {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({
"psbt": "cHNidP8BAP0fAQIAAAACfxBUfmD8FgvLWC+rhhI7HaW1ncmmlqpbSg8h3N/usyQAAAAAAP3///9Bihr4H2G1iZuygx3BHzwLSWfyqpoJAv/W0tpPJYLJAQAAAAAA/f///wUQJwAAAAAAACJRIKgvKZRNZbhq5rXlzHXilOrWxZORoe3F4BbjSYxn/Hu7sK0BAAAAAAAiUSCmCGnw288dxlnJzsuvgFATXqnozcSHBT8dxogJSdxoTL4KAAAAAAAAIlEgrfKcXTOb9Ymo27aSDRsOplytPApoV4riNE46JGW7F/AvJxUAAAAAACJRIKgvKZRNZbhq5rXlzHXilOrWxZORoe3F4BbjSYxn/Hu7AAAAAAAAAAAOagxyYXJlc2F0cy5uZXQAAAAAAAEBKxAnAAAAAAAAIlEgpghp8NvPHcZZyc7Lr4BQE16p6M3EhwU/HcaICUncaEwBE0AH22HiJwQjhGYmUScuZwJAaaRczyxViuzB4L48meWqATwLvJ3xPAgrv7MqmcxjqeR+Oe+frCEqFAKj0AZy4BF1ARcgzIpLxk2Je93F+8L2cPeougs4Z3kQbPEiPG/F181vwRUAAQErYOMWAAAAAAAiUSCoLymUTWW4aua15cx14pTq1sWTkaHtxeAW40mMZ/x7uwAAAAAAAA=="
})
});
const data = await response.json();import requests
data = requests.post("https://raresats.net/api/market/offers/dbf866a1e7e209e7/accept", json={
"psbt": "cHNidP8BAP0fAQIAAAACfxBUfmD8FgvLWC+rhhI7HaW1ncmmlqpbSg8h3N/usyQAAAAAAP3///9Bihr4H2G1iZuygx3BHzwLSWfyqpoJAv/W0tpPJYLJAQAAAAAA/f///wUQJwAAAAAAACJRIKgvKZRNZbhq5rXlzHXilOrWxZORoe3F4BbjSYxn/Hu7sK0BAAAAAAAiUSCmCGnw288dxlnJzsuvgFATXqnozcSHBT8dxogJSdxoTL4KAAAAAAAAIlEgrfKcXTOb9Ymo27aSDRsOplytPApoV4riNE46JGW7F/AvJxUAAAAAACJRIKgvKZRNZbhq5rXlzHXilOrWxZORoe3F4BbjSYxn/Hu7AAAAAAAAAAAOagxyYXJlc2F0cy5uZXQAAAAAAAEBKxAnAAAAAAAAIlEgpghp8NvPHcZZyc7Lr4BQE16p6M3EhwU/HcaICUncaEwBE0AH22HiJwQjhGYmUScuZwJAaaRczyxViuzB4L48meWqATwLvJ3xPAgrv7MqmcxjqeR+Oe+frCEqFAKj0AZy4BF1ARcgzIpLxk2Je93F+8L2cPeougs4Z3kQbPEiPG/F181vwRUAAQErYOMWAAAAAAAiUSCoLymUTWW4aua15cx14pTq1sWTkaHtxeAW40mMZ/x7uwAAAAAAAA=="
}).json()Response 200 #
| Field | Type | Description |
|---|---|---|
txid | string | The broadcast transaction. |
{
"txid": "332f8cf83155e2532101454afe84ed45aedf9b2f98f8593b82ff38687cfee3be"
}Errors #
{error, code}; see Errors for every code.
| Status | Code | Meaning |
|---|---|---|
| 400 | bad_json | The body is not valid JSON. |
| 400 | bad_psbt | Not a base64 PSBT, or one that does not parse. |
| 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, 422 | bad_signature | 400: signature is missing or too long. 422: a signature does not verify (cancel or registration message, listing or purchase input). |
| 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. |
| 404 | not_found | No such listing or offer. In chat: no such message. A display name to remove that does not exist. |
| 405 | method_not_allowed | Wrong method for the route; the allow header lists the right ones. |
| 409 | changed | The UTXO's value is not what the PSBT says, or (wallet tools) a UTXO, its sats or the transaction being replaced changed since prepare: prepare again. |
| 409 | config_changed | The marketplace settings changed since this purchase or transfer was prepared (prepare it again), or since this offer was made (it is now invalid, reason config_changed). |
| 409 | conflict | A listing or one of your UTXOs was spent meanwhile (lost race), or bitcoind would not replace a transaction already spending it (insufficient fee), or a transfer's inputs are spent by another transaction. |
| 409 | expired | The prepared purchase, offer or transfer expired, or the offer itself has: prepare it again. |
| 409 | funding_spent | A UTXO of the bidder's that funds the offer was spent (or is no longer plain cardinal): the offer is no longer valid. |
| 409 | not_active | A listing (or offer) is not active: being bought (or accepted), sold, cancelled, moved, expired or invalid. Carries id and status. |
| 409 | offer_changed | The offer's stored signatures no longer verify: it cannot be accepted. |
| 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. |
| 413 | too_large | The body is over 256 KiB. |
| 415 | not_json | A POST without content-type: application/json. |
| 422 | bad_sighash | A signature uses the wrong sighash type (listings: 0x83; purchases: DEFAULT or ALL). |
| 422 | missing_signature | An input that must be signed is not. |
| 422 | psbt_mismatch | The signed PSBT is not the prepared transaction. |
| 422 | rejected | bitcoind refused the transaction (reason). |
| 422 | unsupported_script | The trade engine met a script type it does not support. |
| 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. |
| 500 | internal | A server bug. Report it. |
| 500 | invariant_violated | A planned or finalized purchase or transfer broke an invariant (violations); nothing was broadcast. |
| 503 | bitcoind_unavailable | bitcoind is not available. |
| 503 | broadcast_unknown | The broadcast's outcome is unknown: submit the same purchase or transfer again to settle it. Carries txid. |
| 503 | engine_unavailable | The trade engine is not available. |
| 503 | fork_unavailable | The rare-sat index is not available. |
| 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. |
{
"error": "the bidder's UTXO 24b3eedfdc210f4a5baa96a6c99db5a51d3b1286ab2f58cb0b16fc607e54107f:0 is no longer usable (spent (in the mempool or a block)): the offer is no longer valid",
"code": "funding_spent",
"outpoint": "24b3eedfdc210f4a5baa96a6c99db5a51d3b1286ab2f58cb0b16fc607e54107f:0"
}When the answer is lost #
An accept that times out, or answers 503 broadcast_unknown, may still have gone through. Submit the same body again: it is idempotent. If bitcoind has the transaction, the answer is the same {txid}; if it was refused, you get that error; while it cannot be known yet, broadcast_unknown again. Meanwhile the offer (and your listing of the UTXO) stays reserved: pending.