git / moonbite-network / templates/merchant.html · raw
{% extends "base.html" %}{% block body_class %}mb-v2{% endblock %}{% block title %}Accept MBITE Payments - MoonBite Merchants{% endblock %}{% block nav_active %}merchants{% endblock %}{% block content %}<div class="main-content"> <section class="hero"> <h2>Accept MoonBite Payments</h2> <p>Non-custodial invoicing: customers pay your own address, wallet to wallet. The server only observes the chain.</p> </section> <div class="cards-grid"> <div class="card"> <div class="card-header">Self-Custody</div> <div class="card-body"> <p>Payments land directly on an address you control. MoonBite never holds coins, keys, or balances on your behalf.</p> </div> </div> <div class="card"> <div class="card-header">No Platform Fee</div> <div class="card-body"> <p>There is no merchant fee. The only cost is the ordinary network transaction fee the payer attaches to their transaction.</p> </div> </div> <div class="card"> <div class="card-header">Chain-Verified</div> <div class="card-body"> <p>An invoice is marked paid only when a new inbound payment of at least the invoiced amount is observed on chain above the balance snapshot taken when the invoice was raised.</p> </div> </div> <div class="card"> <div class="card-header">Token-Gated</div> <div class="card-body"> <p>Registering returns a manage token once. Only that token can raise invoices against your address or read your ledger.</p> </div> </div> </div> <div class="card card-full"> <div class="card-header">How It Works</div> <div class="card-body"> <ol class="info-list" style="list-style-type: decimal;"> <li><strong>Get a receive address</strong> from your own MoonBite wallet. Use a dedicated address for invoicing and do not spend from it while invoices are open.</li> <li><strong>Register once</strong> with <code>POST /api/merchants</code>. The response includes <code>manage_token</code> exactly once. Store it like a password; it is never shown again.</li> <li><strong>Create an invoice</strong> with <code>POST /api/merchant/invoice</code>, sending your merchant id and the token in the <code>X-Merchant-Token</code> header.</li> <li><strong>Show the customer</strong> the returned <code>pay_uri</code> or the QR at <code>/api/merchant/invoice/<id>/qr.svg</code>. They pay from their wallet.</li> <li><strong>Confirm payment</strong> by polling <code>GET /api/merchant/invoice/<id></code> until <code>status</code> is <code>paid</code>, or sweep all open invoices with <code>POST /api/merchant/invoices/poll</code>.</li> </ol> <p style="margin-top: 1rem; color: var(--text-secondary);"> Invoices expire after one hour if unpaid. While network hashrate is low, wait for a comfortable number of confirmations before releasing high-value goods. </p> </div> </div> <div class="card card-full"> <div class="card-header">1. Register a Merchant</div> <div class="card-body"> <pre class="code-block"><code>POST /api/merchantsContent-Type: application/json{ "name": "Your Shop", "category": "goods", "mbite_address": "<your MoonBite receive address>", "url": "https://example.com", "blurb": "What you sell"}201 Created{ "status": "success", "merchant": { "id": "<merchant_id>", "name": "Your Shop", "mbite_address": "<your MoonBite receive address>", "manage_token": "<shown once, store it securely>" }}</code></pre> <p style="color: var(--text-secondary);">Categories: goods, services, food, digital, donation, other. The token is not recoverable; if it is lost, register again.</p> </div> </div> <div class="card card-full"> <div class="card-header">2. Create an Invoice</div> <div class="card-body"> <pre class="code-block"><code>POST /api/merchant/invoiceContent-Type: application/jsonX-Merchant-Token: <manage_token>{ "merchant_id": "<merchant_id>", "amount": "12.5", "memo": "Order 1042"}201 Created{ "status": "success", "invoice": { "id": "<invoice_id>", "address": "<your MoonBite receive address>", "amount": "12.5", "status": "pending", "seconds_left": 3600, "pay_uri": "moonbite:<address>?amount=12.5&label=Order%201042" }}</code></pre> <p style="color: var(--text-secondary);"> The invoice is always raised against your registered address. Requests without a valid token, or naming any other address, are refused. Rate limit: 30 per minute per client. </p> </div> </div> <div class="card card-full"> <div class="card-header">3. Check Payment</div> <div class="card-body"> <pre class="code-block"><code>GET /api/merchant/invoice/<invoice_id>200 OK{ "status": "success", "invoice": { "id": "<invoice_id>", "status": "paid", "paid_units": 1250000000, "paid_at": 1760000000 }}GET /api/merchant/invoice/<invoice_id>/qr.svgimage/svg+xml encoding the pay_uri</code></pre> <p style="color: var(--text-secondary);"> Status is one of pending, paid, expired. Anyone holding the invoice id may poll it, so share ids only with the paying customer. Each poll may trigger a chain scan; polls are rate-limited and share a global scan budget, so a 503 with Retry-After means try again shortly. </p> </div> </div> <div class="card card-full"> <div class="card-header">4. Ledger and Sweep (authenticated)</div> <div class="card-body"> <pre class="code-block"><code>GET /api/merchant/invoices?merchant_id=<merchant_id>X-Merchant-Token: <manage_token>POST /api/merchant/invoices/pollContent-Type: application/jsonX-Merchant-Token: <manage_token>{ "merchant_id": "<merchant_id>" }200 OK{ "status": "success", "checked": 3, "paid": ["..."], "expired": [], "addresses_scanned": 1 }</code></pre> <p style="color: var(--text-secondary);"> Send the token only in the header, never in the URL. Both calls return only your own merchant's invoices. </p> </div> </div> <div class="card card-full"> <div class="card-header">Directory</div> <div class="card-body"> <p>Registered merchants are listed publicly at <code>GET /api/merchants</code> (optionally <code>?category=food</code>). Manage tokens are never included in directory reads.</p> </div> </div></div>{% endblock %}