Building payment infrastructure for Monero requires a different architectural approach than the custodial services many developers know. When a user’s private keys never touch your servers, the responsibility for secure key management shifts entirely to the client side. This creates both a technical challenge and a genuine privacy advantage: your application cannot be forced to surrender user funds because your application has never possessed them. The integration path depends on whether you need wallet instantiation, transaction signing, or both—and understanding that distinction shapes every subsequent decision about authentication, key derivation, and state management.

The non-custodial model also changes how you handle user onboarding, recovery, and account restoration. There is no password reset flow that your backend can execute because no password is stored server-side. Users reconstruct their wallet state by providing either an encrypted wallet file with its password or a 25-word recovery seed that derives the same private keys locally. This shifts authentication from credential verification to cryptographic proof of key possession. That shift demands careful API design, because developers often expect a traditional login endpoint to validate credentials and return a session token. Instead, you will design for local key reconstruction and in-client transaction signing.

XMRWallet login interface showing wallet file and recovery seed input fields for non-custodial key reconstruction

Wallet instantiation and key derivation in the client

The first architectural decision is whether key derivation happens entirely on the client or whether some computation moves to your backend. The correct answer for a non-custodial wallet is: all of it stays on the client. When a user provides a recovery seed or encrypted wallet file, your application should reconstruct the complete key pair locally without transmitting the seed or intermediate derivation steps to any server. This protects against both server compromise and man-in-the-middle interception during login.

The recovery seed encodes entropy from which both the private view key and private spend key are deterministically derived. Monero’s wallet specification defines the key derivation process, meaning that any compatible wallet can recreate the same private keys from the same seed. This is how users can restore their wallet through XMRWallet or any other Monero software without trusting a backup or recovery service. Your integration should implement or wrap this derivation carefully. The entropy seed should never be logged, cached in unencrypted form, or transmitted across the network. After keys are derived, the seed can be discarded from memory if the user is not requesting a plaintext export.

If users want to import an encrypted wallet file instead of a seed, the file contains the private keys in encrypted form. When the user provides the file and the password, your application decrypts it locally to retrieve the raw keys. Again, the decryption happens on the client, and the decrypted keys should remain in memory only as long as needed for signing or balance checking. The encrypted file itself can be stored or transmitted safely because decryption is computationally bound to knowing the password.

For developers integrating wallet functionality, the practical implementation often wraps existing libraries. Monero’s C++ reference implementation and maintained bindings for languages like JavaScript, Python, or Go expose the key derivation logic. If you are building a web application, JavaScript libraries can handle seed reconstruction in the browser before any network communication begins. Mobile applications built on Android or iOS should use the native Monero libraries or verified bindings to avoid reimplementing cryptographic primitives. The security principle is simple: leverage tested, audited libraries rather than writing cryptographic code yourself.

Blockchain synchronization and transaction scanning

Once keys are derived, the wallet needs to scan the blockchain to find transactions belonging to the user. This is where remote node communication becomes necessary. The wallet cannot scan the entire Monero blockchain on every client device; instead, it connects to a Monero node and requests blocks. The node sees your wallet’s view key requests but cannot decrypt the transactions or determine which are relevant to your user without the private view key held only on the client.

Your integration point here is deciding how users specify their node connection. Some applications enforce a default public node operated by the developers or a trusted third party. Other applications let users specify a custom node URL, including nodes they run themselves. The security implication is that a malicious node operator can observe which block heights are requested and potentially infer transaction timing. A user running their own Monero node eliminates that observation vector but requires substantial disk space and technical knowledge. For many users, a well-chosen public node represents an acceptable trade-off between privacy and convenience.

The synchronization workflow involves fetching blocks, scanning them against the derived keys locally, and extracting matching transaction outputs. This scanning is computationally intensive and should ideally happen in the background without blocking user interaction. On mobile devices, you may want to sync only recent blocks initially and allow users to request full history scans as needed. The balance overview and transaction history are derived from this scanning process, so the accuracy of synchronization directly determines the accuracy of the displayed balance.

