XMR Payment Integration: Node Setup and RPC Gateway

Technical Complexities of Monero Payments: Protocol-Level Privacy Organizing Monero payment acceptance runs into privacy architecture: each transaction uses stealth addresses, ring signatures (Ring Signatures), and hidden amounts (RingCT). Without an RPC wallet, you won't see incoming transaction

Blockchain Development Services

Frequently Asked Questions

Latest works

  • image_website-b2b-advance_0.webp
    B2B ADVANCE company website development
    1450
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1308
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    1003
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1269
  • image_logo-advance_0.webp
    B2B Advance company logo design
    717
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    1008

Technical Complexities of Monero Payments: Protocol-Level Privacy

Organizing Monero payment acceptance runs into privacy architecture: each transaction uses stealth addresses, ring signatures (Ring Signatures), and hidden amounts (RingCT). Without an RPC wallet, you won't see incoming transactions — standard approaches like monitoring an address in the blockchain don't work here. We, a team of blockchain engineers with Monero integration experience, break down the engineering solution from node synchronization to subaddress monitoring. Get a consultation on implementation — discuss your architecture.

The difficulty of integrating Monero stems from its very nature. An address consists of two key pairs: (public spend key, private spend key) and (public view key, private view key). The sender generates a one-time stealth address using your public view key and a random scalar. Only the owner of the private view key can compute that the transaction belongs to them. RingCT hides amounts using Pedersen commitments — only the sender and receiver know the actual XMR amount. The average transaction fee is about 0.0001 XMR, which is significantly lower than bank transfers.

What This Means for Receiving Incoming Payments

You cannot simply scan the blockchain — monitoring requires the private view key. In practice, this means running a full node with monero-wallet-rpc or using the view key on the server (allows seeing incoming but not spending). Subjectively, Monero provides 15 decoys per input (since HF v15), and the average block time is 2 minutes. For production, it's critical to configure monero-wallet-rpc with TLS and authentication.

Feature Subaddress Payment ID (deprecated)
Privacy Full — does not reveal wallet link Reveals link to a single recipient
Blockchain level Different addresses Attached to the transaction
Standard De facto since 2018 Outdated, not recommended

Monero developers emphasize that subaddresses are the de facto standard for payment gateways. The wallet can generate up to 2^64 subaddresses, enough for any load.

Architecture: monero-wallet-rpc

The standard integration tool is monero-wallet-rpc from the official package. It provides a JSON-RPC interface for all operations: creating subaddresses, checking balance, forming transactions.

Node Deployment

First, synchronize monerod. The blockchain size is ~180 GB (pruned ~60 GB), initial sync takes 12–48 hours. Use SSD and at least 4 GB RAM.

# Run monerod with pruning monerod --data-dir /var/lib/monero \ --prune-blockchain \ --db-sync-mode fast \ --rpc-bind-ip 127.0.0.1 \ --rpc-bind-port 18081 \ --no-igd \ --detach # Run monero-wallet-rpc monero-wallet-rpc \ --daemon-address 127.0.0.1:18081 \ --rpc-bind-port 18083 \ --wallet-file /etc/monero/payment-wallet \ --password-file /etc/monero/wallet.pass \ --rpc-login payment_server:$(cat /etc/monero/rpc.pass) \ --disable-rpc-login false \ --trusted-daemon \ --non-interactive 

For production — separate wallet per environment, nginx with TLS, HTTP Basic. Contact us for a ready configuration — we'll help set it up.

How to Assign a Subaddress to Each Order Correctly?

Monero supports subaddresses — derived addresses fully independent at the blockchain level. This is a key feature for payment processing.

A four-step process:

  1. Wallet via monero-wallet-rpc.
  2. Create a subaddress for each order (create_address).
  3. Associate the subaddress with the order in the database.
  4. Monitor incoming transactions on that subaddress.

Example:

