status
What this gateway is, and whether it can verify a listing right now.
GET /api/ordex/health
The observed verification verdict, not the configuration. Reports configuration completeness and, separately, whether a Bitcoin listing can actually be verified right now: storage writable, both nodes answering, and the ord index within its accepted lag of Bitcoin Core.
| Status | Answers | Notes |
|---|
200 | HealthReport | The health report. |
default | ErrorResponse | The request failed. The envelope states the status, a human readable message, and the request id. |
GET /api/ordex/protocol
The protocol contract this gateway speaks.
| Status | Answers | Notes |
|---|
200 | ProtocolContract | The protocol contract. |
default | ErrorResponse | The request failed. The envelope states the status, a human readable message, and the request id. |
GET /api/ordex/catalog
The markets this gateway serves, and what it verifies for each. Every entry states its verification scope in plain language and its capabilities as booleans. An entry in the catalog never implies a working flow beyond what its capabilities state.
| Status | Answers | Notes |
|---|
200 | array of ProtocolTemplate | The protocol catalog. |
default | ErrorResponse | The request failed. The envelope states the status, a human readable message, and the request id. |
orders
The orderbook, one order, and its signed artifact.
GET /api/ordex/orders
One page of the orderbook. Paging is keyset, never offset. A request carrying an `offset` parameter is refused with 400, and a malformed cursor is a 400 rather than a silent restart from the first page.
| Parameter | In | Type | Notes |
|---|
protocol optional | query | string | One catalog protocol id. |
protocols optional | query | string | Comma separated catalog ids. Applied before sorting and pagination. |
group optional | query | string | A catalog group id, expanded to every protocol it contains. |
token optional | query | string | |
source optional | query | Source | |
state optional | query | string | An order state from `OrderState`. |
safety optional | query | string | A safety class from `PsbtInspection.safety`. |
orderClass optional | query | string | |
signature optional | query | string | A signature status from `SignatureStatus`. |
side optional | query | string | |
seller optional | query | string | Restricts the page to the listings one seller script owns. |
assetInscriptionId optional | query | string | Restricts the page to orders claiming one inscription. Resolved through an index of order claims. |
assetOutpoint optional | query | string | Restricts the page to orders claiming an asset at one `txid:vout`. |
search optional | query | string | |
sort optional | query | newest | oldest | price_asc | price_desc | token_asc | protocol_asc | validation_newest | Every sort ends on the order id, which is unique, so the ordering is total and a cursor resumes exactly. An unpriced order sorts after every priced one in both price directions. |
includeWithdrawn optional | query | string | |
limit optional | query | string | Page size as a decimal string. |
cursor optional | query | string | The keyset resume point a previous page answered with. |
| Status | Answers | Notes |
|---|
200 | OrderPage | One page of orders. |
400 | ErrorResponse | The request is malformed or refused, with the exact reason in `message`. |
default | ErrorResponse | The request failed. The envelope states the status, a human readable message, and the request id. |
GET /api/ordex/orders/{id}
One order.
| Parameter | In | Type | Notes |
|---|
id | path | string | The order id. |
| Status | Answers | Notes |
|---|
200 | OrderSummary | The order, without its signed artifact. |
404 | ErrorResponse | No order with this id. |
default | ErrorResponse | The request failed. The envelope states the status, a human readable message, and the request id. |
GET /api/ordex/orders/{id}/artifact
The signed artifact for one live listing. Deliberately its own rate limited request. A browse response carrying raw PSBTs would hand every public ask to anything that can read the market. Only a live listing hands over its artifact; any other state is refused with 400.
| Parameter | In | Type | Notes |
|---|
id | path | string | The order id. |
| Status | Answers | Notes |
|---|
200 | OrderArtifact | The signed artifact and its current verification. |
400 | ErrorResponse | The request is malformed or refused, with the exact reason in `message`. |
404 | ErrorResponse | No order with this id. |
429 | ErrorResponse | Rate limited. The envelope carries `code: ORDEX_RATE_LIMITED`. |
default | ErrorResponse | The request failed. The envelope states the status, a human readable message, and the request id. |
POST /api/ordex/orders/{id}/revalidate
Recheck one order against both authorities.
| Parameter | In | Type | Notes |
|---|
id | path | string | The order id. |
| Status | Answers | Notes |
|---|
201 | OrderSummary | The order after a fresh verification. |
404 | ErrorResponse | No order with this id. |
429 | ErrorResponse | Rate limited. The envelope carries `code: ORDEX_RATE_LIMITED`. |
default | ErrorResponse | The request failed. The envelope states the status, a human readable message, and the request id. |
activity
The appended lifecycle log.
GET /api/ordex/activity
The appended lifecycle log, newest first. Reads the appended transition log, so an entry is something that happened rather than a listing's current state restated after the fact.
| Parameter | In | Type | Notes |
|---|
orderId optional | query | string | |
limit optional | query | string | |
cursor optional | query | string | |
| Status | Answers | Notes |
|---|
200 | ActivityPage | One page of lifecycle transitions. |
default | ErrorResponse | The request failed. The envelope states the status, a human readable message, and the request id. |
selling
Building, publishing, and withdrawing a listing.
POST /api/ordex/orders/build
Build the unsigned seller half. Composes the one input, one output PSBT a seller signs `SIGHASH_SINGLE | SIGHASH_ANYONECANPAY`. The asset and outpoint are verified against the node and the ord index before anything is composed.
Request body: BuildAskRequest
| Status | Answers | Notes |
|---|
201 | BuildAskResult | The unsigned seller half and its inspection. |
400 | ErrorResponse | The request is malformed or refused, with the exact reason in `message`. |
429 | ErrorResponse | Rate limited. The envelope carries `code: ORDEX_RATE_LIMITED`. |
default | ErrorResponse | The request failed. The envelope states the status, a human readable message, and the request id. |
POST /api/ordex/orders/publish
Take the signed seller half and publish it.
Request body: PublishAskRequest
| Status | Answers | Notes |
|---|
201 | OrderSummary | The published order after verification. |
400 | ErrorResponse | The request is malformed or refused, with the exact reason in `message`. |
429 | ErrorResponse | Rate limited. The envelope carries `code: ORDEX_RATE_LIMITED`. |
default | ErrorResponse | The request failed. The envelope states the status, a human readable message, and the request id. |
GET /api/ordex/orders/{id}/ownership-challenge
The message a listing owner signs before managing it.
| Parameter | In | Type | Notes |
|---|
id | path | string | The order id. |
| Status | Answers | Notes |
|---|
200 | OwnershipChallenge | The challenge to sign with the key that owns the offered output. |
404 | ErrorResponse | No order with this id. |
default | ErrorResponse | The request failed. The envelope states the status, a human readable message, and the request id. |
POST /api/ordex/orders/{id}/withdraw
Remove a listing, proved by the key owning the output it sells. Withdrawal is discovery, not cancellation. It stops this gateway publishing the listing; it cannot unpublish a signed artifact already distributed elsewhere. Only spending the offered output makes such an artifact unusable.
| Parameter | In | Type | Notes |
|---|
id | path | string | The order id. |
Request body: OwnershipProof
| Status | Answers | Notes |
|---|
201 | OrderSummary | The withdrawn order. |
400 | ErrorResponse | The request is malformed or refused, with the exact reason in `message`. |
404 | ErrorResponse | No order with this id. |
429 | ErrorResponse | Rate limited. The envelope carries `code: ORDEX_RATE_LIMITED`. |
default | ErrorResponse | The request failed. The envelope states the status, a human readable message, and the request id. |
buying
Quoting and preflighting a purchase.
POST /api/ordex/orders/{id}/quote
Compose the buyer half and state the exact terms. The caller names its own outputs and nothing else. Value and script are read from Bitcoin Core, never from the request, so a buyer cannot make a purchase look cheaper by describing their own funding wrongly. Each named output is checked against the ord index first: an output holding an asset is not spare change, and an unexamined output is unknown rather than empty.
| Parameter | In | Type | Notes |
|---|
id | path | string | The order id. |
Request body: QuoteRequest
| Status | Answers | Notes |
|---|
201 | Quote | The unsigned buyer half and the exact economics. A fee or a royalty of zero is stated as zero rather than omitted. |
400 | ErrorResponse | The request is malformed or refused, with the exact reason in `message`. |
404 | ErrorResponse | No order with this id. |
429 | ErrorResponse | Rate limited. The envelope carries `code: ORDEX_RATE_LIMITED`. |
default | ErrorResponse | The request failed. The envelope states the status, a human readable message, and the request id. |
POST /api/ordex/orders/{id}/preflight
Verify a signed purchase and ask the node whether it would accept it. Takes either `finalTxHex` or the `signedPsbt` a wallet actually answers with. Given a PSBT it finalises only inputs the buyer already signed: it creates no signature and changes no input, output, or amount, and an unsigned input is an error rather than a guess. It rechecks the order against the chain, binds the transaction to the order, proves the sat flow invariant, then asks the node itself. The gateway does not broadcast; that is the buyer's own deliberate step.
| Parameter | In | Type | Notes |
|---|
id | path | string | The order id. |
Request body: PreflightRequest
| Status | Answers | Notes |
|---|
201 | PreflightResult | The verdict, with the exact bytes checked so a buyer broadcasts those and no others. |
400 | ErrorResponse | The request is malformed or refused, with the exact reason in `message`. |
404 | ErrorResponse | No order with this id. |
429 | ErrorResponse | Rate limited. The envelope carries `code: ORDEX_RATE_LIMITED`. |
default | ErrorResponse | The request failed. The envelope states the status, a human readable message, and the request id. |
interoperability
Importing and exporting portable signed orders.
POST /api/ordex/orders/import
Take a signed artifact and verify it. A source may supply signed order evidence, but it never overrides what the node and the ord index prove. The claims travel as evidence and the authorities decide the state.
Request body: ImportRequest
| Status | Answers | Notes |
|---|
201 | OrderSummary | The imported order after verification. |
400 | ErrorResponse | The request is malformed or refused, with the exact reason in `message`. |
429 | ErrorResponse | Rate limited. The envelope carries `code: ORDEX_RATE_LIMITED`. |
default | ErrorResponse | The request failed. The envelope states the status, a human readable message, and the request id. |
POST /api/ordex/orders/openordex-event
Take a signed OpenOrdex event and verify it. Accepts a kind 802 Nostr event carrying a signed PSBT, verifies the event signature, then verifies the order exactly as a direct import.
Request body: NostrEvent
| Status | Answers | Notes |
|---|
201 | OrderSummary | The imported order after verification. |
400 | ErrorResponse | The request is malformed or refused, with the exact reason in `message`. |
429 | ErrorResponse | Rate limited. The envelope carries `code: ORDEX_RATE_LIMITED`. |
default | ErrorResponse | The request failed. The envelope states the status, a human readable message, and the request id. |
GET /api/ordex/orders/{id}/nostr-envelope
The unsigned kind 802 event announcing this listing. The gateway never holds Nostr keys. The customer's own NIP-07 signer signs this envelope, the browser publishes it, and the signed event can then be handed back through the OpenOrdex import route.
| Parameter | In | Type | Notes |
|---|
id | path | string | The order id. |
| Status | Answers | Notes |
|---|
200 | NostrEnvelope | The unsigned event envelope. |
404 | ErrorResponse | No order with this id. |
default | ErrorResponse | The request failed. The envelope states the status, a human readable message, and the request id. |
operator
Separately authenticated moderation.
POST /api/ordex/admin/orders/{id}/withdraw
Operator moderation, separately authenticated.
| Parameter | In | Type | Notes |
|---|
id | path | string | The order id. |
Request body: object
| Status | Answers | Notes |
|---|
201 | OrderSummary | The withdrawn order. |
401 | ErrorResponse | Operator credentials missing, invalid, or not configured. |
404 | ErrorResponse | No order with this id. |
default | ErrorResponse | The request failed. The envelope states the status, a human readable message, and the request id. |
Schemas
The shapes the routes above exchange, exactly as the contract states them.
AtomicSats
An exact non-negative atomic amount as a decimal string. Never floating point, never grouped, never padded.
string, matching ^(0|[1-9][0-9]*)$
Network
mainnet | regtest | signet
Source
Where order evidence arrived from. Source is provenance, never proof; the node and the ord index decide the state.
openordex-nostr802 | ord-offers | direct-import
OrderClass
ASK_ANYONECANPAY | BID_FULLY_FUNDED | UNSUPPORTED
OrderState
Every state is reachable. A mempool conflict can return to LIVE when the conflicting spend is replaced or dropped; a confirmed spend does not come back short of a reorg. SETTLED is narrower than SPENT: the offered output was spent by a transaction observed carrying this order's exact payout.
PENDING_NODE | PENDING_ORD | LIVE | MEMPOOL_CONFLICTED | SPENT | SETTLED | REJECTED | WITHDRAWN
Actionability
What a customer may do right now. A LIVE order whose verification has aged past its freshness bound is REVIEW_ONLY, not HANDOFF_READY.
REVIEW_ONLY | HANDOFF_READY | BLOCKED
SignatureStatus
NONE | VALID | INVALID | UNAVAILABLE
OrderSide
ASK | BID
Outpoint
| Field | Type | Notes |
|---|
txid | string | |
vout | integer | |
AssetClaim
| Field | Type | Notes |
|---|
inscriptionId | string | |
outpoint | Outpoint | |
inscriptionNumber optional | integer | Read from the local ord index during verification, never from a claim. |
SourceEvidence
| Field | Type | Notes |
|---|
source | Source | |
sourceId | string | |
observedAt | string | |
eventId optional | string | |
eventPubkey optional | string | |
signatureVerified optional | boolean | |
claimedPriceSats optional | AtomicSats | |
claimedAsset optional | AssetClaim | |
PsbtInspection
| Field | Type | Notes |
|---|
psbtVersion | integer | |
unsignedTxid | string | |
digest | string | |
inputCount | integer | |
outputCount | integer | |
inputOutpoints | array of Outpoint | |
inputWitnessUtxos | array of object or null | |
outputValuesSats | array of AtomicSats | |
outputScriptsHex | array of string | |
hasProprietaryFields | boolean | |
hasUnknownFields | boolean | |
signatureStatus | SignatureStatus | |
orderClass | OrderClass | |
safety | PUBLIC_RACEABLE | TARGETED_REVIEW | UNSUPPORTED | |
reasons | array of string | |
Validation
| Field | Type | Notes |
|---|
checkedAt | string | |
nodeStatus | UNCONFIGURED | READY | UNAVAILABLE | OUTPOINT_MISSING | OUTPOINT_SPENT | |
ordStatus | NOT_REQUESTED | UNCONFIGURED | VERIFIED | MISMATCH | UNAVAILABLE | |
nodeTip optional | object | |
reasons | array of string | |
Settlement
Chain settlement the gateway actually observed, never an assumption.
| Field | Type | Notes |
|---|
txid | string | |
observedAt | string | |
confirmations | integer | |
confirmedAt optional | string | |
VerificationView
Read-time freshness of the last verification. Age is published with every order so staleness is visible rather than implied.
| Field | Type | Notes |
|---|
checkedAt | string | |
ageSeconds | number | |
maxAgeSeconds | number | |
stale | boolean | |
Withdrawal
| Field | Type | Notes |
|---|
withdrawnAt | string | |
reason optional | string | |
OrderSummary
What a list or detail response carries. The signed artifact is deliberately absent; it is released only through its own rate limited route while the order is live.
| Field | Type | Notes |
|---|
id | string | |
network | Network | |
inspection | PsbtInspection | |
assets | array of AssetClaim | |
sources | array of SourceEvidence | |
state | OrderState | |
actionability | Actionability | |
validation | Validation | |
sellerScriptHex optional | string | The output script of the PSBT input being sold. Only the key behind it can have created this listing, so it is the identity every seller management action is checked against. |
settlement optional | Settlement | |
protocolId optional | string | User supplied discovery metadata. It never substitutes for chain verification. |
token optional | string | |
side optional | OrderSide | |
quotedPriceSats optional | AtomicSats | |
withdrawal optional | Withdrawal | |
createdAt | string | |
updatedAt | string | |
OrderPage
| Field | Type | Notes |
|---|
orders | array of OrderSummary | |
total | integer | |
limit | integer | |
nextCursor | string | Keyset resume point for the next page. Empty when this page is last. |
hasMore | boolean | Derived from nextCursor, never from a total that concurrent writes can move. |
ActivityEntry
| Field | Type | Notes |
|---|
id | string | |
orderId | string | |
fromState | OrderState or null | Null for the first transition an order makes. |
toState | OrderState | |
reason | string | |
actor | string | Who caused the transition: the reconciler, the seller, an operator, or an import. |
observedAt | string | |
ActivityPage
| Field | Type | Notes |
|---|
entries | array of ActivityEntry | |
limit | integer | |
nextCursor | string | |
hasMore | boolean | |
OrderArtifact
ImportRequest
| Field | Type | Notes |
|---|
psbt | string | |
source optional | Source | |
sourceId optional | string | |
asset optional | AssetClaim | |
claimedPriceSats optional | string or number | |
protocolId optional | string | |
token optional | string | |
side optional | OrderSide | |
quotedPriceSats optional | string or number | |
QuoteRequest
What a buyer names when asking the gateway to price a purchase. The buyer names its own outputs and nothing else.
| Field | Type | Notes |
|---|
assetReceiveAddress optional | string | Where the buyer receives the asset. Never the payment address. |
paymentAddress optional | string | Where the buyer's change and merged padding return. |
paddingUtxos optional | array of object | Outputs placed ahead of the offered one, so the asset reaches the buyer. |
fundingUtxos optional | array of object | |
feeRateSatsPerVb optional | string or number | |
Quote
Everything a buyer needs to decide, and the unsigned half their wallet will be asked to sign. Every amount is atomic sats as a string.
| Field | Type | Notes |
|---|
orderId | string | |
network | Network | |
psbt | string | |
sellerIndex | integer | The index the seller's input and payment output share. |
asset | AssetClaim or null | |
assetReceiveAddress | string | |
paymentAddress | string | |
sellerPaymentScriptHex | string | |
assetValueSats | AtomicSats | |
sellerProceedsSats | AtomicSats | |
marketplaceFeeSats | AtomicSats | |
creatorRoyaltySats | AtomicSats | |
networkFeeSats | AtomicSats | |
feeRateSatsPerVb | string | |
estimatedVbytes | string | |
changeSats | AtomicSats | |
paddingSats | AtomicSats | Padding the buyer supplies and receives back, so it is not a cost. |
totalBuyerCostSats | AtomicSats | |
inputOutpoints | array of Outpoint | |
outputScriptsHex | array of string | |
outputValuesSats | array of AtomicSats | |
checkpoint | object | |
observedAt | string | |
expiresAt | string | |
PreflightRequest
Either the final transaction hex or the signed PSBT a wallet actually answers with.
| Field | Type | Notes |
|---|
finalTxHex optional | string | |
signedPsbt optional | string | |
PreflightResult
| Field | Type | Notes |
|---|
finalTxHex optional | string | The exact bytes checked, so a buyer broadcasts those and no others. |
orderId | string | |
allowed | boolean | |
rejectReason optional | string | |
txid optional | string | |
vsize optional | integer | |
feesSats optional | AtomicSats | |
checkedAt | string | |
BuildAskRequest
| Field | Type | Notes |
|---|
protocolId | string | |
token | string | |
quotedPriceSats | string or number | |
sellerPaymentAddress | string | |
asset optional | AssetClaim | |
outpoint optional | Outpoint | |
BuildAskResult
| Field | Type | Notes |
|---|
psbt | string | |
inspection | PsbtInspection | |
outpoint | Outpoint | |
nodeTip | object | |
protocolId | string | |
builderProfile | OPEN_ASK | EXTERNAL_PSBT | EXTERNAL_SETTLEMENT | |
PublishAskRequest
| Field | Type | Notes |
|---|
psbt | string | The seller half, now signed by the seller's own wallet. |
OwnershipChallenge
The message a seller signs to prove they own a listing's source UTXO.
| Field | Type | Notes |
|---|
orderId | string | |
address | string | |
message | string | |
windowStart | string | |
expiresAt | string | |
OwnershipProof
| Field | Type | Notes |
|---|
address optional | string | |
signature optional | string | |
reason optional | string | |
NostrEnvelope
| Field | Type | Notes |
|---|
kind | constant 802 | |
created_at | integer | |
tags | array of array of string | |
content | string | |
notice | string | |
NostrEvent
| Field | Type | Notes |
|---|
id | string | |
pubkey | string | |
created_at | integer | |
kind | integer | |
tags | array of array of string | |
content | string | |
sig | string | |
ProtocolCapabilities
What a protocol can truthfully do today. An entry in the catalog never implies a working flow beyond these booleans.
| Field | Type | Notes |
|---|
browse | boolean | |
createListing | boolean | |
verifyAssetSemantics | boolean | True when the local ord index proves the asset's current location, not only that its UTXO is unspent. |
reviewOnlyHandoff | boolean | |
externalSettlement | boolean | |
sourceIngestion | boolean | |
mediaResolution | boolean | |
ProtocolTemplate
| Field | Type | Notes |
|---|
id | string | |
label | string | |
route | string | |
family | bitcoin | dogecoin | counterparty | |
capability | PSBT_HANDOFF | EXTERNAL_SETTLEMENT | |
builderProfile | OPEN_ASK | EXTERNAL_PSBT | EXTERNAL_SETTLEMENT | |
assetRequirement | INSCRIPTION | OUTPOINT | NONE | |
templateLabel | string | |
templateGuidance | string | |
verificationScope | string | Plain language scope of what verification proves for this protocol. Never softened to look more capable. |
capabilities | ProtocolCapabilities | |
groupId | string | |
groupLabel | string | |
groupOrder | integer | |
displayOrder | integer | |
aliasOf optional | string | Set when this id is a catalog alias of another protocol. Aliases stay filterable but are not offered as a separate market leaf. |
ListingReadiness
Whether a Bitcoin listing can actually be verified right now. Observed, never inferred from the presence of a URL.
| Field | Type | Notes |
|---|
ready | boolean | |
reason | not_configured | storage_unavailable | core_unavailable_or_syncing | ord_unreachable | ord_index_behind | observation_timed_out or null | |
coreHeight | integer or null | |
ordHeight | integer or null | |
lagBlocks | integer or null | |
maxLagBlocks | integer | |
storageWritable | boolean | |
checkedAt | string | |
HealthReport
| Field | Type | Notes |
|---|
ok | boolean | |
service | constant "ordex" | |
enabled | boolean | |
defaultEnabled | boolean | |
network | Network | |
status | active | degraded | disabled | |
featureFlag | constant "ORDEX_ENABLED" | |
coreConfigured | boolean | |
ordConfigured | boolean | |
configurationComplete | boolean | |
signsOrBroadcasts | constant false | |
spendsFunds | constant false | |
supportedSources | array of Source | |
storageWritable | boolean | |
readyForBitcoinListings | boolean | |
maxVerificationAgeSeconds | number | |
listingReadiness | ListingReadiness | |
ProtocolContract
| Field | Type | Notes |
|---|
name | constant "Ordex" | |
settlement | string | |
sourceOfTruth | string | |
supportedProfiles | array of string | |
orderTemplates | object | |
safety | object | |
nostr | object | |
ErrorResponse
The error envelope every route answers with. Rate limited requests additionally carry `code: ORDEX_RATE_LIMITED`.
| Field | Type | Notes |
|---|
statusCode | integer | |
error | string | |
message | string or array of string | |
requestId optional | string | |
code optional | string | |