# Para > Non-custodial embedded wallet infrastructure using MPC for building embedded wallet integrations across web, mobile, and server platforms supporting EVM, Solana, and Cosmos chains. ## Para SDK Implementation Supplement > Concrete build-time details: packages, initialization, authentication, signing, connectors, account abstraction, and configuration for building Para integrations. ## 1. SDK Package Matrix All `@getpara/*` packages must use the **same version** as each other. Always pin every `@getpara/*` dependency to the same release to avoid mismatches. ### Core SDKs | Package | Use When | |---------|----------| | `@getpara/react-sdk` | React/Next.js apps with ParaProvider + hooks + ParaModal | | `@getpara/react-sdk-lite` | React apps using Para only through a connector (Wagmi/Graz) - lighter bundle, exports `ParaWeb` | | `@getpara/web-sdk` | Non-React web frameworks (Vue, Svelte) - exports `ParaWeb` imperative class | | `@getpara/server-sdk` | Node.js/Bun/Deno server-side - exports `Para` (aliased as `ParaServer`) | | `@getpara/react-native-wallet` | React Native / Expo mobile apps | ### Signing Integration Packages | Package | Web3 Library | Companion Deps | |---------|-------------|----------------| | `@getpara/viem-v2-integration` | Viem 2.x | `viem@^2.27.0` | | `@getpara/ethers-v6-integration` | Ethers 6.x | `ethers@^6.13.0` | | `@getpara/ethers-v5-integration` | Ethers 5.x | `ethers@^5.8.0` | | `@getpara/solana-web3.js-v1-integration` | Solana Web3.js 1.x | `@solana/web3.js@^1.98.0` | | `@getpara/solana-signers-v2-integration` | Solana Signers 2.x | `@solana/web3.js@^1.98.0` | | `@getpara/cosmjs-v0-integration` | CosmJS 0.34+ | `@cosmjs/stargate@^0.34.0`, `@cosmjs/proto-signing@^0.34.0` | ### Connector Packages | Package | Connector Ecosystem | Companion Deps | |---------|-------------------|----------------| | `@getpara/wagmi-v2-integration` | Wagmi 2.x / 3.x | `wagmi@^2.15.0`, `viem@^2.27.0`, `@tanstack/react-query@^5.0.0` | | `@getpara/rainbowkit-wallet` | RainbowKit | `@rainbow-me/rainbowkit@^2.0.0`, `wagmi`, `viem` | | `@getpara/graz-integration` | Graz (Cosmos) | `graz@^0.4.1` | ### External Wallet Connector Packages | Package | Purpose | |---------|---------| | `@getpara/evm-wallet-connectors` | EVM external wallet connections | | `@getpara/solana-wallet-connectors` | Solana external wallet connections | | `@getpara/cosmos-wallet-connectors` | Cosmos external wallet connections | ### Account Abstraction Companion Deps | AA Provider | Key Packages | |------------|-------------| | Alchemy (ERC-4337) | `@aa-sdk/core`, `@account-kit/infra`, `@account-kit/smart-contracts` | | Alchemy (EIP-7702) | Same as above, uses `createModularAccountV2Client` with `mode: "7702"` | | ZeroDev (ERC-4337) | `@zerodev/sdk`, `@zerodev/ecdsa-validator` | | ZeroDev (EIP-7702) | Same packages, uses `create7702KernelAccount` + `KERNEL_V3_3` | | Gelato | `@gelatonetwork/smartwallet` | | Thirdweb | `thirdweb` | | Rhinestone | `@rhinestone/sdk` | | Porto | `porto` | ### Required Companion Dependency All React examples require: ``` @tanstack/react-query@^5.0.0 ``` --- ## 2. Initialization Patterns ### React / Next.js (ParaProvider) ```tsx // src/components/ParaProvider.tsx "use client"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { Environment, ParaProvider as ParaSDKProvider } from "@getpara/react-sdk"; const API_KEY = process.env.NEXT_PUBLIC_PARA_API_KEY ?? ""; const ENVIRONMENT = (process.env.NEXT_PUBLIC_PARA_ENVIRONMENT as Environment) || Environment.BETA; if (!API_KEY) { throw new Error("API key is not defined. Please set NEXT_PUBLIC_PARA_API_KEY in your environment variables."); } const queryClient = new QueryClient(); export function ParaProvider({ children }: { children: React.ReactNode }) { return ( {children} ); } ``` The `config` prop accepts: ```ts interface ParaProviderConfig { appName: string; // required disableAutoSessionKeepAlive?: boolean; // disable automatic session refresh disableEmbeddedModal?: boolean; // set true only when rendering your own ParaModal rpcUrl?: string; farcasterMiniAppConfig?: FarcasterMiniAppConfig; } ``` Wrap your app root (e.g., `layout.tsx`): ```tsx import { ParaProvider } from "@/components/ParaProvider"; export default function RootLayout({ children }) { return {children}; } ``` `ParaProvider` also accepts an optional `callbacks` prop for event handling: ```ts type Callbacks = { onLogout?: (event) => void; onLogin?: (event) => void; onAccountSetup?: (event) => void; onAccountCreation?: (event) => void; onSignMessage?: (event) => void; onSignTransaction?: (event) => void; onWalletsChange?: (event) => void; onWalletCreated?: (event) => void; onPregenWalletClaimed?: (event) => void; }; ``` ### Vue / Svelte (ParaWeb - imperative) ```ts // src/lib/para.ts import { Environment, ParaWeb } from "@getpara/web-sdk"; const API_KEY = import.meta.env.VITE_PARA_API_KEY; const ENVIRONMENT = (import.meta.env.VITE_PARA_ENVIRONMENT as Environment) || Environment.BETA; if (!API_KEY) { throw new Error("API key is not defined. Please set VITE_PARA_API_KEY in your environment variables."); } export const para = new ParaWeb(ENVIRONMENT, API_KEY); ``` ### Server (ParaServer) ```ts import { Para as ParaServer, Environment } from "@getpara/server-sdk"; const PARA_API_KEY = process.env.PARA_API_KEY; const PARA_ENVIRONMENT = (process.env.PARA_ENVIRONMENT as Environment) || Environment.BETA; const para = new ParaServer(PARA_ENVIRONMENT, PARA_API_KEY); ``` ### React Native / Expo (ParaMobile) ```ts import ParaMobile, { Environment } from "@getpara/react-native-wallet"; const para = new ParaMobile( Environment.BETA, process.env.EXPO_PUBLIC_PARA_API_KEY, undefined, { disableWorkers: true } ); ``` The `{ disableWorkers: true }` option is **required** for React Native because Web Workers are not available. ### Chrome Extension (storage overrides) ```ts import { ParaWeb } from "@getpara/react-sdk"; import { chromeStorageOverrides } from "../chrome-storage"; export const para = new ParaWeb(ENVIRONMENT, API_KEY, { ...chromeStorageOverrides, useStorageOverrides: true, }); // Shared init promise - await in any script that needs Para export const paraReady = para.init(); ``` The `chromeStorageOverrides` object maps `chrome.storage.local` / `chrome.storage.session` to replace `localStorage` / `sessionStorage` which are not available in extension service workers. See `examples-hub/web/with-chrome-extension/src/lib/chrome-storage.ts` for the full implementation. --- ## 3. REST API — Default for Server-Side Wallets **When a backend needs to create wallets or sign on behalf of users (pre-created wallets, agent wallets, automated signing), use the REST API.** It is the recommended path for nearly all server-side integrations: no SDK to install, no user share to store or encrypt, no MPC ceremony to run per signature. Para's enclave holds the key material; your server holds only an API key. Only fall back to SDK-based pregeneration when the flow requires direct user-share control (see Section 7). For typed TypeScript access, use `@getpara/rest-sdk`. Otherwise call the HTTP API from any language. ### Base URLs | Environment | URL | |------------|-----| | Beta | `https://api.beta.getpara.com` | | Production | `https://api.getpara.com` | ### Authentication Header ``` X-API-Key: your_api_key X-Request-Id: # optional, for request tracing Content-Type: application/json ``` ### Endpoints ``` POST /v1/wallets - Create wallet GET /v1/wallets/{walletId} - Get wallet details POST /v1/wallets/{walletId}/sign-raw - Sign raw bytes (0x-prefixed hex) ``` The API also has `sign-transaction`, `sign-message`, `sign-typed-data`, `sign-authorization`, `transfer`, `balance`, `transactions`, and `estimate-fee` endpoints under `/v1/wallets/{walletId}/`. Full spec: https://docs.getpara.com/openapi.yaml ### Create Wallet Request ```json { "type": "EVM", "userIdentifier": "alice@example.com", "userIdentifierType": "EMAIL", "scheme": "DKLS" } ``` - `type`: `"EVM"` | `"SOLANA"` | `"COSMOS"` | `"STELLAR"` - `userIdentifierType`: `"EMAIL"` | `"PHONE"` | `"CUSTOM_ID"` | `"GUEST_ID"` | `"TELEGRAM"` | `"DISCORD"` | `"TWITTER"` | `"FARCASTER"` - `scheme`: `"DKLS"` | `"CGGMP"` | `"ED25519"` (optional, defaults based on wallet type) - `cosmosPrefix`: string (optional, for Cosmos wallets) ### Sign Raw Request ```json { "data": "0xdeadbeef..." } ``` ### Error Codes | Code | Meaning | |------|---------| | 201 | Created | | 200 | Success | | 400 | Bad request (invalid params) | | 401 | Unauthorized (invalid API key) | | 404 | Not found | | 409 | Conflict (wallet already exists) | | 429 | Rate limited | | 500 | Server error | ### Example Node.js client ```ts const PARA_API_KEY = process.env.PARA_API_KEY; const BASE_URL = process.env.PARA_REST_BASE_URL ?? "https://api.beta.getpara.com"; async function callPara(path: string, options: { method?: string; body?: unknown } = {}): Promise { const { method = "GET", body } = options; const headers: Record = { "X-API-Key": PARA_API_KEY, "X-Request-Id": crypto.randomUUID(), }; if (body) headers["Content-Type"] = "application/json"; const res = await fetch(`${BASE_URL}${path}`, { method, headers, body: body ? JSON.stringify(body) : undefined, }); const data = await res.json(); if (!res.ok) throw new Error(`Para ${res.status}: ${JSON.stringify(data)}`); return data as T; } ``` ### Wallet Claiming Wallets created over REST are claimable the same way as SDK pregen wallets: when a user signs up through the client SDK with the same identifier (e.g., the same email), the wallet transfers to their account automatically. No server-side action is required. --- ## 4. Environment Variables ### Naming Conventions by Framework | Framework | Prefix | Example | |-----------|--------|---------| | Next.js (client) | `NEXT_PUBLIC_` | `NEXT_PUBLIC_PARA_API_KEY` | | Next.js (server) | none | `PARA_API_KEY` | | Vite (Vue/Svelte) | `VITE_` | `VITE_PARA_API_KEY` | | Expo | `EXPO_PUBLIC_` | `EXPO_PUBLIC_PARA_API_KEY` | | Node.js server | none | `PARA_API_KEY` | ### Common Variables ```env # Required - Para PARA_API_KEY=your_api_key PARA_ENVIRONMENT=BETA # or PRODUCTION # Client-side variants (pick one based on framework) NEXT_PUBLIC_PARA_API_KEY=your_api_key NEXT_PUBLIC_PARA_ENVIRONMENT=BETA VITE_PARA_API_KEY=your_api_key VITE_PARA_ENVIRONMENT=BETA EXPO_PUBLIC_PARA_API_KEY=your_api_key # Server-side pregen encryption ENCRYPTION_KEY=a_32_byte_string_exactly_this_l # Must be exactly 32 bytes # Account Abstraction ALCHEMY_API_KEY=your_alchemy_key ALCHEMY_GAS_POLICY_ID=your_policy_id ALCHEMY_RPC_URL=https://arb-sepolia.g.alchemy.com/v2/your_key ZERODEV_PROJECT_ID=your_zerodev_project_id ZERODEV_BUNDLER_RPC=https://rpc.zerodev.app/api/v2/bundler/... ZERODEV_PAYMASTER_RPC=https://rpc.zerodev.app/api/v2/paymaster/... ZERODEV_ARBITRUM_SEPOLIA_RPC=https://rpc.zerodev.app/api/v2/rpc/... # REST API PARA_REST_BASE_URL=https://api.beta.getpara.com # or https://api.getpara.com ``` --- ## 5. Authentication Flows ### Email Auth (React hooks pattern) ```tsx import { useSignUpOrLogIn, useWaitForLogin, useWaitForWalletCreation, type AuthStateVerify, } from "@getpara/react-sdk"; // In your hook/component: const { signUpOrLogIn, isPending: isSigningUp } = useSignUpOrLogIn(); const { waitForLogin, isPending: isWaitingForLogin } = useWaitForLogin(); const { waitForWalletCreation, isPending: isWaitingForWallet } = useWaitForWalletCreation(); const shouldCancel = useRef(false); // Step 1: Submit email signUpOrLogIn( { auth: { email } }, { onSuccess: (authState) => { if (authState?.stage === "verify") { const verifyState = authState as AuthStateVerify; // verifyState.loginUrl -> open in iframe or popup for passkey verification // verifyState.nextStage -> "signup" (new user) or "login" (returning user) const isNewUser = verifyState.nextStage === "signup"; handleAuthComplete(isNewUser); } }, onError: (err) => { /* handle error */ }, } ); // Step 2: Wait for auth completion function handleAuthComplete(isNewUser: boolean) { if (isNewUser) { waitForWalletCreation( { isCanceled: () => shouldCancel.current }, { onSuccess: () => { /* user is logged in with wallet */ } } ); } else { waitForLogin( { isCanceled: () => shouldCancel.current }, { onSuccess: () => { /* user is logged in */ } } ); } } ``` The `loginUrl` from Step 1 must be displayed to the user in an iframe or popup - it's the passkey verification page hosted by Para. ### Email Auth (Imperative / Svelte / Vue) ```ts import { para } from "@/lib/para"; // Step 1: Submit email const authState = await para.signUpOrLogIn({ auth: { email } }); if (authState.stage === "verify" && authState.loginUrl) { const isNewUser = authState.nextStage === "signup"; // Show authState.loginUrl to user in iframe/popup // Step 2: Wait for completion if (isNewUser) { await para.waitForWalletCreation({ isCanceled: () => shouldCancel }); } else { const result = await para.waitForLogin({ isCanceled: () => shouldCancel }); if (result.needsWallet) { await para.waitForWalletCreation({ isCanceled: () => shouldCancel }); } } } ``` ### OAuth Auth (React hooks) ```tsx import { useVerifyOAuth, useVerifyFarcaster, useWaitForLogin, useWaitForWalletCreation, type TOAuthMethod, } from "@getpara/react-sdk"; const { verifyOAuth } = useVerifyOAuth(); const { verifyFarcaster } = useVerifyFarcaster(); // Standard OAuth (Google, Apple, Discord, Facebook, Twitter) verifyOAuth( { method: "GOOGLE", // TOAuthMethod excluding "TELEGRAM" | "FARCASTER" onOAuthUrl: (url) => { window.open(url, "oauth", "popup=true"); }, isCanceled: () => shouldCancel.current || !!popupWindow.current?.closed, }, { onSuccess: (authState) => { if (authState.stage === "done") { handleAuthComplete(authState.isNewUser); } }, } ); // Farcaster verifyFarcaster( { onConnectUri: (uri) => { window.open(uri, "farcaster", "popup=true"); }, isCanceled: () => shouldCancel.current || !!popupWindow.current?.closed, }, { onSuccess: (authState) => { if (authState.stage === "done") { handleAuthComplete(authState.isNewUser); } }, } ); ``` ### Verify iframe listener When showing the `loginUrl` in an iframe, listen for the close message: ```ts useEffect(() => { const portalBase = "https://app.beta.getpara.com"; // or https://app.getpara.com const handleMessage = (event: MessageEvent) => { if (!event.origin.startsWith(portalBase)) return; if (event.data?.type === "CLOSE_WINDOW" && event.data.success) { setVerifyUrl(null); } }; window.addEventListener("message", handleMessage); return () => window.removeEventListener("message", handleMessage); }, []); ``` --- ## 6. Signing Integration Code ### Viem v2 ```ts import { createParaAccount, createParaViemClient } from "@getpara/viem-v2-integration"; import { http, parseEther, parseGwei } from "viem"; import { sepolia } from "viem/chains"; // From client (using useClient hook): import { useClient } from "@getpara/react-sdk"; const client = useClient(); // returns the Para client instance // Create account + client const viemParaAccount = createParaAccount(para); // para = ParaServer or client const viemClient = createParaViemClient(para, { account: viemParaAccount, chain: sepolia, transport: http("https://ethereum-sepolia-rpc.publicnode.com"), }); // Sign transaction const request = await viemClient.prepareTransactionRequest({ account: viemParaAccount, to: "0x...", value: parseEther("0.0001"), gas: BigInt(21000), maxFeePerGas: parseGwei("20"), maxPriorityFeePerGas: parseGwei("3"), chain: sepolia, }); const signedTx = await viemClient.signTransaction(request); ``` ### Ethers v6 ```ts import { ParaEthersSigner } from "@getpara/ethers-v6-integration"; import { ethers } from "ethers"; const provider = new ethers.JsonRpcProvider("https://ethereum-sepolia-rpc.publicnode.com"); const signer = new ParaEthersSigner(para, provider as ethers.Provider); const address = await signer.getAddress(); const tx = { to: address, value: ethers.parseEther("0.0001"), nonce: await provider.getTransactionCount(address), gasLimit: 21000, gasPrice: (await provider.getFeeData()).gasPrice, }; await signer.signTransaction(tx); ``` ### Ethers v5 ```ts import { ParaEthersV5Signer } from "@getpara/ethers-v5-integration"; import { ethers } from "ethers"; const provider = new ethers.providers.JsonRpcProvider(RPC_URL); const signer = new ParaEthersV5Signer(client, provider); // client from useClient() await signer.signMessage("Hello, Para!"); await signer.sendTransaction(tx); ``` ### Solana Web3.js v1 ```ts import { ParaSolanaWeb3Signer } from "@getpara/solana-web3.js-v1-integration"; import { Connection, Transaction, SystemProgram, LAMPORTS_PER_SOL } from "@solana/web3.js"; const connection = new Connection("https://api.testnet.solana.com"); const signer = new ParaSolanaWeb3Signer(para, connection); const { blockhash } = await connection.getLatestBlockhash(); const tx = new Transaction(); tx.recentBlockhash = blockhash; tx.feePayer = signer.sender; // PublicKey from Para wallet tx.add( SystemProgram.transfer({ fromPubkey: signer.sender, toPubkey: signer.sender, lamports: LAMPORTS_PER_SOL / 1000, }) ); await signer.signTransaction(tx); ``` ### CosmJS ```ts import { ParaProtoSigner } from "@getpara/cosmjs-v0-integration"; import { SigningStargateClient } from "@cosmjs/stargate"; const signer = new ParaProtoSigner(para, "cosmos"); // second arg is bech32 prefix const stargateClient = await SigningStargateClient.connectWithSigner( "https://rpc-rs.cosmos.nodestake.top/", signer ); const fee = { amount: [{ denom: "uatom", amount: "500" }], gas: "200000" }; await stargateClient.sign( signer.address, [{ typeUrl: "/cosmos.bank.v1beta1.MsgSend", value: { fromAddress: signer.address, toAddress: "cosmos1...", amount: [{ denom: "uatom", amount: "1000" }] } }], fee, "Signed with Para" ); ``` --- ## 7. Advanced: SDK Wallet Pregeneration **Most server integrations should use the REST API (Section 3) instead of this section.** SDK pregeneration requires you to store, encrypt, and restore the wallet's user share yourself, and to run an MPC ceremony for every signature. Use it only when the flow needs direct user-share control — for example, signing with SDK ecosystem integrations (ethers, viem, @solana/web3.js adapters) before the wallet is claimed. Existing SDK pregen integrations can move over: https://docs.getpara.com/v3/rest/migrate-from-sdk-pregen ### Create pre-generated wallet ```ts import { Para as ParaServer, Environment } from "@getpara/server-sdk"; import { encrypt } from "./encryption-utils"; import { setKeyShareInDB } from "./keySharesDB"; const para = new ParaServer(PARA_ENVIRONMENT, PARA_API_KEY); // Check if wallet already exists const walletExists = await para.hasPregenWallet({ pregenId: { email } }); // Create wallets for all chain types const wallets = await para.createPregenWalletPerType({ types: ["EVM", "SOLANA", "COSMOS"], pregenId: { email }, }); // Get and encrypt the user share const keyShare = para.getUserShare(); const encryptedKeyShare = await encrypt(keyShare); await setKeyShareInDB(email, encryptedKeyShare); ``` ### Restore user share for signing ```ts const keyShare = await getKeyShareInDB(email); const decryptedKeyShare = await decrypt(keyShare); await para.setUserShare(decryptedKeyShare); // Now para is ready for signing with any integration ``` ### AES-GCM Encryption Pattern ```ts // encryption-utils.ts const ALGORITHM = "AES-GCM"; const IV_LENGTH = 12; // ENCRYPTION_KEY env var must be exactly 32 bytes async function importSecretKey(keyString: string): Promise { const keyBuffer = Buffer.from(keyString, "utf-8"); return await crypto.subtle.importKey("raw", keyBuffer, { name: ALGORITHM }, false, ["encrypt", "decrypt"]); } export async function encrypt(text: string): Promise { const cryptoKey = await importSecretKey(process.env.ENCRYPTION_KEY); const iv = crypto.getRandomValues(new Uint8Array(IV_LENGTH)); const encoded = new TextEncoder().encode(text); const encrypted = await crypto.subtle.encrypt({ name: ALGORITHM, iv }, cryptoKey, encoded); return `${Buffer.from(iv).toString("base64")}:${Buffer.from(encrypted).toString("base64")}`; } export async function decrypt(encryptedText: string): Promise { const [ivBase64, dataBase64] = encryptedText.split(":"); const iv = new Uint8Array(Buffer.from(ivBase64, "base64")); const data = Buffer.from(dataBase64, "base64"); const cryptoKey = await importSecretKey(process.env.ENCRYPTION_KEY); const decrypted = await crypto.subtle.decrypt({ name: ALGORITHM, iv }, cryptoKey, data); return new TextDecoder().decode(decrypted); } ``` ### SQLite Storage Schema ```ts // keySharesDB.ts - uses `sqlite` + `sqlite3` packages import { open } from "sqlite"; import sqlite3 from "sqlite3"; const db = await open({ filename: "keyShares.db", driver: sqlite3.Database }); await db.exec(` CREATE TABLE IF NOT EXISTS keyShares ( email TEXT PRIMARY KEY NOT NULL, keyShare TEXT NOT NULL ) `); // Get const row = await db.get("SELECT keyShare FROM keyShares WHERE email = ?", [email]); // Upsert await db.run( "INSERT INTO keyShares (email, keyShare) VALUES (?, ?) ON CONFLICT(email) DO UPDATE SET keyShare = excluded.keyShare", [email, encryptedKeyShare] ); ``` --- ## 8. Account Abstraction Patterns ### Alchemy ERC-4337 ```ts import { alchemy, arbitrumSepolia } from "@account-kit/infra"; import { WalletClientSigner } from "@aa-sdk/core"; import { createModularAccountAlchemyClient } from "@account-kit/smart-contracts"; import { createParaAccount, createParaViemClient } from "@getpara/viem-v2-integration"; const viemParaAccount = createParaAccount(para); const viemClient = createParaViemClient(para, { account: viemParaAccount, chain: arbitrumSepolia, transport: http(ALCHEMY_RPC_URL), }); const walletClientSigner = new WalletClientSigner(viemClient, "para"); const alchemyClient = await createModularAccountAlchemyClient({ transport: alchemy({ rpcUrl: ALCHEMY_RPC_URL }), chain: arbitrumSepolia, signer: walletClientSigner, policyId: ALCHEMY_GAS_POLICY_ID, }); const result = await alchemyClient.sendUserOperation({ uo: batchCalls }); await alchemyClient.waitForUserOperationTransaction(result); ``` ### Alchemy EIP-7702 ```ts import { createModularAccountV2Client } from "@account-kit/smart-contracts"; import { createParaAccount } from "@getpara/viem-v2-integration"; import type { SmartAccountSigner, LocalAccount } from "@aa-sdk/core"; const viemParaAccount = createParaAccount(para); // Wrap as SmartAccountSigner const paraSigner: SmartAccountSigner = { signerType: "para", inner: viemParaAccount, getAddress: async () => viemParaAccount.address, signMessage: async (message) => viemParaAccount.signMessage({ message }), signTypedData: async (typedData) => viemParaAccount.signTypedData(typedData), signAuthorization: async (auth) => viemParaAccount.signAuthorization(auth), }; const alchemyClient = await createModularAccountV2Client({ mode: "7702", transport: alchemy({ rpcUrl: ALCHEMY_RPC_URL }), chain: arbitrumSepolia, signer: paraSigner, policyId: ALCHEMY_GAS_POLICY_ID, }); ``` ### ZeroDev ERC-4337 ```ts import { signerToEcdsaValidator } from "@zerodev/ecdsa-validator"; import { createKernelAccount, createKernelAccountClient, createZeroDevPaymasterClient } from "@zerodev/sdk"; import { getEntryPoint, KERNEL_V3_1 } from "@zerodev/sdk/constants"; const viemParaAccount = createParaAccount(para); const viemClient = createParaViemClient(para, { account: viemParaAccount, chain: arbitrumSepolia, transport: http(ZERODEV_RPC_URL) }); const publicClient = createPublicClient({ chain: arbitrumSepolia, transport: http(ZERODEV_RPC_URL) }); const entryPoint = getEntryPoint("0.7"); const ecdsaValidator = await signerToEcdsaValidator(viemClient, { signer: viemParaAccount, entryPoint, kernelVersion: KERNEL_V3_1, }); const kernelAccount = await createKernelAccount(publicClient, { plugins: { sudo: ecdsaValidator }, entryPoint, kernelVersion: KERNEL_V3_1, }); const kernelClient = createKernelAccountClient({ account: kernelAccount, chain: arbitrumSepolia, bundlerTransport: http(ZERODEV_BUNDLER_RPC), paymaster: { getPaymasterData: (userOp) => createZeroDevPaymasterClient({ chain: arbitrumSepolia, transport: http(ZERODEV_PAYMASTER_RPC) }) .sponsorUserOperation({ userOperation: userOp }), }, }); const hash = await kernelClient.sendUserOperation({ callData: await kernelClient.account.encodeCalls(calls) }); await kernelClient.waitForUserOperationReceipt({ hash, timeout: 30000 }); ``` ### ZeroDev EIP-7702 ```ts import { create7702KernelAccount, create7702KernelAccountClient } from "@zerodev/ecdsa-validator"; import { KERNEL_V3_3 } from "@zerodev/sdk/constants"; const kernelAccount = await create7702KernelAccount(publicClient, { signer: viemParaAccount, entryPoint: getEntryPoint("0.7"), kernelVersion: KERNEL_V3_3, }); const kernelClient = create7702KernelAccountClient({ account: kernelAccount, chain: arbitrumSepolia, bundlerTransport: http(ZERODEV_BUNDLER_RPC), paymaster: createZeroDevPaymasterClient({ chain: arbitrumSepolia, transport: http(ZERODEV_PAYMASTER_RPC) }), client: publicClient, }); const hash = await kernelClient.sendUserOperation({ calls }); ``` ### Gelato ERC-4337 ```ts import { accounts, createGelatoSmartWalletClient } from "@gelatonetwork/smartwallet"; const viemParaAccount = createParaAccount(para); const viemClient = createParaViemClient(para, { account: viemParaAccount, chain: sepolia, transport: http() }); const account = await accounts.kernel({ eip7702: false, signer: viemClient }); const gelatoClient = createGelatoSmartWalletClient({ account, apiKey: GELATO_API_KEY }); const result = await gelatoClient.execute({ payment: { type: "sponsored" }, calls: [{ to: "0x...", value: 0n, data: "0x" }], }); await result.wait(); ``` ### Gelato EIP-7702 ```ts import { gelato } from "@gelatonetwork/smartwallet/accounts"; import { createGelatoSmartWalletClient } from "@gelatonetwork/smartwallet"; const account = await gelato({ signer: viemClient }); // Different subpath from 4337's accounts.kernel() const gelatoClient = createGelatoSmartWalletClient({ account, apiKey: GELATO_API_KEY }); // Same execute pattern as 4337 ``` ### Thirdweb ERC-4337 ```ts import { createThirdwebClient, sendTransaction, prepareTransaction } from "thirdweb"; import { viemAdapter, smartWallet } from "thirdweb/wallets"; import { sepolia } from "thirdweb/chains"; const thirdwebClient = createThirdwebClient({ clientId: THIRDWEB_CLIENT_ID }); const personalAccount = viemAdapter.walletClient.fromViem({ walletClient: viemClient }); const wallet = smartWallet({ chain: sepolia, sponsorGas: true }); const smartAccount = await wallet.connect({ client: thirdwebClient, personalAccount }); const tx = prepareTransaction({ to: "0x...", value: 0n, chain: sepolia, client: thirdwebClient }); await sendTransaction({ account: smartAccount, transaction: tx }); ``` ### Porto EIP-7702 Porto operates on Base Sepolia with a unique EOA-to-smart-account upgrade flow. See `examples-hub/web/with-react-nextjs/aa-porto-7702/` for the full implementation using `Account.from()`, `Key.createSecp256k1()`, and `RelayActions.prepareUpgradeAccount()`. ### Rhinestone ERC-4337 Rhinestone provides cross-chain account abstraction using `@rhinestone/sdk`. See `examples-hub/web/with-react-nextjs/aa-rhinestone-4337/` for cross-chain USDC transfers (Arbitrum->Base) with sponsored transactions. --- ## 9. Connector Integrations ### Wagmi Connector ```ts // src/config/wagmi.ts import { paraConnector } from "@getpara/wagmi-v2-integration"; import { ParaWeb } from "@getpara/react-sdk-lite"; // or @getpara/react-sdk import { createConfig, http, cookieStorage, createStorage } from "wagmi"; import { sepolia } from "wagmi/chains"; // Initialize ParaWeb (not ParaProvider - connector manages its own UI) const para = new ParaWeb(Environment.BETA, API_KEY); const connector = paraConnector({ para, appName: "My App", chains: [sepolia], queryClient, authLayout: ["AUTH:FULL", "EXTERNAL:FULL"], oAuthMethods: ["APPLE", "DISCORD", "FACEBOOK", "FARCASTER", "GOOGLE", "TWITTER"], disableEmailLogin: false, disablePhoneLogin: false, logo: "/logo.svg", onRampTestMode: true, recoverySecretStepEnabled: true, twoFactorAuthEnabled: false, theme: { foregroundColor: "#222222", backgroundColor: "#FFFFFF", accentColor: "#888888", mode: "light", borderRadius: "none", font: "Inter", }, }); export const wagmiConfig = createConfig({ chains: [sepolia], connectors: [connector, injected(), metaMask(), coinbaseWallet()], ssr: true, storage: createStorage({ storage: cookieStorage }), transports: { [sepolia.id]: http(RPC_URL) }, }); ``` Important: The Wagmi connector uses `@getpara/react-sdk-lite` (not the full `@getpara/react-sdk`) to avoid bundle bloat, since the connector provides its own modal. ### RainbowKit ```ts // src/client/wagmi.ts import { getParaWallet } from "@getpara/rainbowkit-wallet"; import { connectorsForWallets } from "@rainbow-me/rainbowkit"; import { createConfig, http } from "wagmi"; import { sepolia } from "wagmi/chains"; const paraWallet = getParaWallet({ para, // ParaWeb instance chains: [sepolia], appName: "My App", // Same modal config options as paraConnector: oAuthMethods, theme, etc. }); const connectors = connectorsForWallets( [{ groupName: "Para", wallets: [paraWallet] }], { appName: "My App", projectId: WALLETCONNECT_PROJECT_ID } ); export const wagmiConfig = createConfig({ chains: [sepolia], connectors, transports: { [sepolia.id]: http(RPC_URL) }, }); // Providers: WagmiProvider + QueryClientProvider + RainbowKitProvider // Then use wagmi hooks: useSignMessage(), useSendTransaction(), etc. ``` ### Graz (Cosmos) ```tsx // src/context/Provider.tsx import { ParaGrazConnector } from "@getpara/graz-integration"; import { ParaWeb, Environment } from "@getpara/react-sdk-lite"; import { GrazProvider, defineChainInfo, type ParaGrazConfig } from "graz"; const para = new ParaWeb(Environment.BETA, API_KEY); const cosmosTestnet = defineChainInfo({ chainId: "provider", chainName: "Cosmos ICS Provider Testnet", rpc: "https://rpc.provider-sentry-01.ics-testnet.polypore.xyz", rest: "https://rest.provider-sentry-01.ics-testnet.polypore.xyz", bip44: { coinType: 118 }, bech32Config: { bech32PrefixAccAddr: "cosmos", /* ... other prefixes */ }, stakeCurrency: { coinDenom: "ATOM", coinMinimalDenom: "uatom", coinDecimals: 6 }, currencies: [{ coinDenom: "ATOM", coinMinimalDenom: "uatom", coinDecimals: 6 }], feeCurrencies: [{ coinDenom: "ATOM", coinMinimalDenom: "uatom", coinDecimals: 6 }], }); const paraConfig: ParaGrazConfig = { paraWeb: para as ParaGrazConfig["paraWeb"], connectorClass: ParaGrazConnector, // Note: connectorClass, not connector instance modalProps: { appName: "My App" }, queryClient: queryClient, }; // Wrap your app: {children} ``` Note: `defineChainInfo` and `ParaGrazConfig` type are imported from `graz`, not from `@getpara/graz-integration`. --- ## 10. Session Management ### Check and keep alive ```ts // Client-side (React hooks) import { useAccount, useKeepSessionAlive } from "@getpara/react-sdk"; const { isConnected } = useAccount(); // Imperative const isActive = await para.isSessionActive(); if (isActive) { await para.keepSessionAlive(); } ``` ### Export / Import session (server transfer) ```ts // Client: export session string const sessionString = await para.exportSession(); // Send sessionString to server via API call // Server: import session const serverPara = new ParaServer(PARA_ENVIRONMENT, PARA_API_KEY); await serverPara.importSession(sessionString); // Server can now sign on behalf of the user const isActive = await serverPara.isSessionActive(); ``` ### Issue JWT ```ts // Client-side import { useIssueJwt } from "@getpara/react-sdk"; const { issueJwt } = useIssueJwt(); const { token, keyId } = await issueJwt(); // Send `token` to your server for verification // Imperative const { token, keyId } = await para.issueJWT(); ``` --- ## 11. ParaModal Configuration The `paraModalConfig` prop on `` (or the config object for `paraConnector`) accepts: ```ts interface ParaModalConfig { // Authentication layout authLayout?: ("AUTH:FULL" | "AUTH:CONDENSED" | "EXTERNAL:FULL" | "EXTERNAL:CONDENSED")[]; // Email / Phone login toggles disableEmailLogin?: boolean; disablePhoneLogin?: boolean; defaultAuthIdentifier?: string; // Pre-fill email/phone // OAuth providers oAuthMethods?: TOAuthMethod[]; // TOAuthMethod = "APPLE" | "DISCORD" | "FACEBOOK" | "FARCASTER" | "GOOGLE" | "TWITTER" | "TELEGRAM" // Branding logo?: string; // recommended 372x160px // Theme theme?: { foregroundColor?: string; backgroundColor?: string; accentColor?: string; darkForegroundColor?: string; darkBackgroundColor?: string; darkAccentColor?: string; overlayBackground?: string; mode?: "light" | "dark"; borderRadius?: "none" | "xs" | "sm" | "md" | "lg" | "xl" | "full"; font?: string; oAuthLogoVariant?: "dark" | "light" | "default"; }; // Features onRampTestMode?: boolean; recoverySecretStepEnabled?: boolean; twoFactorAuthEnabled?: boolean; hideWallets?: boolean; // Hide wallet terminology isGuestModeEnabled?: boolean; // Enable guest login bareModal?: boolean; // No overlay backdrop embeddedModal?: boolean; // Embedded styling className?: string; // Custom CSS class // Account linking supportedAccountLinks?: ("EMAIL" | "PHONE" | "GOOGLE" | "EXTERNAL_WALLET")[]; // Step override currentStepOverride?: ModalStepProp; // Steps: AUTH_MAIN, AUTH_MORE, AWAITING_OAUTH, VERIFICATIONS, // BIOMETRIC_CREATION, PASSWORD_CREATION, SECRET, AWAITING_WALLET_CREATION, // ACCOUNT_MAIN, ACCOUNT_PROFILE, CHAIN_SWITCH, // EX_WALLET_MORE, EX_WALLET_SELECTED, // ADD_FUNDS_BUY, ADD_FUNDS_RECEIVE, ADD_FUNDS_WITHDRAW, // SETUP_2FA, VERIFY_2FA // Callbacks onModalStepChange?: (value: any) => void; onClose?: () => void; // Advanced overrides loginTransitionOverride?: (para: ParaWeb) => Promise; createWalletOverride?: (para: ParaWeb) => Promise<{ recoverySecret?: string; walletIds: any }>; } ``` > **Note:** Password and PIN screens render in an iframe and use the Developer Portal theme settings, not `paraModalConfig.theme`. --- ## 12. Mobile Setup Requirements ### Required Native Modules (Expo) ```json { "@craftzdog/react-native-buffer": "^6.1.0", "@getpara/react-native-wallet": "", "@peculiar/webcrypto": "^1.5.0", "@react-native-async-storage/async-storage": "^2.2.0", "react-native-keychain": "^10.0.0", "react-native-modpow": "^1.1.0", "react-native-passkey": "^3.3.2", "react-native-quick-base64": "^2.2.0", "react-native-quick-crypto": "^0.7.14", "react-native-worklets": "^0.5.1", "readable-stream": "^4.5.2" } ``` ### Metro Config (polyfills) ```js // metro.config.js const { getDefaultConfig } = require('expo/metro-config'); const config = getDefaultConfig(__dirname); config.resolver.extraNodeModules = { crypto: require.resolve('react-native-quick-crypto'), buffer: require.resolve('@craftzdog/react-native-buffer'), }; module.exports = config; ``` ### Babel Config ```js // babel.config.js module.exports = function (api) { api.cache(true); return { presets: [['babel-preset-expo', { jsxImportSource: 'nativewind' }], 'nativewind/babel'], plugins: ['react-native-worklets/plugin'], }; }; ``` ### iOS Passkey Setup For passkey support on iOS, you must configure your app's Associated Domains capability with a `webcredentials:` entry pointing to your domain. The domain must serve an `apple-app-site-association` file. See `examples-hub/mobile/with-expo-one-click-login/ios/` for an example Xcode project configuration. ### Key Init Option Always pass `{ disableWorkers: true }` when initializing `ParaMobile` - Web Workers are not available in React Native. --- ## 13. Vite Polyfill Configuration Vue and Svelte projects using Vite need `vite-plugin-node-polyfills` because the Para SDK uses Node.js built-in modules (`buffer`, `crypto`, `stream`). ```ts // vite.config.ts import { defineConfig } from "vite"; import vue from "@vitejs/plugin-vue"; // or svelte() import { nodePolyfills } from "vite-plugin-node-polyfills"; export default defineConfig({ plugins: [vue(), nodePolyfills()], }); ``` Install: ```bash npm install -D vite-plugin-node-polyfills ``` This is required for `@getpara/web-sdk`. The `@getpara/react-sdk` with Next.js does **not** need this (Next.js handles polyfills via `npx setup-para` postinstall script). --- ## 14. React Hook Reference ### CSS Import ParaModal requires its stylesheet: ```tsx import "@getpara/react-sdk/styles.css"; ``` Add this in your root layout or ParaProvider component. `ParaProvider` renders an embedded `ParaModal` by default. Do not render a separate `` unless `config.disableEmbeddedModal` is set to `true`. ### From `@getpara/react-sdk` **Account & Connection:** - `useAccount()` -> `{ isConnected, isConnecting, address, embedded }` - `embedded.wallets` contains wallet array - `useClient()` -> Para client instance (for passing to signer constructors) - `useIsFullyLoggedIn()` -> `boolean | undefined` - `useParaStatus()` -> `ParaStatus` (readiness and Farcaster Mini App detection) - `useModal()` -> `{ isOpen, openModal, closeModal }` - `useWallet()` -> `Wallet | null | undefined` (active wallet) - `useWalletState()` -> `{ selectedWallet, setSelectedWallet, updateSelectedWallet }` - `useLinkedAccounts()` -> `LinkedAccounts & { userId: string }` **Authentication:** - `useSignUpOrLogIn()` -> `{ signUpOrLogIn, signUpOrLogInAsync, isPending }` - `useVerifyOAuth()` -> `{ verifyOAuth, isPending }` - `useVerifyFarcaster()` -> `{ verifyFarcaster, isPending }` - `useVerifyNewAccount()` -> `{ verifyNewAccount, verifyNewAccountAsync }` - `useWaitForLogin()` -> `{ waitForLogin, isPending }` - `useWaitForWalletCreation()` -> `{ waitForWalletCreation, isPending }` - `useLoginExternalWallet()` -> `{ loginExternalWallet, loginExternalWalletAsync }` - `useLogout()` -> `{ logout, logoutAsync }` - `useAddAuthMethod()` -> `{ addCredential, addCredentialAsync }` - `useLinkAccount()` -> `{ linkAccount, isPending, error }` **Signing (low-level):** - `useSignMessage()` -> `{ signMessage, signMessageAsync }` - signs base64-encoded message with wallet ID - `useSignTransaction()` -> `{ signTransaction, signTransactionAsync }` **Session:** - `useKeepSessionAlive()` -> `{ keepSessionAlive, keepSessionAliveAsync }` - `useIssueJwt()` -> `{ issueJwt, issueJwtAsync }` -> `{ token, keyId }` **Wallet Management:** - `useCreateWallet()` -> `{ createWallet, createWalletAsync }` - `useCreateWalletPerType()` -> `{ createWalletPerType, createWalletPerTypeAsync }` - create wallets for multiple chain types - `useCreateGuestWallets()` -> `{ createGuestWallets, createGuestWalletsAsync }` - `useWalletBalance()` -> `string | null` - balance in native units ### From `@getpara/react-sdk/evm` EVM-specific hooks for direct Viem client access. `@getpara/react-sdk` includes `@getpara/viem-v2-integration`; install `viem` when your app imports Viem helpers directly: - `useViemClient({ address, walletClientConfig })` -> `{ viemClient }` - returns a Viem WalletClient pre-configured with the Para signer ```ts import { useAccount } from "@getpara/react-sdk"; import { useViemClient } from "@getpara/react-sdk/evm"; import { http } from "viem"; import { sepolia } from "viem/chains"; const { embedded } = useAccount(); const address = embedded?.wallets?.[0]?.address as `0x${string}`; const { viemClient } = useViemClient({ address, walletClientConfig: { chain: sepolia, transport: http() }, }); // viemClient.sendTransaction, viemClient.signMessage, etc. ``` This is the preferred way to use Viem in React - no need to import `createParaAccount` / `createParaViemClient` directly. ### From `@getpara/react-sdk/viem` - `useViemAccount({ address? })` -> `{ viemAccount: Account | null, isLoading }` - lower-level access to the viem Account without creating a full WalletClient ### From `@getpara/react-sdk/solana` - `useSolanaSigner({ rpc, walletId? })` -> `{ solanaSigner: SignerWalletAdapter | null, isLoading }` - for Solana Signers v2 integration ### From `@getpara/react-sdk/cosmos` - `useCosmjsProtoSigner({ prefix?, walletId?, messageSigningTimeoutMs? })` -> `{ protoSigner: OfflineDirectSigner | null, isLoading }` - for CosmJS proto signing - `useCosmjsAminoSigner({ prefix?, walletId?, messageSigningTimeoutMs? })` -> `{ aminoSigner: OfflineAminoSigner | null, isLoading }` - for CosmJS amino signing ```ts // CosmJS example using hooks import { useCosmjsProtoSigner } from "@getpara/react-sdk/cosmos"; import { SigningStargateClient } from "@cosmjs/stargate"; const { protoSigner } = useCosmjsProtoSigner({ prefix: "cosmos" }); const stargateClient = await SigningStargateClient.connectWithSigner(RPC_URL, protoSigner); ``` --- ## 15. Testing Credentials ### Beta Environment - **Environment**: `Environment.BETA` / `"BETA"` - **Portal base URL**: `https://app.beta.getpara.com` - **API base URL**: `https://api.beta.getpara.com` ### Test Email Pattern Use any email ending in `@test.getpara.com` (e.g., `dev@test.getpara.com`, `test1@test.getpara.com`). **Any OTP code works** (e.g., `123456`, `000000`). ### Test Phone Numbers Use US numbers (+1) with format `(area code)-555-xxxx` (e.g., `(425)-555-1234`, `(206)-555-9876`). **Any OTP code works**. ### User Limits 50 users per beta account. Delete test users via [Developer Portal](https://developer.getpara.com) -> Users section. Users can only be deleted in BETA; in production, wallets are permanent. ### Post-Install Setup Many Next.js examples include a `postinstall` script: ```json "postinstall": "npx setup-para" ``` This configures Next.js webpack to handle Para SDK's WASM and worker files. Always run it after `npm install`. --- ## 16. Examples Hub Directory Map ### Web - Framework Setup | Directory | Framework | SDK | Key Concept | |-----------|----------|-----|-------------| | `web/with-react-nextjs/para-modal/` | Next.js | `@getpara/react-sdk` | ParaProvider + ParaModal quickstart | | `web/with-react-vite/` | React + Vite | `@getpara/react-sdk` | Vite with React | | `web/with-svelte-vite/` | Svelte + Vite | `@getpara/web-sdk` | Imperative ParaWeb init | | `web/with-vue-vite/` | Vue + Vite | `@getpara/web-sdk` | Imperative ParaWeb init | | `web/with-react-tanstack-start/` | TanStack Start | `@getpara/react-sdk` | Full-stack meta-framework | | `web/with-chrome-extension/` | Chrome Ext | `@getpara/react-sdk` | Storage overrides | | `web/with-pwa/` | PWA | `@getpara/react-sdk` | Progressive Web App | ### Web - Authentication | Directory | Auth Method | |-----------|------------| | `web/with-react-nextjs/custom-email-auth/` | Email + passkey verification | | `web/with-react-nextjs/custom-phone-auth/` | Phone + OTP verification | | `web/with-react-nextjs/custom-oauth-auth/` | OAuth (Google, Apple, etc.) + Farcaster | | `web/with-react-nextjs/custom-combined-auth/` | All auth methods combined | ### Web - Signing Libraries | Directory | Library | Package | |-----------|---------|---------| | `web/with-react-nextjs/signer-viem-v2/` | Viem 2.x | `@getpara/viem-v2-integration` | | `web/with-react-nextjs/signer-ethers-v5/` | Ethers 5.x | `@getpara/ethers-v5-integration` | | `web/with-react-nextjs/signer-ethers-v6/` | Ethers 6.x | `@getpara/ethers-v6-integration` | | `web/with-react-nextjs/signer-solana-web3/` | Solana Web3.js | `@getpara/solana-web3.js-v1-integration` | | `web/with-react-nextjs/signer-solana-anchor/` | Anchor | `@getpara/solana-web3.js-v1-integration` | | `web/with-react-nextjs/signer-solana-signers-v2/` | Solana Signers v2 | `@getpara/solana-signers-v2-integration` | | `web/with-react-nextjs/signer-cosmjs/` | CosmJS | `@getpara/react-sdk` (uses `useCosmjsProtoSigner` from `/cosmos`) | ### Web - Connectors | Directory | Connector | Package | |-----------|-----------|---------| | `web/with-react-nextjs/connector-wagmi/` | Wagmi v2 | `@getpara/wagmi-v2-integration` + `@getpara/react-sdk-lite` | | `web/with-react-nextjs/connector-rainbowkit/` | RainbowKit | `@getpara/rainbowkit-wallet` | | `web/with-react-nextjs/connector-graz/` | Graz (Cosmos) | `@getpara/graz-integration` | | `web/with-react-nextjs/connector-reown-appkit/` | Reown AppKit | `@getpara/wagmi-v2-integration` | ### Web - Account Abstraction | Directory | Provider | Standard | |-----------|----------|----------| | `web/with-react-nextjs/aa-alchemy-4337/` | Alchemy | ERC-4337 | | `web/with-react-nextjs/aa-alchemy-7702/` | Alchemy | EIP-7702 | | `web/with-react-nextjs/aa-zerodev-4337/` | ZeroDev | ERC-4337 | | `web/with-react-nextjs/aa-zerodev-7702/` | ZeroDev | EIP-7702 | | `web/with-react-nextjs/aa-gelato-4337/` | Gelato | ERC-4337 | | `web/with-react-nextjs/aa-gelato-7702/` | Gelato | EIP-7702 | | `web/with-react-nextjs/aa-thirdweb-4337/` | Thirdweb | ERC-4337 | | `web/with-react-nextjs/aa-rhinestone-4337/` | Rhinestone | ERC-4337 | | `web/with-react-nextjs/aa-porto-7702/` | Porto | EIP-7702 | ### Web - Modal Variants | Directory | Chain Focus | |-----------|------------| | `web/with-react-nextjs/para-modal/` | Default (all chains) | | `web/with-react-nextjs/para-modal-evm/` | EVM only | | `web/with-react-nextjs/para-modal-solana/` | Solana only | | `web/with-react-nextjs/para-modal-cosmos/` | Cosmos only | | `web/with-react-nextjs/para-modal-multichain/` | Explicit multi-chain | | `web/with-react-nextjs/para-pregen-claim/` | Pre-generated wallet claiming | ### Server | Directory | Runtime | Key Features | |-----------|---------|-------------| | `server/with-node/` | Node.js | Pregen wallets, Viem/Ethers/Solana/CosmJS signing, Alchemy AA, ZeroDev AA | | `server/with-bun/` | Bun | Session-based signing, Alchemy/ZeroDev EIP-7702 | | `server/with-deno/` | Deno | Session-based signing, Alchemy/ZeroDev EIP-7702 | | `server/rest-with-node/` | Node.js | REST API direct usage (no SDK, raw fetch) | ### Mobile | Directory | Platform | Key Features | |-----------|----------|-------------| | `mobile/with-react-native/` | React Native | Standard RN setup | | `mobile/with-expo-one-click-login/` | Expo | One-click login, passkeys, native crypto polyfills | ### Advanced Patterns | Directory | Pattern | |-----------|---------| | `advanced-patterns/client-auth-server-sign/` | Client authenticates, exports session, server signs | | `advanced-patterns/with-bulk-pregen/` | Bulk wallet pre-generation with multi-chain claiming UI | ### DeFi Integrations | Directory | Integration | |-----------|------------| | `defi-integrations/with-jupiter-dex-api/` | Jupiter DEX (Solana) | | `defi-integrations/with-squid-router-api/` | Squid cross-chain router | | `defi-integrations/with-relay-bridge-api/` | Relay Protocol bridge | --- --- # Agentic Development Source: https://docs.getpara.com/v3/cli/agentic-development import { Link } from "/snippets/v3/components/ui/link.mdx"; Use the Para CLI with Claude, Codex, Cursor, Windsurf, and other coding agents to manage project setup, API keys, and integration checks from the terminal. ## What You'll Learn - How to give an agent a safe Para CLI workflow - Which CLI commands are useful for setup, key management, and diagnostics - How agents can inspect the command catalog instead of guessing command syntax - Which operations should require your approval before the agent runs them ## Start With CLI Context Install and authenticate the CLI before asking an agent to configure Para: ```bash npm install -g @getpara/cli para login para whoami ``` Then let the agent inspect the machine-readable command catalog: ```bash para commands --json ``` The catalog includes command paths, arguments, options, JSON support, interactivity, side effects, and examples. Agents should use it before running unfamiliar `para` commands. For broader Para context, give your agent the or connect the . ## Prompt Claude or Codex Use a prompt that gives the agent a clear boundary: ```text Use the Para CLI to help me finish my Para integration. First run read-only commands: - para commands --json - para auth status --json - para whoami --json - para keys list --json - para keys config show --json Then propose the exact commands needed to configure my local app. Ask before creating, rotating, archiving, or changing API keys or projects. Do not print secret keys in the chat unless I explicitly ask. ``` For a new Next.js app, ask for a full setup path: ```text Use the Para CLI to scaffold a Next.js app with EVM and Solana support. After scaffolding, connect it to my selected Para project, write the API key to the app env file, and run para doctor on the result. Use JSON output where available and explain any command that needs my approval before running it. ``` For an existing app, ask the agent to inspect first: ```text Use the Para CLI to audit this existing Para integration. Run para whoami, para keys config show --json, and para doctor. Compare the API key config to the app's env vars and provider setup. Recommend fixes before changing files or API key configuration. ``` ## Common Agent Workflows ### Confirm Context ```bash para auth status --json para whoami --json para orgs list --json para projects list --json para keys list --json ``` Use these commands before any mutation so the agent knows which organization, project, and key environment are active. ### Save Project Defaults ```bash para orgs switch para projects switch para init --yes ``` `para init --yes` writes `.pararc` for the current directory using the resolved org, project, and key environment. Commit `.pararc` only if your team wants shared project defaults, and never store secrets in it. ### Manage API Key Settings ```bash para keys config show --json para keys config security --origins "https://app.example.com,http://localhost:3000" para keys config auth --oauth-methods "GOOGLE,APPLE" para keys config setup --wallet-types "EVM,~SOLANA" para keys config webhooks --url "https://api.example.com/webhooks" --events "user.created,wallet.created" --enabled ``` Use category commands for focused changes. Most `para keys config` category commands can run interactively or with flags. ### Diagnose an Integration ```bash para doctor para doctor --json para doctor --category configuration para doctor --severity error ``` Agents can use `para doctor --json` to identify missing env vars, framework-specific setup issues, API key mismatches, duplicate modal instances, package issues, and other integration problems. ## Use JSON Safely Many commands support `--json` for agent and CI workflows. Some commands require enough non-interactive flags before JSON output is allowed: | Command | Required for non-interactive JSON | |---|---| | `para init --json` | Add `--yes` | | `para create --json` | Provide an app name plus `--networks` for Next.js or `-t expo --bundle-id` for Expo | | `para projects create --json` | Add `--name` | | `para projects archive --json` | Add `--yes` | | `para keys create --json` | Add `--name` | | `para keys rotate --json` | Add `--yes` | | `para keys archive --json` | Add `--yes` | | `para keys config --json` | Provide at least one category flag | | `para update --json` | Add `--check` or `--yes` | Treat key rotation, key archival, project archival, migration apply, rollback apply, and CLI updates as approval-required operations. They can change live configuration or local files. ## Keep Secrets Out of Chat - Prefer `para keys get --copy` when you need the public API key locally. - Use `para keys get --copy-secret` only when you intentionally need the secret key. - Avoid pasting secret keys into an agent conversation. - Ask the agent to summarize configuration without printing full secrets. ## Useful Links - - - - # Command Reference Source: https://docs.getpara.com/v3/cli/commands import { Link } from "/snippets/v3/components/ui/link.mdx"; ## Global Options These options work with all commands: | Flag | Description | |---|---| | `-e, --environment ` | Key environment: `beta` or `prod` (default: `beta`) | | `--json` | Output JSON when the command supports it | | `--org ` | Override the active organization | | `--project ` | Override the active project | | `-q, --quiet` | Suppress non-essential output | Use `para commands --json` to print the agent-readable command catalog. It includes command paths, arguments, options, examples, interactivity, JSON support, and side effects. ## Authentication The full command paths are `para auth login`, `para auth logout`, and `para auth status`. `para login` and `para logout` are top-level shortcuts. ### `para login` Authenticate with your Para developer account. Opens your browser for a secure OAuth flow with PKCE verification. ```bash para login ``` After login, the CLI automatically selects your first organization and project if none are configured. Sessions are stored at `~/.config/para/credentials.json`. The session is validated server-side on each CLI invocation. Sessions are shared across key environments — logging in once gives you access to both beta and prod keys. ### `para logout` Clear stored authentication credentials. ```bash para logout ``` | Flag | Description | |---|---| | `--all` | Clear all stored sessions | The CLI sends a best-effort server-side session invalidation. ### `para auth status` Check whether your current session is valid. This performs a server-side validation, not just a local check. ```bash para auth status ``` ```bash Output Status: Authenticated Email: dev@example.com Expires: 3/10/2026, 12:00:00 PM ``` With `--json`: ```json { "authenticated": true, "email": "dev@example.com", "userId": "usr_abc123", "expiresAt": 1741608000000 } ``` ### `para whoami` Show the current authenticated user and active context — organization, project, and environment. ```bash para whoami ``` ```bash Output Email: dev@example.com User ID: usr_abc123 Key Environment: beta Organization: My Company (admin) Project: proj_def456 Session Expires: 3/10/2026, 12:00:00 PM ``` Organization shows the name and your role. Project shows the raw project ID. If the organization ID can't be resolved to a name, the raw ID is shown instead. --- ## Configuration Configuration resolves from multiple sources: CLI flags, environment variables (`PARA_ENVIRONMENT`, `PARA_ORG_ID`, `PARA_PROJECT_ID`), `.pararc`, global config, then defaults. See [Installation](/v3/cli/installation#configuration) for the full resolution chain. ### `para config get` Read configuration values. Without a key, shows all values from both global and project config with their source. ```bash para config get ``` ```bash Output defaultEnvironment (global): beta environment (.pararc): beta organizationId (.pararc): org_xyz789 projectId (.pararc): proj_def456 ``` Read a specific key: ```bash para config get defaultEnvironment ``` Project config (`.pararc`) takes precedence over global config (`~/.config/para/config.json`). ### `para config set` Set a configuration value. ```bash para config set ``` | Flag | Description | |---|---| | `--local` | Write to `.pararc` in the current directory instead of global config | #### Valid Keys | Global Key | Project `.pararc` Key | Values | |---|---|---| | `defaultEnvironment` | `environment` | `beta`, `prod` | | `defaultOrganizationId` | `organizationId` | Any valid organization ID | | `defaultProjectId` | `projectId` | Any valid project ID | #### Examples ```bash # Set global default key environment para config set defaultEnvironment prod # Set global default org para config set defaultOrganizationId org_xyz789 ``` `para config set --local` accepts either global key names such as `defaultEnvironment` or project key names such as `environment`, then writes the `.pararc` key form. ### `para config unset` Remove a configuration value. ```bash para config unset ``` | Flag | Description | |---|---| | `--local` | Remove from `.pararc` instead of global config | ```bash para config unset defaultOrganizationId para config unset environment --local ``` ### `para init` Create a `.pararc` configuration file in the current directory. This pins the organization, project, and environment for anyone working in this directory. ```bash para init ``` | Flag | Description | |---|---| | `--force` | Overwrite an existing `.pararc` file | | `-y, --yes` | Skip prompts and use the resolved defaults | In interactive mode, you'll be prompted to select a key environment (`beta` or `prod`). With `--yes`, the current resolved key environment is used. The resulting `.pararc` file: ```json { "environment": "beta", "organizationId": "org_xyz789", "projectId": "proj_def456" } ``` The `.pararc` writer rejects keys that contain sensitive terms (`session`, `token`, `secret`, `credential`, `password`, `apikey`, `api_key`) to prevent accidental credential storage in version-controlled files. --- ## Organizations ### `para orgs list` List all organizations you belong to. ```bash para orgs list ``` ```bash Output Name ID Plan My Company org_xyz789 growth (active) Side Project org_abc123 free ``` The `(active)` indicator shows which organization is currently selected. With `--json`, returns an array of organization objects. ### `para orgs switch` Set the active organization. This updates your global config so subsequent commands use this org. ```bash para orgs switch [org-id] ``` Without an `org-id`, an interactive selector is shown: ```bash para orgs switch ``` ```bash Output ◆ Select an organization │ ○ My Company (org_xyz789) (current) │ ● Side Project (org_abc123) └ ``` With a specific ID: ```bash para orgs switch org_abc123 ``` After switching organizations, your previous project ID remains in the config but may point to a project in the old org. Run `para projects switch` to select a project in the new organization. --- ## Projects All project commands require an active organization. Set one with `para orgs switch` if you haven't already. ### `para projects list` List projects in your active organization. ```bash para projects list ``` | Flag | Description | |---|---| | `--include-archived` | Include archived projects in the list | ```bash Output Name ID Framework my-app proj_def456 nextjs (active) backend proj_ghi789 vite ``` ### `para projects switch` Set the active project. ```bash para projects switch [project-id] ``` Without a `project-id`, an interactive selector shows all active projects in the current organization. ### `para projects create` Create a new project in the active organization. ```bash para projects create ``` | Flag | Description | |---|---| | `-n, --name ` | Project name | | `-d, --description ` | Project description | | `--framework ` | Framework (`nextjs`, `vite`, `react-native`, etc.) | Without flags, you'll be prompted interactively for a name. ```bash para projects create -n "my-new-app" --framework nextjs ``` ### `para projects update` Update a project's name, description, or framework. ```bash para projects update [project-id] ``` | Flag | Description | |---|---| | `-n, --name ` | New project name | | `-d, --description ` | New description | | `--framework ` | Framework (`REACT`, `NEXT`, `VITE`, etc.) | | `--package-manager ` | Package manager (`NPM`, `YARN`, `PNPM`) | Uses the active project if no `project-id` is given. Without flags, prompts interactively. ### `para projects archive` Archive a project. Its API keys stop working immediately. This is reversible with `restore`. ```bash para projects archive [project-id] ``` Uses the active project if no `project-id` is given. | Flag | Description | |---|---| | `-y, --yes` | Skip confirmation prompt | Archiving a project immediately disables all of its API keys. Active users will lose access. ### `para projects restore` Restore a previously archived project. ```bash para projects restore ``` Use `para projects list --include-archived` to find the ID of archived projects. --- ## API Keys All key commands require an active organization and project. Set them with `para orgs switch` and `para projects switch`. ### `para keys list` List API keys for the active project. ```bash para keys list ``` | Flag | Description | |---|---| | `--include-archived` | Include archived keys | ```bash Output Name ID API Key Env Status prod-key key_abc123 para_beta_a1b2... BETA active test-key key_def456 para_beta_c3d4... BETA archived ``` ### `para keys get` Get details of an API key. Without a key ID, the CLI auto-resolves the key from your active project and key environment. ```bash para keys get [key-id] ``` | Flag | Description | |---|---| | `--show-secret` | Show the full secret key (unmasked) | | `--copy` | Copy the public API key to clipboard | | `--copy-secret` | Copy the secret key to clipboard | ```bash para keys get # Get the beta key (default) para keys get -e prod # Get the prod key para keys get abc-123 --copy # Copy a specific key ``` ### `para keys create` Create a new API key in the active project. ```bash para keys create ``` | Flag | Description | |---|---| | `-n, --name ` | Internal key name | | `--display-name ` | Display name shown to users | The secret key is only shown once at creation time. Save it immediately. ### `para keys rotate` Rotate an API key. The old key stops working immediately. Without a key ID, the CLI auto-resolves the key from your active project and key environment. ```bash para keys rotate [key-id] ``` | Flag | Description | |---|---| | `--secret` | Rotate the secret key instead of the public key | | `-y, --yes` | Skip confirmation prompt | ```bash para keys rotate # Rotate the beta key para keys rotate -e prod # Rotate the prod key para keys rotate --secret # Rotate the secret key ``` Key rotation is irreversible. The old key stops working immediately after rotation. ### `para keys archive` Archive (revoke) an API key. The key stops working immediately. Without a key ID, the CLI auto-resolves the key from your active project and key environment. ```bash para keys archive [key-id] ``` | Flag | Description | |---|---| | `-y, --yes` | Skip confirmation prompt | ```bash para keys archive # Archive the beta key para keys archive -e prod # Archive the prod key ``` ### `para keys config` Configure settings for an API key. Without a sub-category, opens an interactive menu to browse all categories. ```bash para keys config [key-id] ``` The CLI auto-resolves the key from your active project and key environment (`-e beta` or `-e prod`). If multiple keys exist for the same environment, you'll be prompted to choose one. #### Show Configuration View the current configuration for an API key without entering an edit flow. Shows all settings organized by category. ```bash para keys config show [category] [key-id] ``` | Argument | Description | |---|---| | `[category]` | Filter by category: `security`, `branding`, `auth`, `modal`, `external-wallets`, `links`, `app`, `setup`, `ramps`, `webhooks` | | `[key-id]` | API key ID (resolved from project + environment if omitted) | ```bash para keys config show # Show all configuration para keys config show security # Show security settings only para keys config show ramps # Show ramp settings only para keys config show --json # Full config as JSON (for scripting) para keys config show security --json # Single category as JSON ``` ```bash Example output Para (beta) Security Auth Methods PASSKEY, PASSWORD Origins https://myapp.com Session Length 1440 minutes (1 day) Tx Popups enabled IP Allowlist (none — all IPs allowed) Branding Foreground #333333 Background #ffffff Accent (default) Font Helvetica ... ``` Use `para keys config show --json` to pipe configuration into other tools or audit scripts. The JSON output uses raw values (arrays, booleans, `null`) rather than display strings. #### Security Configure auth methods, origins, session length, and IP restrictions. ```bash para keys config security [key-id] ``` | Flag | Description | |---|---| | `--origins ` | Comma-separated allowed origins (empty string to clear) | | `--auth-methods ` | Auth methods: `PASSKEY`, `PASSWORD`, `PIN` (comma-separated). `PASSWORD` and `PIN` cannot be enabled simultaneously | | `--session-length ` | Session length in minutes (5–43200) | | `--transaction-popups` | Enable transaction popups | | `--no-transaction-popups` | Disable transaction popups | | `--ip-allowlist ` | Comma-separated CIDR blocks (empty string to clear) | ```bash para keys config security --origins "https://myapp.com,https://staging.myapp.com" --auth-methods "PASSKEY,PASSWORD" ``` #### Branding Configure colors, fonts, social links, and email settings. ```bash para keys config branding [key-id] ``` | Flag | Description | |---|---| | `--foreground-color ` | Foreground color (`#RGB` or `#RRGGBB`) | | `--fg-color ` | Foreground color (alias) | | `--background-color ` | Background color | | `--bg-color ` | Background color (alias) | | `--accent-color ` | Accent color | | `--font ` | Font: `Arial`, `Courier New`, `Georgia`, `Helvetica`, `Lucida Sans`, `Tahoma`, `Times New Roman`, `Trebuchet MS` | | `--mode ` | Theme mode: `light` or `dark` | | `--border-radius ` | Border radius | | `--foreground-mix-ratio ` | Foreground mix ratio from `0` to `1` | | `--css-override ` | Repeatable CSS override for supported modal CSS variables | | `--homepage-url ` | Homepage URL (HTTPS) | | `--twitter-url ` | Twitter/X profile URL | | `--linkedin-url ` | LinkedIn company URL | | `--github-url ` | GitHub URL | | `--verify-url ` | Verification email URL (HTTPS) | | `--email-welcome` / `--no-email-welcome` | Toggle welcome email | | `--email-backup-kit` / `--no-email-backup-kit` | Toggle backup kit email | #### Authentication Configure login methods, OAuth providers, 2FA, and guest mode. ```bash para keys config auth [key-id] ``` | Flag | Description | |---|---| | `--oauth-methods ` | Comma-separated OAuth methods | | `--disable-email-login` / `--no-disable-email-login` | Disable or enable email login | | `--disable-phone-login` / `--no-disable-phone-login` | Disable or enable phone login | | `--two-factor-auth` / `--no-two-factor-auth` | Enable or disable two-factor auth | | `--guest-mode` / `--no-guest-mode` | Enable or disable guest mode | ```bash para keys config auth --oauth-methods "GOOGLE,APPLE" --two-factor-auth ``` #### Custom OIDC Configure your own OpenID Connect provider as a login method. See [Set up Custom OIDC](/v3/general/developer-portal-custom-oidc) for the full walkthrough. ```bash para keys config oidc set [key-id] ``` | Flag | Description | |---|---| | `--issuer ` | Provider issuer URL (HTTPS, no query string) | | `--client-id ` | OIDC client ID | | `--scopes ` | Space-separated scopes (defaults to `openid email profile`) | | `--auth-method ` | Token endpoint auth: `client_secret_post`, `client_secret_basic`, or `none` | | `--label ` | Sign-in label shown on the login button | ```bash # Configure the provider para keys config oidc set --issuer https://idp.example.com --client-id my-client --label "Sign in with Acme" # Store the client secret (prompted; never echoed or written to .pararc) para keys config oidc set-secret # Verify Para can reach the provider para keys config oidc verify # Show the current config (and whether a secret is set) para keys config oidc show ``` Enable Custom OIDC once configured with `para keys config auth --oauth-methods "...,CUSTOM_OIDC"`. #### Modal Configure modal UI behavior for an API key. ```bash para keys config modal [key-id] ``` | Flag | Description | |---|---| | `--hide-wallets` / `--no-hide-wallets` | Hide or show wallet terminology and displays | | `--auth-layout ` | Comma-separated auth layout slots | | `--hide-logo` / `--no-hide-logo` | Hide or show the partner logo | | `--disable-add-funds-prompt` / `--no-disable-add-funds-prompt` | Disable or enable the add-funds prompt | ```bash para keys config modal --hide-wallets --auth-layout "AUTH:FULL,EXTERNAL:FULL" ``` #### External Wallets Configure external wallet support for an API key. ```bash para keys config external-wallets [key-id] ``` | Flag | Description | |---|---| | `--wallet-connect-project-id ` | WalletConnect project ID | | `--app-description ` | App description shown to wallet users | | `--wallets ` | Comma-separated external wallet IDs | | `--mode ` | External wallet connection mode | ```bash para keys config external-wallets --wallets "METAMASK,RAINBOW" --mode para-account ``` #### Links Configure partner social and support links. ```bash para keys config links [key-id] ``` | Flag | Description | |---|---| | `--x-url ` | X/Twitter profile URL | | `--linkedin-url ` | LinkedIn company URL | | `--github-url ` | GitHub URL | | `--homepage-url ` | Homepage URL (HTTPS) | ```bash para keys config links --homepage-url "https://example.com" --github-url "https://github.com/example" ``` #### App Configure app-level settings. ```bash para keys config app [key-id] ``` | Flag | Description | |---|---| | `--rpc-url ` | RPC URL | | `--display-name ` | Display name | | `--farcaster-mini-app-url ` | Farcaster mini-app URL | | `--farcaster-splash-image-url ` | Farcaster splash image URL | | `--farcaster-splash-background-color ` | Farcaster splash background color | ```bash para keys config app --display-name "My App" --rpc-url "https://rpc.example.com" ``` #### Setup / Networks Configure wallet types and native passkey settings. ```bash para keys config setup [key-id] ``` | Flag | Description | |---|---| | `--wallet-types ` | Wallet types — prefix with `~` for optional: `"EVM,~SOLANA,~COSMOS,~STELLAR"` | | `--cosmos-prefix ` | Cosmos address prefix | | `--team-id ` | Apple Team ID (10 chars) | | `--bundle-id ` | Apple bundle identifier | | `--android-package ` | Android package name | | `--android-fingerprints ` | Comma-separated SHA256 fingerprints | #### On/Off Ramps Configure buy, receive, and withdraw settings. ```bash para keys config ramps [key-id] ``` | Flag | Description | |---|---| | `--buy-enabled` / `--no-buy-enabled` | Toggle buy | | `--receive-enabled` / `--no-receive-enabled` | Toggle receive | | `--withdraw-enabled` / `--no-withdraw-enabled` | Toggle withdraw | | `--send-enabled` / `--no-send-enabled` | Toggle Send | | `--providers ` | Comma-separated ordered providers: `RAMP`, `STRIPE`, `MOONPAY` | | `--ramp-api-key ` | Ramp API key | | `--default-buy-amount ` | Default buy amount (0.0001–999999) | | `--default-on-ramp-asset ` | Default on-ramp asset | | `--default-on-ramp-network ` | Default on-ramp network | #### Webhooks Configure webhook endpoints, events, and signing secrets. ```bash para keys config webhooks [key-id] ``` | Flag | Description | |---|---| | `--url ` | Webhook endpoint URL (HTTPS) | | `--events ` | Comma-separated events: `user.created`, `wallet.created`, `transaction.signed`, `send.broadcasted`, `send.confirmed`, `send.failed`, `wallet.pregen_claimed`, `user.external_wallet_verified` | | `--enabled` / `--no-enabled` | Toggle the webhook | | `--status` | Show current webhook configuration | | `--test` | Send a test webhook | | `--rotate-secret` | Rotate the webhook signing secret | | `--delete` | Remove webhook configuration | | `-y, --yes` | Skip confirmation for destructive operations | ```bash para keys config webhooks --url "https://api.myapp.com/webhooks" --events "user.created,wallet.created" --enabled ``` See for event type details and signature verification. --- ## Users ### `para users list` List users for the active project API key. The CLI resolves the API key from the active project and key environment unless you pass `--key`. ```bash para users list ``` | Flag | Description | |---|---| | `--limit ` | Number of users to fetch per page (default: 25, max: 100) | | `--page ` | Page number to fetch (default: 1) | | `--all` | Fetch all pages | | `--method ` | Comma-separated login method filter | | `--key ` | API key ID override | ```bash para users list --key abc-123 para users list --method email,google para users list --json ``` --- ## Scaffold a Project ### `para create` Scaffold a new application with Para SDK pre-configured. The interactive wizard walks you through template, network, auth, and wallet selection. ```bash para create [app-name] ``` | Flag | Description | |---|---| | `-t, --template