ORD20 APIapi.ord20.ioord20.io →
Read API · Poort I-6

Everything the index knows about ORD20, as JSON.

Tokens, cards, mint state, balances per address, transfers, holders, listings and trades — read from the ORD20 indexer on the ORDnet node. One write route: broadcast a transaction through our own node.

Base URLhttps://api.ord20.io/v1/ord20
numbers
always strings
counters are u64/i128; parse with BigInt, never Number
identity
by id, never by symbol
72 hex chars: deploy txid (little-endian) ‖ vout (LE u32)
errors
{ "error": { code, message } }
not_found · invalid_id · invalid_request · broadcast_rejected · node_unavailable · internal

Conventions

Reads are served from one repeatable-read snapshot per request, so the numbers in a single answer belong together. No authentication. CORS is open to ord20.io origins.

TermMeaning
idToken id: the deploy transaction's txid in little-endian hex followed by the card output index as little-endian u32 — 72 lowercase hex characters. Symbols (sym) are labels and can repeat.
outpointSame 72-hex form (txid LE ‖ vout LE) for any output, e.g. the active mint state.
pkhAddresses are given and returned as the 40-hex public-key hash of a P2PKH address.
unitsOne unit is one satoshi locked in the token covenant. Display convention: two decimals (1.00 = 100 units).
heightBlock height as a string. tx_index is the transaction's position in that block.

Routes

The first seven routes are the contract of the mint-page specification §7; the last five are the website additions v1.0 (explorer, token page, market, richlist).

GET/status

Index tip, node tip and how far the index is behind; counters and the sync profile (anchor block 963369, ruleset 0.2.18, mainnet).

{ "tip": { "height": "967017", "hash": "00000000…" }, "node_tip": "967020", "index_behind": "3", "index_behind_threshold": "3",
  "blocks": "3649", "tokens": "1", "utxos": "3", "reorgs": "0", "catalog_hash": "…",
  "sync_profile": { "start_height": "963369", "start_parent_hash": "…", "ruleset": "0.2.18", "network": "main:…", "anchor_id": "…" },
  "indexer_node_height": "967020", "node_error": null, "api_version": "1.0.1" }
GET/tokens?mintable=1&q=&page=

mintable=1 keeps only tokens whose mint is open with an active state. q matches the symbol (case-insensitive) or an id prefix. 50 per page; has_more tells you to fetch the next.

{ "items": [ {
    "id": "aa9f…00000000", "card": { "p": "ord-20", "op": "deploy", "ver": 1, "sym": "ORDTEST", "name": "ORD20 network test",
      "cap_mode": "capped", "cap": "10000", "premint": "1000", "m1_enabled": true, "x": "1000", "mint_fee": "100",
      "fee_default": "token", "mint_vout": 1, "whitelist_root": null },
    "deploy_height": "967006", "deploy_txid": "829f…", "holders": "2", "issuer_pkh": "e8e5…",
    "mint_status": "open", "minted_total": "2000", "free": "1807", "listed": "0", "loss_a": "193", "loss_c": "0", "invalidated": "0",
    "active_mint": "3176…00000000",
    "active_mint_state": { "ver": 1, "id": "aa9f…", "issuer": "e8e5…", "cap_mode": "capped", "cap": "10000", "x": "1000",
      "mint_fee": "100", "m1": true, "premint": "1000", "activated": true, "remaining": "8000", "minted_total": "2000" },
    "last_height": "967014" } ],
  "page": "1", "page_size": "50", "has_more": false }
GET/tokens/{id}

One token record, same shape as an item above. Unknown id → 404 not_found; anything that is not 72 hex chars → 400 invalid_id.

GET/tokens/{id}/mint-state

The active mint state to build an M1 against. outpoint is the state UTXO; active_mint_state is null when the mint is closed or not activated.

{ "outpoint": "3176…00000000", "mint_status": "open", "height": "967013",
  "active_mint_state": { "id": "…", "issuer": "…", "cap_mode": "capped", "cap": "10000", "x": "1000", "mint_fee": "100", "m1": true,
                         "premint": "1000", "activated": true, "remaining": "8000", "minted_total": "2000" } }
GET/address/{pkh}/utxos?token={id}

Live token/lock/mint outputs owned by a pkh (max 500). role: G = issued to the holder, R = received by transfer, M = mint state.

[ { "outpoint": "3176…01000000", "id": "aa9f…", "form": "token", "role": "G", "owner": "e8e5…", "sats": "1000", "price_sats": null, "height": "967013" } ]
GET/tx/{txid}

Indexed: seen: true with block, position, roles and events. Only known to the node (mempool or not yet indexed): seen: false, node_known: true. Neither: 404 not_found.

{ "txid": "4497…", "seen": true, "block_height": "967014", "block_hash": "…", "tx_index": 903, "n_inputs": 1, "n_outputs": 1,
  "roles": ["R"], "ids": ["aa9f…"], "events": [ { "type": "melt", "amount": "193", "kind": "loss_a" }, { "type": "transfer", "amount": "807", "vout": 0 } ], "errors": [] }
POST/broadcast

Body { "rawtx": "<hex>" }. Sent to the ORDnet node with sendrawtransaction. An explicit node rejection is 400 broadcast_rejected with the node's reason. A transport or protocol failure is 502 node_unavailable: the outcome is unknown — resolve the same txid via /tx, never rebuild and resend.

{ "txid": "…", "accepted": true }
GET/tokens/{id}/transfers?limit=

Newest first. fee_from is token when the transfer paid its miner fee from the token value (a melt · loss_a event in the same transaction), else bsv.

[ { "txid": "…", "from": "e8e5…", "to": "ed40…", "amount": "807", "height": "967014", "fee_from": "token" } ]
GET/tokens/{id}/holders

Distribution over live token and lock outputs (top 1000 holders). Shares are percentages with two decimals, as strings.

{ "total_holders": "2", "total_units": "1807",
  "distribution": [ { "label": "Top 1", "units": "1000", "share": "55.34" }, { "label": "Top 10", … }, { "label": "Top 100", … }, { "label": "Rest", … } ],
  "rows": [ { "rank": 1, "pkh": "e8e5…", "units": "1000", "share": "55.34", "outputs": "1" }, … ] }
GET/tokens/{id}/mints?limit=

Public mints (M1) and the issuer's activation (M0, amount = premint), newest first. by is public for M1, null for M0.

[ { "txid": "…", "to": "e8e5…", "amount": "1000", "height": "967013", "by": "public" } ]
GET/tokens/{id}/listings?limit=

Open ORD/locked listings, cheapest per unit first.

[ { "outpoint": "…", "seller": "…", "units": "500000", "price_sats": "750000", "height": "…" } ]
GET/tokens/{id}/trades?limit=

Completed sales (sold events), newest first.

[ { "txid": "…", "units": "200000", "price_sats": "280000", "buyer": "…", "height": "…" } ]

Errors

HTTPcodeWhen
400invalid_idan id, outpoint, pkh or txid has the wrong form (e.g. a symbol or a base58 address where a pkh is expected)
400invalid_requestbad query or body (non-JSON, non-hex rawtx, disallowed characters in q)
400broadcast_rejectedthe node explicitly rejected the transaction; message carries its reason
404not_foundunknown route, token, or transaction
502node_unavailablethe node did not answer cleanly; for broadcast this means the outcome is unknown
500internalanything else; nothing about the cause is leaked