X-Change Guide

API reference, in plain language

Every endpoint the node exposes. JWT means it needs an Authorization: Bearer <access token> header. All requests and responses are JSON; amounts are integer minor units (1 XCH = 1e8).

Error convention
Every error returns { "error": "message" } with a proper HTTP status: 400 bad request, 401 unauthorized, 404 not found, 409 conflict, 500 internal, 429 rate limited.
MethodPathAuthWhat it does
GET/healthpublicLiveness check. Railway pings this. Returns status, service, env, chain height, node.
POST/auth/challengepublicStart sign-in-with-wallet: give your address, get a random single-use challenge (10 min expiry).
POST/auth/loginpublicProve ownership: address + pubkey + challenge + signature. Verifies signature AND that pubkey derives to address. Returns access + refresh JWTs.
POST/auth/refreshpublicTrade a valid refresh token for a fresh access + refresh pair (rotation).
GET/auth/meJWTWho am I? Returns the token's address and its balances.
POST/tx/submitpublicSubmit a signed transaction. Validates hash, signature, nonce, balance, min fee, chain id. Returns {tx_hash, status:'pending'}.
GET/tx/{hash}publicFetch a single transaction by its 64-hex hash. 404 if missing.
GET/txspublicRecent transactions. ?address= filters by wallet, else latest chain-wide. limit max 200.
POST/faucetpublicMint 100 XCH once per address. Node signs the tx with the faucet key.
GET/wallet/{address}publicWallet summary: balances, nonce, last 20 transactions. Lazily creates the account row.
GET/wallet/{address}/noncepublicThe account's next nonce — used for signing.
GET/chain/heightpublic{height} — the latest block index.
GET/chain/blockspublicRecent blocks (newest first). ?after=&limit= pagination.
GET/chain/blocks/{sel}publicOne block by index (number) or by hash (64 hex), including its transactions.
GET/chain/validatorspublicActive validators ordered by stake (also aliased at /staking/validators).
GET/chain/searchpublicUniversal search: number → block index, 64-hex → block hash, 0x… → matching transactions.
GET/trade/orderbookpublicOrder book depth: bids + asks as [price, size] pairs, plus best bid/ask.
POST/trade/orderJWTPlace an order (limit or market). Locks funds, matches, settles, refunds remainder. Returns {order_id, filled, trades, status}.
GET/trade/ordersJWTThe caller's last 50 orders.
DELETE/trade/order/{id}JWTCancel an open order, refund the unfilled lock, remove from the in-memory book.
GET/trade/tradespublicRecent trades for the pair, newest first.
POST/staking/registerJWTSelf-stake ≥ MIN_STAKE (10 XCH) and become a validator.
POST/staking/stakeJWTLock XCH into a validator's escrow (defaults to self).
POST/staking/unstakeJWTSchedule release of eligible stake (cooldown = 2 epochs).
GET/staking/positionsJWTThe caller's stake positions with a pending/active flag.
POST/multisig/walletJWTCreate an N-of-M multisig wallet. Deterministic address → idempotent.
POST/multisig/txJWTPropose a transfer from a multisig wallet (signer only).
POST/multisig/tx/{id}/signJWTEndorse a proposal (signer only, deduped).
POST/multisig/tx/{id}/executeJWTExecute once unique valid signatures ≥ threshold. Moves balances + bumps nonce.
GET/multisig/wallet/{address}publicMultisig wallet detail: signers, threshold, balances, txs, pending proposals.
GET/admin/metricsJWTChain-wide metrics: height, TVL, 24h volume, active wallets, total accounts, total staked, validator count, pending txs, blocks last hour.
GET/admin/validatorsJWTPer-validator: address, stake, rewards, blocks proposed.

Grouped by concern