Next lesson →

Sending Payments & Managing Outputs

Build the payout side: transfer, transfer_split and sweep_all, fees and priority, locked vs unlocked balance, change outputs, and hot/cold wallet design.

Receiving payments is only half of an integration. Sooner or later you have to send Monero back out — paying customer withdrawals on an exchange, issuing refunds, or sweeping deposits into cold storage. This lesson covers the payout side using monero-wallet-rpc: how to build and broadcast transactions, how Monero's output model affects your available balance, and how to design a sending system that is safe to run with real money and safe to retry when things go wrong.

Sending with transfer

The workhorse method is transfer. You hand it a destinations array, where each entry is an object with an address and an amount in atomic units (1 XMR = 1e12 atomic units — always work in atomic units to avoid floating-point errors). A single transfer call can pay many destinations at once, which is how you batch a round of withdrawals into one transaction.

  • priority (0–3: default, low, normal, high). A higher priority pays a higher fee so miners include your transaction sooner. For routine payouts, default or low is fine; raise it only when you need fast confirmation.
  • get_tx_key: true tells the wallet to return the transaction's secret key. Store it — you'll need it later to generate a payment proof if a recipient disputes whether you paid.

A successful transfer returns the tx_hash, the fee charged, the amount sent, and (when requested) the tx_key. When a payout has so many destinations or input outputs that it won't fit in a single transaction, the call fails with "transaction would be too large." Use transfer_split instead: it takes the same parameters but splits the payment across multiple transactions automatically, returning arrays of hashes, fees, and keys.

Sweeping balances

Sometimes you don't want to send a specific amount — you want to move everything. sweep_all sends the entire balance of an account or subaddress to a single destination address. This is the tool for consolidating scattered deposits, sweeping incoming funds to cold storage, and processing full-balance withdrawals where the customer asks for "all of it." There's also sweep_dust, which gathers up tiny leftover outputs too small to be useful on their own and consolidates them.

Outputs and change

Monero spends whole outputs (the equivalent of Bitcoin's UTXOs). You can't spend "half" an output. When you send a payment, the wallet selects one or more input outputs whose combined value covers the amount plus the fee, and the remainder comes back to you as a brand-new change output. You never manage this by hand — the wallet does coin selection for you — but it matters for two reasons: your balance is made of discrete chunks, not a single pool, and a change output you just created is itself locked before you can spend it again.

Balance versus unlocked balance

This is the single most common source of payout bugs. get_balance returns both a balance and an unlocked_balance, and only unlocked funds can be spent. Every newly received output — including the change from your own transactions — is locked for 10 blocks (roughly 20 minutes) before it becomes spendable. If you try to pay out using funds that are still locked, the wallet returns "not enough unlocked money" even though the total balance looks sufficient.

For an exchange or processor this means you cannot pay out a deposit the instant it arrives. Either wait for the unlock, or maintain a float of already-unlocked funds in the hot wallet so withdrawals can be served immediately while fresh deposits mature in the background.

Fees

You do not set the fee directly. The wallet computes it from the daemon's get_fee_estimate and the chosen priority. Critically, Monero fees are based on the transaction's weight and size, not a percentage of the amount sent. A transaction with many inputs costs more than one with few inputs, regardless of how much XMR moves. This is why consolidating outputs periodically keeps future payouts cheap, and why batching many withdrawals into one transaction is more efficient than sending them individually.

Hot and cold wallet design

Never keep an exchange's entire reserve in an online wallet. The standard architecture splits funds:

  • A hot wallet runs on monero-wallet-rpc, holds only a limited float, and signs automatic payouts.
  • The bulk of funds lives in cold storage, offline and out of reach of your servers.
  • You periodically sweep_all accumulated deposits from the hot wallet to a cold address, and refill the hot wallet from cold reserves only as needed.

If the hot wallet server is ever compromised, the attacker can only steal the small float — not the whole treasury. This is the same sweep-to-cold discipline a self-hosted store applies, scaled up to an automated system.

Building a robust payout pipeline

Real money is unforgiving, so engineer for failure:

  • Record everything. Persist the tx_hash and tx_key for every payout. The hash gives you idempotency and an audit trail; the key lets you prove payment later.
  • Make payouts idempotent. Tie each withdrawal request to a unique internal ID and check whether it already has a recorded tx_hash before sending. A retry after a timeout must never double-pay.
  • Handle the known errors. "not enough unlocked money" means wait for unlock or top up the float; "transaction would be too large" means switch to transfer_split; daemon-busy or still-syncing errors mean back off and retry rather than failing the withdrawal.
  • Confirm before marking done. A returned tx_hash means broadcast, not finality — track confirmations before treating the payout as settled.

What the wallet handles for you

You orchestrate; the wallet does the cryptography. It manages key images (so an output can't be double-spent), performs ring and decoy selection — the ring size is fixed at 16 across the network — and produces the signatures. You never touch ring members or construct signatures yourself. Your job is to decide what to send, from which account, at what priority, and to make the surrounding bookkeeping bulletproof.

Next: Building a Light Wallet

Comments

Log in or create a free account to comment.

No comments yet — be the first.

🎓 Graduate from Monero Academy

Create a free account, ace every quiz across all courses, and earn your place on the Graduates wall — with your own Monero address for donations. An account also tracks your progress through the courses, and graduating is the prize for finishing.