One practical consideration is handling the private view key during synchronization. The view key is necessary to decrypt transactions, but it does not allow spending funds. Some wallet implementations leak view key information through request patterns or IP addresses. If your application supports Tor or I2P connectivity, users can mask their network connection during synchronization. At minimum, document which communication channels expose what information so users can make informed choices about which node to trust and what privacy level to expect.

Transaction signing and submission without key export

When a user initiates a payment, your application must construct a transaction, sign it with the private spend key, and broadcast it to the network. The critical security boundary is that the private spend key never leaves the client application. You do not transmit it for signing on a backend server, and you do not store it in a way that outlives the current session.

Transaction construction involves specifying outputs (where the money goes), selecting inputs from the user’s unspent transaction outputs, and calculating fees. The selection of inputs is non-trivial because Monero uses a ring signature construction where each input is mixed with decoys. The selection algorithm affects both privacy and fee efficiency. Your integration should expose this logic to the user or make intelligent default choices. A user selecting their own inputs (UTXO coin control) gains transparency but requires more knowledge. A wallet that selects inputs automatically is more convenient but less transparent about privacy consequences.

Once the transaction is constructed, your application signs it with the private spend key, which happens entirely on the client. The signature proves that the holder of the key authorized the transaction. After signing, the transaction is ready to broadcast. At this point, your backend can receive the signed transaction and submit it to the Monero network on behalf of the user. This is safe because the signature cannot be forged and the transaction cannot be modified without invalidating the signature. Your backend never saw the private key.

One integration pattern is exposing a transaction signing API that accepts the transaction bytes and returns the signed bytes. Another pattern is integrating the entire workflow into your client application. The choice depends on whether your backend needs to store transaction history or broadcast on behalf of users with intermittent connectivity. In either case, the private spend key remains on the client, and the backend’s role is limited to read-only information and network communication.

Session management and automatic expiration

Unlike traditional web applications where sessions persist until explicit logout, a non-custodial wallet application should aggressively clean up sensitive data. A session should represent the time during which decrypted keys are held in memory. When the user closes the application or a timeout expires, the keys should be cleared from memory. This prevents a scenario where a device is left unattended and someone else accesses the wallet without the user’s knowledge.

The timeout period should be configurable by the user but default to a reasonably short interval such as five to fifteen minutes. Mobile applications should implement additional cleanup when the application enters the background. Some wallet implementations even require re-authentication when the user returns to the application after a background transition. This adds friction but significantly reduces the window during which an unattended device exposes active keys.

For web-based integrations, browser security features like sessionStorage and localStorage present a trade-off. Storing encrypted wallet data in localStorage persists across page refreshes and can improve user experience. However, any JavaScript code running in the page context can access localStorage, so malicious scripts injected through a compromised dependency or supply-chain attack could exfiltrate encrypted data. One defensive approach is to store only encrypted wallet files locally and require the user to provide the password on each login, accepting the friction to avoid persistent decrypted keys.

Another session consideration is how to handle multiple devices. A user with the same recovery seed can restore the wallet on multiple devices, and each device independently synchronizes with the blockchain. However, there is no server-side sync mechanism to keep balances or transaction histories aligned across devices. This is a direct consequence of the non-custodial architecture: there is no central record to synchronize against. Users should understand that they may need to rescan or wait for synchronization on each device independently, and that the true balance is determined by the blockchain itself, not by what any single device claims.

API design for third-party integrations

If you are building a platform that allows third-party applications to integrate with your non-custodial wallet, your API surface should enforce the principle that third parties never access private keys. This means designing endpoints that let applications request wallet information or initiate transactions without providing raw key material.

A read-only API might expose endpoints for checking balance, fetching transaction history, and deriving public addresses. These operations need only the public view key or the private view key, neither of which permits spending. A third-party application can query balance or confirm received payments without any spending capability. The API should clearly document these boundaries so developers do not mistakenly assume they can authorize payments from external applications.

For transaction initiation, one pattern is a request-signing flow where the third-party application submits a transaction request, your wallet application displays it to the user, and the user explicitly approves the transaction within your application context. The approval triggers local signing, and the signed transaction is returned to the third party. This prevents a third-party application from spending funds without explicit user consent presented in the wallet interface where users expect to make financial decisions.

Version your API carefully and document changes extensively. Non-custodial wallets often serve users in jurisdictions where the wallet software itself is the only technical support available. When you change an API endpoint or response format, old client versions may break without clear error messages. Providing a deprecation period where old and new endpoints coexist, publishing migration guides, and testing client compatibility before cutting off old versions reduces frustration and potential loss of access to funds.

Testing and verification in development

Because private keys and user funds are at stake, testing a non-custodial wallet integration requires more care than typical application development. Use Monero testnet for initial development. Testnet XMR has no financial value and allows you to test the complete workflow without risk. Create test wallets, send transactions, verify synchronization, and confirm balance calculations entirely on testnet before touching mainnet.

Implement comprehensive logging of key operations without logging sensitive data. Record that a wallet was instantiated, that synchronization occurred, and that a transaction was signed, but do not log the actual keys, seeds, or unencrypted transaction contents. This preserves a debugging trail while protecting user privacy.

Test recovery paths explicitly. Create a wallet, export the recovery seed, delete all wallet state, recreate the wallet from the seed, and verify that the restored wallet arrives at the same balance and transaction history. Test backup and restore of encrypted wallet files. Test session expiration and re-authentication. Test the behavior when the network connection is lost during synchronization or transaction submission. These edge cases reveal gaps in your implementation before they affect users.

For API integrations, publish API documentation with working code examples. Developers integrating your wallet API may be unfamiliar with Monero’s privacy model or cryptographic construction. Clear examples showing how to request a balance, how to initiate a payment, and how to handle the response reduce integration errors. Include error codes and their meanings so third-party developers can debug integration issues without contacting support for every failure.

Documentation and user education

The technical excellence of a non-custodial wallet means nothing if users lose their recovery seed or fall for phishing that harvests their password. Your integration should include prominent, clear documentation about security practices. Advise users never to share their recovery seed or enter it into websites, applications, or support forms. Explain that there is no password reset if they forget their password, because there is no way to recover an unremembered password from a non-custodial system. This is not a limitation you can engineer away; it is fundamental to the architecture.

Document the privacy properties and limitations of your implementation. Explain which third parties can observe what information. If you operate a public node, describe its logging and retention policies. If users can specify a custom node, explain that the node operator can observe their request patterns. If you support Tor, explain how to enable it and what additional latency to expect. Users can then make informed decisions about which features to use based on their threat model.

Provide clear guidance on wallet backups. Explain the difference between a recovery seed (which should be written down and stored securely offline) and the wallet file (which can be backed up digitally but should be encrypted). Give users step-by-step instructions for testing their backups on testnet before relying on them. Describe what information a backup contains and what it does not contain (it does not contain transaction history, which can always be rescanned from the blockchain).

Finally, document the release notes and changelog extensively. When you update the wallet software, publish what changed, why it changed, and whether any action is required from users. Breaking changes to key derivation or blockchain scanning should be clearly highlighted because they affect wallet restoration and recovery.

Frequently asked questions

Can I store Monero private keys on my backend server if I encrypt them?

No. Storing encrypted private keys on your backend defeats the core security property of a non-custodial wallet. Even encrypted, they represent centralized assets you control. If your backend is compromised and decrypted, user funds are at risk. The non-custodial architecture requires that private keys remain under the user’s control exclusively, usually on their local device.

What happens if a user forgets their wallet password in a non-custodial system?

If the user loses the wallet file and forgets the password, recovery is impossible. This is why wallet documentation must emphasize backing up the recovery seed separately. If the user has the recovery seed, they can recreate the wallet with a new password. If they have neither the file nor the seed, the funds are effectively inaccessible, though they still exist on the blockchain and could theoretically be recovered if the seed is later found.

How do I prevent users from exposing their recovery seed when importing a wallet?

Ensure your application accepts the seed only through a secure input field, never from a URL parameter, query string, or browser history. After the seed is processed and keys are derived, clear it from memory and do not display it back to the user unless they explicitly request an export. Use in-app warnings and education to teach users that legitimate wallet applications never ask for seeds through external channels.

Leave a Reply

Your email address will not be published. Required fields are marked *

×