What you need
| Field | What it does |
|---|---|
| Mint endpoint URL | Your node's public address-minting route. We call it to get a fresh address for each order. Not secret. |
| Webhook secret | A shared secret your watcher signs with and we verify. It can never touch your wallet. Secret. |
This option is for people who want to run their own node. You also run a Monero node, a view-only wallet, and a small always-on watcher on your own machine. This guide walks through all of it. If you would rather not run anything, connect a hosted crypto service instead.
Why we ask for each field
Mint endpoint URL
When a buyer clicks Buy, we ask your node for a fresh address to show them. That request goes to this one public route. It hands back an address and nothing else; your wallet stays private behind it.
Webhook secret
Your watcher tells us "this order is paid" by sending us a signed message. This shared secret lets us confirm the message genuinely came from your watcher, so nobody can forge a paid event. It can read nothing and move nothing.
Set up
- What you will run
Three things, all on your own machine. Nothing here is given to us except the public mint URL and the shared secret.
- A Monero node (monerod) and a view-only wallet (monero-wallet-rpc), kept private.
- A mint endpoint: one small public route that hands out a fresh address per order.
- A watcher: a tiny always-on program that watches your wallet and tells us when a payment lands.
- Create a view-only wallet
A view-only wallet can see incoming payments and mint fresh receive addresses, but it cannot spend. You build it from your real wallet’s address and its private view key, nothing else. That is what lets your node detect payments without ever holding the power to move them.
monero-wallet-cli --generate-from-view-key ~/monero/view-onlyIt prompts for your primary address and your private view key. Never enter your seed or spend key, keep those on a separate machine. It writes view-only and view-only.keys; set a password and save it in a file (wallet.password, next to the wallet) for the next step.
- Run your Monero node
The daemon syncs and holds the blockchain. Run it as a service (systemd or Docker) so it restarts on its own. Its RPC listens on 127.0.0.1:18081.
monerod --data-dir ~/.bitmonero --prune-blockchain --restricted-rpcA pruned node keeps the disk footprint small and still sees every incoming payment. The node reaches the network but exposes nothing public.
- Run the wallet RPC
A second service that opens the view-only wallet and answers the mint endpoint and watcher. Point it at your node and bind it to localhost. Run it as a service too.
monero-wallet-rpc \ --wallet-file ~/monero/view-only \ --password-file ~/monero/wallet.password \ --rpc-bind-ip 127.0.0.1 --rpc-bind-port 18083 \ --daemon-address 127.0.0.1:18081 --trusted-daemon \ --disable-rpc-loginNever expose wallet RPC to the public internet; bind it to localhost or a private network. --disable-rpc-login is fine only because it is localhost-only; use --rpc-login if it is reachable from anywhere else. Only the mint endpoint below is public.
- Install the Coin Moebius Monero package
It supplies the address minter, the webhook signer, and the watcher, so you write almost no code. The fastest path is the ready-to-run example below: copy the folder, fill in four values, and start it.
npm install @aquarian-metals/coin-moebius-moneroThe package on npm ↗Ready-to-run example (node, mint endpoint, watcher) ↗
- Generate your webhook secret
A strong random value that signs and verifies the webhook. Two ways to make one, your choice: click Generate when you add the provider in the dashboard (it runs in your browser, never on our servers), or run the command below yourself. Either way, paste the same value in both your watcher and the dashboard.
openssl rand -hex 32 - Stand up the mint endpoint
One public POST route that fronts your wallet. It uses the package’s createMoneroCreator to mint a fresh address per order. This is the only thing you expose to the internet, and it is safe to expose: it returns a receive address and moves no money.
// POST /coin-moebius/monero/mint import { createMoneroCreator } from '@aquarian-metals/coin-moebius-monero/server'; const mint = createMoneroCreator({ walletRpcUrl: 'http://127.0.0.1:18083/json_rpc', store: myStore, xmrPerUnit: async (cur) => (cur === 'XMR' ? 1 : await myPriceFeed(cur)), }); // return mint({ productId, amount, currency, metadata }) as JSONYou choose where prices come from. Coin Moebius never calls a price oracle.
- Run the watcher and point it at us
The watcher is the always-on program that checks your wallet every few seconds and signs us a message when a payment confirms. Set its webhook URL to your project address (below) and its secret to the value you generated. Run it next to your wallet, under systemd or Docker.
import { createMoneroIndexer } from '@aquarian-metals/coin-moebius-monero/server'; const watcher = createMoneroIndexer({ walletRpcUrl: 'http://127.0.0.1:18083/json_rpc', store: myStore, webhookUrl: process.env.MONERO_WEBHOOK_URL, // your Coin Moebius URL, below hmacSecret: process.env.MONERO_HMAC_SECRET, // the secret you generated requiredConfirmations: 10, }); watcher.start();Watcher recipe: indexer.js + systemd unit + docker-compose ↗
It is catch-up by design. If it is offline for a stretch, the next run sees the payments it missed and tells us then. A home server is fine; you do not need perfect uptime.
- Your webhook URL
Set the watcher’s webhookUrl to your project address. Your project id is on the project settings in the dashboard.
https://api.coinmoebius.com/webhook/monero/<your project id> - Connect in the dashboard
Add provider, choose Be your own provider, then Monero. Paste your mint endpoint URL and the webhook secret. That is everything we store, and neither value can touch your wallet.
After you connect
There is no sandbox for a self-hosted node, so your first small real payment is the test:
- Create a product and place the buy button on a page (a local HTML file works) pointed at your project.
- Pay a small amount of Monero from your own wallet.
- Wait for confirmations. Monero takes about twenty minutes to fully confirm, by design.
- Open the Transactions tab. When the new row reaches succeeded, your mint endpoint, watcher, and secret are all working end to end.
Troubleshooting
Checkout fails right away.
We could not reach your mint endpoint. Confirm it is a public https URL and that your node is online. The dashboard shows this as a reachability message when you save.
The buyer paid but the order stays pending.
Either the watcher is not running, or its secret does not match. Confirm the watcher process is up and that its MONERO_HMAC_SECRET is the exact value you pasted into the dashboard.
The payment took a while to show.
That is normal. Monero confirms over several blocks; the watcher waits for ten confirmations (about twenty minutes) before it reports success.
Good to know
Keep a view-only wallet on the hot box. The watcher only needs to see incoming payments. Keep your spend key on a separate, offline machine and sweep funds from there.
Never expose wallet RPC. Only the mint endpoint is public. Bind wallet RPC to localhost or a private network at all times.
Downtime is cheap. The watcher catches up after an outage and reports the payments it missed. Nothing is lost.
Rotating the secret. Generate a new secret anytime, then paste it into both the watcher and the dashboard.
Questions? [email protected]