Create and manage server-side pregenerated wallets using Para’s Server SDK
For new server-side wallet creation, use the REST API instead. It covers the same use cases
(pre-created user wallets, agent wallets, server-side signing) without requiring you to store, encrypt, and restore
user shares or run an MPC ceremony per signature. This guide covers SDK-based pregeneration for existing integrations
and for flows that need direct user-share control. To move an existing integration, see
Migrate SDK pregen wallets to REST API.
Pregenerated wallets let your server create wallets before a user authenticates with Para. The flow works by creating a wallet associated with an identifier of your choice (email, phone, username, or custom ID). Para then provides you with the user share of the 2/2 MPC key, which you must securely store on your server until it’s either claimed by a user or used for signing operations.Because your server holds the user share, SDK pregeneration is the right choice only when you need that control directly — for example, signing with SDK ecosystem integrations (Ethers, Viem, Solana, CosmJS) before the wallet is claimed, or exporting key material through client flows.
The identifier can be an email or phone number, a third-party user ID (for Farcaster, Telegram, Discord, or X), or a custom ID relevant to your application. Choose an identifier that works best for your application architecture.
You must securely store this user share in your backend, associated with the user’s identifier. If this share is lost, the wallet becomes permanently inaccessible.
We strongly recommend implementing robust encryption for user shares both in transit and at rest. Consider using a high-entropy encryption key with AES-GCM encryption. Do not store encryption keys in the same database as the encrypted data.
Para offers pre-launch security reviews for teams in the Growth tier or above. Reach out to the Para team for assistance with your implementation!
When implementing setUserShare in API routes or serverless functions, it’s critical to create a new Para client instance for each request. This prevents different users’ shares from conflicting with each other. Creating a new Para client has minimal overhead and won’t impact request performance.
Once the user share is loaded, you can test the wallet functionality by signing a message. However, for production use, we recommend using the blockchain library integrations described in the next section.
Claiming pregenerated wallets must be done client-side with the Para Client SDK. The Server SDK does not support the key rotation operations required for wallet claiming.
For applications that need to transfer ownership of pregenerated wallets to users, implement a client-side claiming flow.
Your backend still prepares the stored user share for the authenticating identifier before the client receives it.
Look up the stored pregenerated wallet from the authenticating identifier
Decrypt and load the stored user share into a fresh server-side Para client
Update the pregenerated wallet identifier if it was created with a custom ID
Return the updated user share to the client
Let the client SDK load the share and claim the wallet
import { Para as ParaServer } from "@getpara/server-sdk";export async function preparePregenClaim(email: string) { const wallet = await getPregenWalletByEmail(email); const para = new ParaServer(process.env.PARA_API_KEY!); const userShare = await decryptUserShare(wallet.encryptedUserShare); await para.setUserShare(userShare); await para.updatePregenWalletIdentifier({ walletId: wallet.walletId, newPregenId: { email }, }); return { userShare: await para.getUserShare(), };}
Calling setUserShare before updatePregenWalletIdentifier lets the server SDK update the wallet metadata in the
loaded share. Return that updated share to the client so the loaded wallet identifier matches the user’s auth
identifier during claim.
For a comprehensive guide on implementing the claiming flow, refer to our web documentation: