git / moonbite-network / templates/developers.html · raw
{% extends "base.html" %}{% block body_class %}{% endblock %}{% block title %}MoonBite Developers — API, docs & run a node{% endblock %}{% block meta_description %}Build on MoonBite: a read-only REST API for blocks, transactions and search, plus everything you need to run your own node.{% endblock %}{% block head_extra %}<style nonce="{{ csp_nonce }}">/* Developers page: composed from moonbite-ds.css; only layout glue here, tokens only. */.dv [id] { scroll-margin-top: 96px; }.dv .ds-copy { min-height: 44px; min-width: 64px; }.dv .ds-code pre { white-space: pre; }.dv .ds-code-bar .ep { overflow-wrap: anywhere; }.dv-head-code { margin-top: 0; }.dv-howto-body { min-width: 0; }.dv-howto-body .ds-code + .ds-code { margin-top: 8px; }.dv-howto-body .ds-actions { margin-top: 16px; }.dv-group { padding-top: 64px; }.dv-group:first-child { padding-top: 0; }.dv-group + .dv-group { border-top: 1px solid var(--ds-line); margin-top: 64px; }.dv-group .ds-h3 { margin-top: 12px; }.dv-group .ds-sub { max-width: 68ch; font-size: 16px; }.dv-group .ds-sub code, .dv .ds-table code, .dv-howto-body p code, .dv .ds-callout code, .dv .ds-tile code { font-family: var(--ds-mono); font-size: .9em; padding: 1px 6px; border-radius: 6px; background: var(--ds-raise); color: var(--ds-bone); overflow-wrap: anywhere; }.dv .ds-table { min-width: 560px; }.dv .ds-table td { color: var(--ds-ash); }.dv .ds-table td.ep { width: 42%; color: var(--ds-bone); font-family: var(--ds-mono); font-size: 13px; overflow-wrap: anywhere; }.dv .ds-table td.ep .ds-tag { margin-right: 8px; color: var(--ds-bone); }.dv .ds-table td.auth { width: 18%; font-family: var(--ds-mono); font-size: 12px; overflow-wrap: anywhere; }.dv .flow { display: block; margin-top: 8px; font-family: var(--ds-mono); font-size: 12px; color: var(--ds-bone); overflow-wrap: anywhere; }.dv-group .ds-grid { margin-top: 24px; }.dv-group .ds-callout { margin-top: 24px; }.dv .ds-card .art svg { width: 160px; height: 112px; }@media (max-width: 767px) { .dv-group { padding-top: 48px; } .dv-group + .dv-group { margin-top: 48px; }}</style>{% endblock %}{% block content %}<div class="ds dv"><!-- ================= PAGE HEAD ================= --><header class="ds-pagehead split"> <div class="ds-wrap"> <div> <ol class="ds-crumbs"> <li><a href="/">MoonBite</a></li> <li><span aria-current="page">Developers</span></li> </ol> <p class="ds-eyebrow">Developers · Open network</p> <h1 class="ds-title">Build on MoonBite.<br><span class="g">Read the chain over HTTP.</span></h1> <p class="ds-lede">A clean, read-only REST API for the chain: blocks, transactions and search, <b>no keys required</b>. Run a node, index the chain, or wire MBITE into your app.</p> <div class="ds-actions"> <a class="ds-btn gold" href="#api">API reference <svg width="16" height="16" viewBox="0 0 16 16" aria-hidden="true"><path d="M3 8h10M9 4l4 4-4 4" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg> </a> <a class="ds-btn" href="#run-a-node">Run a node</a> </div> <ul class="ds-checks"> <li>No keys to read</li> <li>Read-only: never moves funds</li> <li>JSON with a <span class="mono">status</span> field</li> </ul> </div> <div class="ds-code dv-head-code"> <div class="ds-code-bar"> <span class="ep">GET /api/consensus</span> <button class="ds-copy" type="button" data-copy="#dv-consensus-cmd" aria-label="Copy the consensus request">Copy</button> </div><pre><span class="c"># The coin's monetary rules, as JSON</span><span id="dv-consensus-cmd">curl -s https://moonbite.org/api/consensus</span><span class="c"># Response (abridged, live values)</span>{ "block_time_sec": {{ consensus.block_time_sec|tojson }}, "current_reward_coins": {{ consensus.current_reward_coins|tojson }}, "halving_interval": {{ consensus.halving_interval|tojson }}, "height": {{ consensus.height|tojson }}, "max_supply_coins": {{ consensus.max_supply_coins|tojson }}, "status": "success", …}</pre> </div> </div></header><!-- ================= QUICK START ================= --><section class="ds-section" id="quickstart" aria-labelledby="dv-qs-h"> <div class="ds-wrap"> <p class="ds-eyebrow">Quick start</p> <h2 class="ds-h2" id="dv-qs-h">Make your first request. <span class="dim">No sign-up, no key.</span></h2> <p class="ds-sub">Open a terminal and run each command. Every response is JSON with a <span class="mono">status</span> field.</p> <ol class="ds-howto"> <li> <div class="dv-howto-body"> <h3 class="ds-h3">Read the chain state</h3> <p>Get the height, tip hash, coins in circulation, tx count and mempool size.</p> <div class="ds-code"> <div class="ds-code-bar"><span>Request</span><button class="ds-copy" type="button">Copy</button></div><pre>curl -s https://moonbite.org/api/blockchain/info</pre> </div> <div class="ds-code"> <div class="ds-code-bar"><span>Response · example</span></div><pre>{ "status": "success", "height": 128, "tip_hash": "…", "total_money_coins": 1280, "tx_count": 129, "mempool_size": 0}</pre> </div> </div> </li> <li> <div class="dv-howto-body"> <h3 class="ds-h3">List the newest blocks</h3> <p>Page through blocks, newest first. <code>limit</code> takes 1–50; <code>offset</code> skips from the tip.</p> <div class="ds-code"> <div class="ds-code-bar"><span>Request</span><button class="ds-copy" type="button">Copy</button></div><pre>curl -s "https://moonbite.org/api/explorer/blocks?limit=5&offset=0"</pre> </div> <div class="ds-code"> <div class="ds-code-bar"><span>Response · example</span></div><pre>{ "status": "success", "blocks": [ { "height": 128, "hash": "…", "tx_count": 1, "confirmations": 1 } ], "total": 129}</pre> </div> </div> </li> <li> <div class="dv-howto-body"> <h3 class="ds-h3">Look up a block or transaction</h3> <p>Pass a height, a block hash or a txid as <code>q</code>. Height <span class="mono">0</span> is the genesis block, so this command always resolves.</p> <div class="ds-code"> <div class="ds-code-bar"><span>Request</span><button class="ds-copy" type="button">Copy</button></div><pre>curl -s "https://moonbite.org/api/explorer/search?q=0"</pre> </div> </div> </li> </ol> </div></section><!-- ================= REFERENCE ================= --><section class="ds-section alt" aria-labelledby="dv-ref-h"> <div class="ds-wrap"> <div class="ds-split"> <nav class="ds-toc" aria-label="On this page"> <p class="ds-eyebrow">On this page</p> <a href="#quickstart">Quick start</a> <a href="#api">REST API</a> <a href="#exchange">Exchange API</a> <a href="#merchant">Merchant API</a> <a href="#run-a-node">Run a node</a> <a href="#source">Source code</a> </nav> <div> <p class="ds-eyebrow">Reference</p> <h2 class="ds-h2" id="dv-ref-h">API reference</h2> <p class="ds-sub">Three groups of endpoints. Paths are relative to <span class="mono">https://moonbite.org</span> or to your own node.</p> <!-- REST API --> <div class="dv-group" id="api"> <p class="ds-eyebrow">REST API</p> <h3 class="ds-h3">Read-only endpoints</h3> <p class="ds-sub">Every endpoint returns JSON with a <code>status</code> field. These are read-only: they never move funds or expose keys.</p> <div class="ds-table-wrap"> <table class="ds-table"> <thead><tr><th scope="col">Endpoint</th><th scope="col">Returns</th></tr></thead> <tbody> <tr><td class="ep"><span class="ds-tag">GET</span>/api/blockchain/info</td><td>Chain height, tip hash, coins in circulation, tx count and mempool size.</td></tr> <tr><td class="ep"><span class="ds-tag">GET</span>/api/explorer/blocks</td><td>Paginated block list, newest first. Params: <code>limit</code> (1–50), <code>offset</code>.</td></tr> <tr><td class="ep"><span class="ds-tag">GET</span>/api/explorer/block/<id></td><td>A single block by <em>height</em> or <em>hash</em>, including its transactions.</td></tr> <tr><td class="ep"><span class="ds-tag">GET</span>/api/explorer/tx/<txid></td><td>A transaction by id, from the active chain or the mempool, with inputs/outputs.</td></tr> <tr><td class="ep"><span class="ds-tag">GET</span>/api/explorer/search?q=</td><td>Resolve a query to a block (height/hash) or a transaction (txid).</td></tr> <tr><td class="ep"><span class="ds-tag">GET</span>/api/transactions</td><td>The most recent transactions across the mempool and latest blocks.</td></tr> <tr><td class="ep"><span class="ds-tag">GET</span><a class="ds-textlink" href="/api/consensus">/api/consensus</a></td><td>The coin's monetary rules (subsidy, halving interval, block time, max supply) plus the live reward and height. Every number on this site is rendered from it.</td></tr> </tbody> </table> </div> </div> <!-- EXCHANGE API --> <div class="dv-group" id="exchange"> <p class="ds-eyebrow">Exchange API · Phase 2</p> <h3 class="ds-h3">Non-custodial order book and atomic-swap settlement</h3> <p class="ds-sub">The order book stores <em>intents</em> only: never coins, keys, or balances. Settlement is a cross-chain <abbr title="Hash Time-Locked Contract">HTLC</abbr> atomic swap between the two wallets; the server just coordinates the hand-off and, once enabled, <strong>verifies it on-chain</strong>. A trade only moves <code>last_price</code> after the verifier confirms both HTLC legs redeemed on-chain. There is no fabricated market data.</p> <div class="ds-table-wrap"> <table class="ds-table"> <thead><tr><th scope="col">Endpoint</th><th scope="col">Auth</th><th scope="col">What it does</th></tr></thead> <tbody> <tr><td class="ep"><span class="ds-tag">POST</span>/api/exchange/order</td><td class="auth">None</td><td>Place a buy/sell order. Returns a one-time secret <code>cancel_token</code>: the only credential that can cancel the order or drive its swap. The public MBITE address cannot.</td></tr> <tr><td class="ep"><span class="ds-tag">GET</span>/api/exchange/orders?pair=</td><td class="auth">None</td><td>The public order book for a pair: bids, asks, and <code>last_price</code> (<code>null</code> until an on-chain-verified trade settles). The <code>cancel_token</code> is never exposed on any read path.</td></tr> <tr><td class="ep"><span class="ds-tag">POST</span>/api/exchange/order/<id>/swap/init</td><td class="auth">cancel_token</td><td>Register the HTLC hand-off for a matched pair. Records only <em>public</em> swap parameters: hashlock, recipient/refund pubkeys, and timelocks (base must out-live quote). No key or preimage is ever accepted.</td></tr> <tr><td class="ep"><span class="ds-tag">POST</span>/api/exchange/order/<id>/swap/funded</td><td class="auth">cancel_token</td><td>Report an HTLC funding txid for one leg (<code>base</code> | <code>quote</code>). This is only a <em>hint</em> telling the verifier where to look; the fact is re-checked on-chain, never trusted on your word. Advances the state machine toward <code>both_locked</code>.</td></tr> <tr><td class="ep"><span class="ds-tag">GET</span>/api/exchange/order/<id>/swap</td><td class="auth">None</td><td>The public swap state for a matched order. The <code>preimage</code> appears only once it is already public on-chain.<span class="flow">swap_init → base_funded → quote_funded → both_locked → quote_redeemed → base_redeemed → settled</span><span class="flow">(or expired on refund/timeout)</span></td></tr> <tr><td class="ep"><span class="ds-tag">POST</span>/api/exchange/verify <span class="ds-tag">operator</span></td><td class="auth">X-Verifier-Token</td><td>Runs one <strong>read-only</strong> on-chain verification pass over pending swaps and settles any that fully redeemed. Off unless the operator sets <code>VERIFIER_ENABLED</code>, and gated by an <code>X-Verifier-Token</code> secret: intended for a cron/timer, not public traffic. The single event that lets <code>last_price</code> move.</td></tr> </tbody> </table> </div> <div class="ds-grid c2"> <div class="ds-code"> <div class="ds-code-bar"><span class="ep">POST /api/exchange/order · body</span><button class="ds-copy" type="button">Copy</button></div><pre>{ "side": "sell", "pair": "MBITE/LTC", "price": "0.0005", "amount": "100", "mbite_address": "moon1…", "quote_address": "ltc1…" }</pre> </div> <div class="ds-code"> <div class="ds-code-bar"><span class="ep">POST …/swap/init · body</span><button class="ds-copy" type="button">Copy</button></div><pre>{ "cancel_token": "…", "hashlock": "<sha256(preimage)>", "base_recipient_pubkey": "02…", "base_refund_pubkey": "02…", "quote_recipient_pubkey": "02…", "quote_refund_pubkey": "02…", "base_locktime": 172800, "quote_locktime": 86400 }</pre> </div> </div> <div class="ds-callout"> <p class="label">How the swap verifier works</p> <p>The swap verifier assembles the HTLC redeemscript, derives its funding address, confirms both legs are funded to the agreed amount and depth, extracts the preimage from the public quote redemption, and confirms the base leg reused that same preimage. <strong>It builds, signs, and broadcasts nothing.</strong> See <code>swap_verifier.py</code> in the repo.</p> </div> </div> <!-- MERCHANT API --> <div class="dv-group" id="merchant"> <p class="ds-eyebrow">Merchant API</p> <h3 class="ds-h3">Accept MBITE: payment observation, no custody</h3> <p class="ds-sub">Raise an invoice against your own address; the server <em>observes</em> the chain for a matching inbound payment and marks it paid. Funds go wallet-to-wallet. The server never holds them.</p> <div class="ds-table-wrap"> <table class="ds-table"> <thead><tr><th scope="col">Endpoint</th><th scope="col">Auth</th><th scope="col">What it does</th></tr></thead> <tbody> <tr><td class="ep"><span class="ds-tag">POST</span>/api/merchant/invoice</td><td class="auth">merchant_id + X-Merchant-Token</td><td>Raise a payment request against a merchant address. Snapshots the address's prior receipts so only a <em>new</em> inbound payment settles this invoice. Returns a BIP21-style <code>pay_uri</code>.</td></tr> <tr><td class="ep"><span class="ds-tag">GET</span>/api/merchant/invoice/<id></td><td class="auth">None</td><td>Poll one invoice. Re-checks the chain for payment on every call and flips <code>pending → paid</code> / <code>expired</code>.</td></tr> <tr><td class="ep"><span class="ds-tag">GET</span>/api/merchant/invoices?merchant_id=</td><td class="auth">X-Merchant-Token</td><td>A shop dashboard read: list a merchant's invoices, each freshly checked on-chain. Listing also advances any that have been paid or expired since last seen.</td></tr> <tr><td class="ep"><span class="ds-tag">POST</span>/api/merchant/invoices/poll</td><td class="auth">merchant_id + X-Merchant-Token</td><td>Sweep a merchant's pending invoices in one pass, auto-marking paid/expired ones, so a shop (or a timer) need not poll each invoice by hand. Idempotent; observes only.</td></tr> </tbody> </table> </div> </div> </div> </div> </div></section><!-- ================= RUN A NODE ================= --><section class="ds-section" id="run-a-node" aria-labelledby="dv-node-h"> <div class="ds-wrap"> <p class="ds-eyebrow">Run a node</p> <h2 class="ds-h2" id="dv-node-h">Enforce the rules yourself.</h2> <p class="ds-sub">A full node validates every block and transaction against MoonBite's consensus rules and helps other peers stay in sync. Don't trust: verify.</p> <ol class="ds-howto"> <li> <div class="dv-howto-body"> <h3 class="ds-h3">Get the node</h3> <p>Read the node and downloads guide, then install the build for your platform.</p> <div class="ds-actions"> <a class="ds-btn" href="/downloads/README.txt">Node & downloads</a> </div> </div> </li> <li> <div class="dv-howto-body"> <h3 class="ds-h3">Create an address</h3> <p>Ask your node's wallet for a fresh receiving address.</p> <div class="ds-code"> <div class="ds-code-bar"><span>Terminal</span><button class="ds-copy" type="button">Copy</button></div><pre>moonbite-cli getnewaddress</pre> </div> </div> </li> <li> <div class="dv-howto-body"> <h3 class="ds-h3">Check chain state over REST</h3> <p>Query your own node instead of moonbite.org. The response has the same shape as in the <a class="ds-textlink" href="#quickstart">quick start</a>.</p> <div class="ds-code"> <div class="ds-code-bar"><span>Terminal</span><button class="ds-copy" type="button">Copy</button></div><pre>curl -s http://127.0.0.1:5000/api/blockchain/info</pre> </div> </div> </li> </ol> </div></section><!-- ================= PRINCIPLES + SOURCE ================= --><section class="ds-section alt" id="source" aria-labelledby="dv-src-h"> <div class="ds-wrap"> <p class="ds-eyebrow">Built to be read</p> <h2 class="ds-h2" id="dv-src-h">Open source. <span class="dim">Open data.</span></h2> <div class="ds-grid c3"> <div class="ds-tile"> <div> <h3 class="ds-h3">Litecoin lineage</h3> <p>Battle-tested core, familiar tooling and address formats (<code>moon1…</code> / <code>M…</code>).</p> </div> </div> <div class="ds-tile"> <div> <h3 class="ds-h3">No auth to read</h3> <p>Public read-only endpoints. Nothing here can spend coins or reveal a key.</p> </div> </div> <div class="ds-tile"> <div> <h3 class="ds-h3">Cross-origin reads</h3> <p>Browser reads from other origins are allow-listed, never a wildcard. Call the API from your backend, or run your own node and add your origin to <code>ALLOWED_ORIGINS</code>.</p> </div> </div> </div> <div class="ds-grid c2"> <a class="ds-card" href="/git/"> <div class="art" aria-hidden="true"> <svg viewBox="0 0 160 112" fill="none" stroke-linecap="round" stroke-linejoin="round"> <rect x="12" y="12" width="136" height="88" rx="8" stroke="#8A8580" stroke-width="2"/> <path d="M12 30h136" stroke="#8A8580" stroke-width="2"/> <path d="M58 52l-14 14 14 14M102 52l14 14-14 14" stroke="#F5F2EA" stroke-width="2"/> <path d="M86 48l-12 36" stroke="#8A8580" stroke-width="2"/> </svg> </div> <div class="body"> <span class="n">moonbite.org/git</span> <span class="t">Source code</span> <span class="d">The node, wallet, explorer and this website. Read it, build it, and send findings or patches.</span> <span class="go">Browse the source →</span> </div> </a> <a class="ds-card" href="/api/consensus"> <div class="art" aria-hidden="true"> <svg viewBox="0 0 160 112" fill="none" stroke-linecap="round" stroke-linejoin="round"> <path d="M54 18c-10 0-12 6-12 14v14c0 6-4 10-10 10 6 0 10 4 10 10v14c0 8 2 14 12 14" stroke="#F5F2EA" stroke-width="2"/> <path d="M106 18c10 0 12 6 12 14v14c0 6 4 10 10 10-6 0-10 4-10 10v14c0 8-2 14-12 14" stroke="#F5F2EA" stroke-width="2"/> <path d="M62 40h36M62 56h24M62 72h30" stroke="#8A8580" stroke-width="2"/> </svg> </div> <div class="body"> <span class="n">GET /api/consensus</span> <span class="t">Consensus as JSON</span> <span class="d">Block time <span class="mono">{{ consensus.block_time_min }}</span> minutes, halving every <span class="mono">{{ "{:,}".format(consensus.halving_interval) }}</span> blocks, max supply <span class="mono">{{ "{:,}".format(consensus.max_supply_coins) }}</span> MBITE. One source for every number.</span> <span class="go">Open the JSON →</span> </div> </a> </div> </div></section></div>{% endblock %}