import requests RPC_URL = "http://127.0.0.1:18083/json_rpc" AUTH = ("payment_server", "rpc_password") def create_payment_address(order_id: str) -> dict: response = requests.post(RPC_URL, auth=AUTH, json={ "jsonrpc": "2.0", "id": "0", "method": "create_address", "params": { "account_index": 0, "label": f"order_{order_id}" } }) result = response.json()["result"] return { "address": result["address"], "address_index": result["address_index"] } def check_incoming_transfers(min_amount_xmr: float) -> list: response = requests.post(RPC_URL, auth=AUTH, json={ "jsonrpc": "2.0", "id": "0", "method": "get_transfers", "params": { "in": True, "pending": False, "min_height": 0 } }) transfers = response.json()["result"].get("in", []) return [t for t in transfers if t["amount"] / 1e12 >= min_amount_xmr] 

Subaddresses have been the de facto standard for several years and are now recommended for all new integrations. They appear as independent addresses, better for privacy than payment IDs. The Monero wallet RPC documentation confirms the effectiveness of this approach.

How to Organize Incoming Monero Payment Monitoring?

Monero uses the concept of unlocked balance — funds become available after 10 confirmations (~20 minutes at 2-minute block time). For a payment system:

def poll_payments(expected_payments: dict) -> None: """ expected_payments: {address_index: {"order_id": str, "amount_xmr": float}} """ response = requests.post(RPC_URL, auth=AUTH, json={ "jsonrpc": "2.0", "id": "0", "method": "get_transfers", "params": {"in": True, "pending": True} }) for transfer in response.json()["result"].get("in", []): addr_idx = transfer["subaddr_index"]["minor"] confirmations = transfer["confirmations"] amount_xmr = transfer["amount"] / 1e12 # 1 piconero = 1e-12 XMR if addr_idx in expected_payments: expected = expected_payments[addr_idx] if amount_xmr >= expected["amount_xmr"] * 0.99: # 1% tolerance for rounding if confirmations >= 10: mark_order_paid(expected["order_id"], amount_xmr) else: update_order_status(expected["order_id"], "pending_confirmations", confirmations) 

Ensure that after 10 confirmations funds are transferred to a cold wallet. A view-only wallet for monitoring eliminates theft risk.

How to Ensure Security with Automatic Payouts?

Store the private spend key in an isolated environment. For automatic payouts, use a separate hot wallet with a minimal balance. Keep the bulk of funds in a cold wallet, periodically sweeping manually.

A view-only wallet (public spend key + private view key) is safe to run on the monitoring server:

monero-wallet-cli --generate-from-view-key view-only-wallet \ --address <main_address> \ --viewkey <private_view_key> 

Even if the server is compromised, an attacker cannot withdraw funds. This approach reduces operational costs by approximately 40% compared to traditional payment systems.

What Is Included in the Work

  • Deployment and synchronization of monerod (full or pruned node)
  • Configuration of monero-wallet-rpc with authentication and TLS
  • Implementation of subaddress-based payment flow
  • Polling service for incoming transaction monitoring with confirmation logic
  • Sweep automation and hot/cold storage separation
  • Integration with existing payment system via webhook or callback
Stage Description Estimated Time
Requirements analysis Agree on architecture, integration scheme 1–2 days
Node deployment Install and sync monerod + wallet-rpc 2–3 days
Payment module implementation Subaddress management, polling, webhooks 3–5 days
Testing Verify payment flow, rollbacks 1–2 days
Deployment and documentation Production launch, instructions 1 day

Common Problems When Integrating Monero

People forget to account for the fee threshold: Monero uses dynamic fees, and if a client pays an amount less than expected due to network fees, the payment won't go through. Solution — specify the net receipt amount, not gross. Also, confusing subaddress with payment ID, though the latter has not been used since 2018 and exposes wallet linkage. Insufficient confirmation period — at least 10 blocks, use 30+ for large amounts. Lack of monitoring for pending transactions: under high network load, some transactions stall; a rescan mechanism is needed.

The average savings on fees when switching to Monero is about 30%, and the cost of gateway development typically pays for itself within 2–3 months. Get a consultation on implementation — discuss your architecture.

Example nginx configuration for wallet-rpc
server { listen 443 ssl; server_name payment.example.com; ssl_certificate /etc/nginx/certs/fullchain.pem; ssl_certificate_key /etc/nginx/certs/privkey.pem; location /json_rpc { proxy_pass http://127.0.0.1:18083; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } } 

Our engineers with experience in over 50 integrations guarantee stable operation of the payment gateway. Order a turnkey setup — contact us to discuss your project.