Developers
Wallet SDK
One connector for seven chains. Request accounts, build transactions and get them signed, without writing a separate integration for every network.
01Install
npm install @xendra/sdk
# or
pnpm add @xendra/sdk
The SDK ships ESM and CJS builds, has no runtime dependencies beyond a small base58 helper, and works in the browser, in a service worker and in React Native.
02Connect and request accounts
import { Xendra } from '@xendra/sdk'
const wallet = new Xendra({
appName: 'Meridian',
appIcon: 'https://meridian.example/icon.png',
chains: ['eip155:1', 'eip155:8453', 'solana:mainnet', 'tron:mainnet'],
})
const session = await wallet.connect()
console.log(session.accounts)
// [{ chain: 'eip155:1', address: '0x8f2…c41' },
// { chain: 'solana:mainnet', address: '7Gq…9Zt' }]
Chains use CAIP-2 identifiers. Ask only for what you need: a request for four chains where one would do is the fastest way to lose a user at the permission sheet.
03Request a signature
const hash = await wallet.sendTransaction({
chain: 'eip155:8453',
to: '0x1f9…0ab',
value: '0',
data: encodedSwapCall,
preview: {
summary: 'Swap 400 USDC for at least 0.118 ETH',
worstCase: '0.118 ETH',
expires: 1789459200,
},
})
The preview block is optional and never trusted on its own. The wallet decodes and simulates the payload independently, then compares the result with your claim. If they disagree, the user sees both, with yours marked unverified.
Design note
Write a preview summary anyway. Honest apps get a green screen and a faster confirmation; the comparison is what makes that signal worth anything.
04Events and session lifecycle
wallet.on('accountsChanged', accounts => render(accounts))
wallet.on('chainChanged', chain => refetch(chain))
wallet.on('disconnect', reason => teardown(reason))
await wallet.disconnect()
Sessions last 30 days by default and are scoped to your origin. A session cannot be revived from another domain, and a popup that changes origin mid-request is refused outright.
05Errors
| Code | Meaning | What to do |
|---|---|---|
| 4001 | User rejected | Return to your idle state quietly |
| 4100 | Not authorised for this chain | Request the chain in connect() |
| 4200 | Method unsupported on this chain | Check the capability matrix |
| 4900 | Wallet locked | Prompt the user to unlock, then retry |
| 5001 | Simulation mismatch | Your preview disagreed with reality; fix the preview |
06Rate limits and good manners
- Batch balance reads. One call for twenty assets, not twenty calls.
- Never poll for accounts; subscribe to the event.
- Ask for a signature in response to a click, never on page load.
- Public endpoints allow 30 requests per minute per origin. Ask for a key if you need more.
Questions and integration reviews: developers@xendra.xyz.
Start holding your own keys.
iOS, Android, desktop and a browser extension — the same vault on all of them. Free, and it stays free.