Kasperia Wallet API Documentation

Integrate Kasperia Wallet by choosing one access mode first: use the injected provider inside the Kasperia App WebView or desktop extension, or use a deep-link request with callback from an external mobile browser. This guide covers connecting accounts, checking networks, reading balances, signing messages, and sending transactions.

Recommended namespaces: use window.kasperia for Kaspa native APIs and window.kasperia.ethereum for EVM APIs. New integrations should avoid mixed casing or fallback global names unless a third-party EVM library requires window.ethereum.

Kaspa Native

Use window.kasperia to connect a Kaspa account, read network and balance, switch Kaspa network, and send KAS.

EVM

Use window.kasperia.ethereum as an EIP-1193 compatible provider for EVM accounts, chains, RPC, and transactions.

Mobile App

When the dApp is opened inside the Kasperia app, the provider is injected automatically at document start.

Integration Modes

ModeWhen to useProviderUser confirmation
Mobile In-App BrowserUser opens the dApp inside Kasperia App WebView.window.kasperia and window.kasperia.ethereumConnect, switch network, signing, and transaction requests are confirmed in the app.
External Mobile BrowserUser opens the dApp from Safari, Chrome, Telegram, X, or another external app.No injected provider until the user opens Kasperia App.Use a deep link or universal link request payload and receive the result by callback.
Browser ExtensionUser opens the dApp in a desktop browser with the Kasperia extension installed.window.kasperia and window.kasperia.ethereumHandled by the extension wallet UI.

Provider Objects

Kasperia exposes one canonical wallet object for dApps:

window.kasperia

For EVM dApps, use the EVM provider under the same namespace:

window.kasperia.ethereum
ObjectPurposeUse this in new integrations?
window.kasperiaKaspa native wallet API and shared request entry.Yes
window.kasperia.ethereumEVM EIP-1193 compatible provider.Yes
window.ethereumCompatibility with existing EVM libraries.Only when a third-party library requires it.

Quick Start

Most integrations should follow this order:

  1. Detect the environment. If window.kasperia exists, use the injected provider. If it does not exist on mobile, open Kasperia through the external request flow.
  2. Connect after a user click. Use requestAccounts() for Kaspa or eth_requestAccounts for EVM.
  3. Check the current network. Read getNetwork() or eth_chainId. If the user is on the wrong network, call the switch method and wait for confirmation.
  4. Read state. Read the selected account, balance, and network again after connect or switch.
  5. Submit user actions. Sign messages or send transactions only after the user confirms the action in your UI.
For a normal EVM dApp, the shortest path is: detect provider → eth_requestAccountseth_chainIdwallet_switchEthereumChain if needed → eth_sendTransaction or personal_sign.

Copy-paste EVM integration

const KASPLEX_L2_TESTNET = '0x28c64'; // 167012
const KASPLEX_L2_MAINNET = '0x3173b'; // 202555
const BSC_TESTNET = '0x61'; // 97
const BSC_MAINNET = '0x38'; // 56

function getKasperiaWallet() {
  return window.kasperia && window.kasperia.isKasperia ? window.kasperia : null;
}

function getKasperiaEvmProvider() {
  const wallet = getKasperiaWallet();
  return wallet && wallet.ethereum ? wallet.ethereum : null;
}

async function waitForKasperia(timeout = 3000) {
  const wallet = getKasperiaWallet();
  if (wallet) return wallet;

  return new Promise((resolve, reject) => {
    const timer = setTimeout(() => reject(new Error('Kasperia provider not found')), timeout);

    window.addEventListener('kasperia#initialized', () => {
      clearTimeout(timer);
      const injected = getKasperiaWallet();
      injected ? resolve(injected) : reject(new Error('Kasperia provider not found'));
    }, { once: true });
  });
}

async function connectEvm() {
  await waitForKasperia();
  const provider = getKasperiaEvmProvider();
  if (!provider) throw new Error('Kasperia EVM provider is not available');

  const accounts = await provider.request({ method: 'eth_requestAccounts' });
  return { provider, address: accounts[0] };
}

async function ensureEvmChain(provider, targetChainId) {
  const currentChainId = await provider.request({ method: 'eth_chainId' });
  if (currentChainId.toLowerCase() === targetChainId.toLowerCase()) return;

  await provider.request({
    method: 'wallet_switchEthereumChain',
    params: [{ chainId: targetChainId }]
  });
}

async function connectAndPrepareEvm() {
  const { provider, address } = await connectEvm();
  await ensureEvmChain(provider, KASPLEX_L2_TESTNET);

  const balance = await provider.request({
    method: 'eth_getBalance',
    params: [address, 'latest']
  });

  return { provider, address, balance };
}

Copy-paste Kaspa native integration

async function connectKaspa() {
  const wallet = await waitForKasperia();

  const accounts = await wallet.requestAccounts();
  const address = accounts[0];

  const network = await wallet.getNetwork();
  const balance = await wallet.getBalance();

  return { wallet, address, network, balance };
}

async function switchKaspaToTestnet10() {
  const wallet = await waitForKasperia();
  await wallet.switchNetwork('testnet-10');
  return await wallet.getNetwork();
}
Do not trigger connect, switch network, signing, or transaction requests on page load. These requests should be started by a direct user action, such as clicking a Connect, Switch, Sign, or Send button.

Mobile Overview

The Kasperia mobile app supports two mobile access paths:

  1. In-App Browser: the dApp page runs inside Kasperia WebView. The wallet provider is injected automatically.
  2. External Browser: the dApp runs outside Kasperia. Use a deep link or universal link request to open Kasperia and get a callback response.

In-App Browser

Use this mode when your dApp is opened inside the Kasperia mobile app. The app injects window.kasperia at document start. Your page should wait for the provider, then use the same APIs as the browser extension integration.

Recommended page behavior: show a Connect Wallet button, call waitForKasperia() after the click, then call the account, network, balance, sign, or transaction method required by your product flow.
async function initInKasperiaApp() {
  const wallet = await waitForKasperia();

  // Kaspa native provider
  const kaspaAccounts = await wallet.requestAccounts();

  // EVM provider
  const evmProvider = wallet.ethereum;
  const evmAccounts = evmProvider
    ? await evmProvider.request({ method: 'eth_requestAccounts' })
    : [];

  return { wallet, kaspaAccounts, evmProvider, evmAccounts };
}

After connection, always re-read the network before showing balances or enabling transaction buttons.

External Browser

Use this mode when the user opens your dApp in Safari, Chrome, Telegram, X, or another external mobile app. In this environment, the page cannot assume that window.kasperia is injected. Instead, create a wallet request, open Kasperia, and receive the result through your callback URL.

Use external requests for one wallet action at a time: connect, switch network, sign, or send transaction. For a full dApp session, prefer opening the dApp inside Kasperia WebView so the injected provider is available.

Supported request URLs:

kasperia://wallet/request?payload=<base64url-json>
https://link.kasperia.app/wallet/request?payload=<base64url-json>
Only document routes that are already implemented and tested in the app. The currently supported external wallet request routes are kasperia://wallet/request and https://link.kasperia.app/wallet/request.

External Request Payload

The payload is a JSON object encoded as base64url without padding. Each request should have a unique id. Your callback handler must decode walletResponse and verify that the response id matches the request id.

const payload = {
  id: crypto.randomUUID(),
  origin: window.location.origin,
  method: 'eth_requestAccounts',
  params: {},
  callback: `${window.location.origin}/wallet-callback`
};

Encode and open the request:

function base64UrlEncodeJson(json) {
  const raw = JSON.stringify(json);
  const bytes = new TextEncoder().encode(raw);
  let binary = '';
  bytes.forEach((b) => binary += String.fromCharCode(b));

  return btoa(binary)
    .replace(/\+/g, '-')
    .replace(/\//g, '_')
    .replace(/=+$/g, '');
}

function openKasperiaWalletRequest(payload) {
  const encoded = base64UrlEncodeJson(payload);
  window.location.href = `kasperia://wallet/request?payload=${encoded}`;
}

Kasperia returns the result by appending walletResponse to your callback URL:

https://your-dapp.com/wallet-callback?walletResponse=<base64url-json>

Decoded success response:

{
  id: 'request-id',
  success: true,
  data: ['0x1234...']
}

Decoded error response:

{
  id: 'request-id',
  success: false,
  error: {
    code: 4001,
    message: 'User rejected the request'
  }
}
Callback URLs must use an allowed scheme such as https or your app scheme. If origin is provided, the callback host should match the origin host.

Mobile Support Matrix

ActionIn-App BrowserExternal RequestNotes
Connect Kaspawindow.kasperia.requestAccounts()kasperia_requestAccountsShows Connect Wallet confirmation if not authorized.
Connect EVMwindow.kasperia.ethereum.request({ method: 'eth_requestAccounts' })eth_requestAccountsReturns the current EVM address.
Get Kaspa networkwindow.kasperia.getNetwork()kasperia_getNetworkReturns current Kaspa network id.
Switch Kaspa networkwindow.kasperia.switchNetwork('mainnet')kasperia_switchNetworkSupports mainnet and testnet-10 aliases depending on app config.
Switch EVM chainwallet_switchEthereumChainwallet_switchEthereumChainShows Switch Network confirmation.
Get balancegetBalance / eth_getBalanceSupportedEVM token contract balance is not exposed in the current service.
Send KASsendKaspakasperia_sendKaspaAmount must be in sompi.
Send EVM transactioneth_sendTransactioneth_sendTransactionShows transaction confirmation.
Sign messagepersonal_signpersonal_signTyped data v4 is not supported yet.

Connect Wallet

window.kasperia.requestAccounts()Kaspa

Requests access to the current Kaspa account. If the site is not authorized, Kasperia shows a Connect Wallet confirmation.

async function connectKaspaWallet() {
  const accounts = await window.kasperia.requestAccounts();
  const address = accounts[0];
  console.log('Kaspa address:', address);
  return address;
}

Returns

['kaspa:...']
// or
['kaspatest:...']

Accounts

After the site is connected, use getAccounts to read the current Kaspa address without opening the connect prompt again.

const accounts = await window.kasperia.getAccounts();
const current = await window.kasperia.request({ method: 'kasperia_currentAccount' });
const publicKey = await window.kasperia.getPublicKey();

Current account response

{
  id: 'account-id',
  name: 'Account 1',
  kaspaAddress: 'kaspa:...',
  evmAddress: '0x...',
  publicKey: '...',
  isCurrent: true
}

Network

Use getNetwork for the current Kaspa network and getNetworks for all available Kaspa and EVM networks.

const currentKaspaNetwork = await window.kasperia.getNetwork();
const allNetworks = await window.kasperia.getNetworks();

Switch Kaspa network:

await window.kasperia.switchNetwork('mainnet');
await window.kasperia.switchNetwork('testnet-10');

You can also use the generic request form:

await window.kasperia.request({
  method: 'kasperia_switchNetwork',
  params: { type: 'kaspa', network: 'testnet-10' }
});

Balance

Read the current Kaspa account balance. The raw unit is sompi and decimals is 8.

const balance = await window.kasperia.getBalance();
console.log(balance.raw, balance.symbol, balance.decimals);

Response

{
  type: 'kaspa',
  network: 'mainnet',
  address: 'kaspa:...',
  symbol: 'KAS',
  decimals: 8,
  total: '100000000',
  available: '100000000',
  pending: '0',
  raw: '100000000'
}

Send KAS

Use sendKaspa to send KAS. The amount must be passed in sompi.

async function sendKas() {
  const to = 'kaspa:qp...';
  const sompi = '100000000'; // 1 KAS
const txid = await window.kasperia.sendKaspa(to, sompi, {
    payload: ''
  });

  console.log('Kaspa txid:', txid);
}

Generic request form:

const result = await window.kasperia.request({
  method: 'kasperia_sendKaspa',
  params: {
    to: 'kaspa:qp...',
    sompi: '100000000',
    payload: ''
  }
});

Generic Request

window.kasperia.request is the shared low-level request method. It is useful for methods without a convenience wrapper.

const version = await window.kasperia.getVersion();

const result = await window.kasperia.request({
  method: 'kasperia_getNetworks',
  params: {}
});
MethodDescriptionParams
kasperia_requestAccountsConnect and return Kaspa account.{}
kasperia_accountsReturn connected Kaspa account.{}
kasperia_currentAccountReturn current account object.{}
kasperia_getPublicKeyReturn current account public key.{}
kasperia_getBalanceReturn Kaspa or EVM balance depending on type.{ type, address }
kasperia_getNetworkReturn current Kaspa network id.{}
kasperia_getNetworksReturn available Kaspa and EVM networks.{}
kasperia_switchNetworkSwitch Kaspa or EVM network.{ type, network } or { type, chainId }
kasperia_sendKaspaSend KAS.{ to, sompi, payload }
kasperia_disconnectRevoke site permission.{}

Kaspa Events

window.kasperia.on('networkChanged', (network) => {
  console.log('Kaspa network changed:', network);
});

window.kasperia.on('accountsChanged', (accounts) => {
  console.log('Kaspa accounts changed:', accounts);
});

Get EVM Provider

Use window.kasperia.ethereum as the recommended EVM provider.

function getEvmProvider() {
  if (window.kasperia && window.kasperia.ethereum) {
    return window.kasperia.ethereum;
  }
  return null;
}

The provider supports request, send, sendAsync, enable, events, selectedAddress, chainId, and networkVersion.

Connect EVM Account

async function connectEvmWallet() {
  const provider = window.kasperia.ethereum;
  const accounts = await provider.request({ method: 'eth_requestAccounts' });
  return accounts[0];
}

Read connected EVM accounts without prompting:

const accounts = await window.kasperia.ethereum.request({
  method: 'eth_accounts'
});

Get / Switch Chain

Read the current EVM chain id. The result is a hex string.

const chainId = await window.kasperia.ethereum.request({
  method: 'eth_chainId'
});

console.log(chainId); // example: '0x28c64' = 167012

Switch EVM chain. Kasperia will show a Switch Network confirmation sheet in the app.

await window.kasperia.ethereum.request({
  method: 'wallet_switchEthereumChain',
  params: [{ chainId: '0x28c64' }]
});

wallet_addEthereumChain is treated as a switch request to an already configured chain. The current app implementation does not add arbitrary new RPC networks from dApp params.

Get EVM Balance

Use eth_getBalance to read the native EVM balance. The result is a hex quantity.

const address = '0x...';
const balanceHex = await window.kasperia.ethereum.request({
  method: 'eth_getBalance',
  params: [address, 'latest']
});

You can also use the Kasperia generic request form:

const balance = await window.kasperia.request({
  method: 'kasperia_getBalance',
  params: {
    type: 'evm',
    address: '0x...'
  }
});

Send EVM Transaction

Use eth_sendTransaction for EVM transfers or contract calls. The app will show a transaction confirmation sheet before submitting the transaction.

async function sendEvmTransaction() {
  const provider = window.kasperia.ethereum;
  const [from] = await provider.request({ method: 'eth_requestAccounts' });

  const txHash = await provider.request({
    method: 'eth_sendTransaction',
    params: [{
      from,
      to: '0x0000000000000000000000000000000000000000',
      value: '0x0',
      data: '0x'
    }]
  });

  console.log('EVM tx hash:', txHash);
}
The from address must match the current Kasperia EVM account. If it does not match, the request will fail with invalid params.

For native transfers without custom gas or data, you may use the generic request form:

const result = await window.kasperia.request({
  method: 'kasperia_sendTransaction',
  params: {
    type: 'evm',
    to: '0x...',
    amount: '0.01'
  }
});

Sign Message

The current mobile implementation supports personal_sign.

const provider = window.kasperia.ethereum;
const [address] = await provider.request({ method: 'eth_requestAccounts' });

const signature = await provider.request({
  method: 'personal_sign',
  params: ['Hello Kasperia', address]
});

Generic request form:

const signed = await window.kasperia.request({
  method: 'kasperia_signMessage',
  params: {
    message: 'Hello Kasperia',
    address: '0x...'
  }
});

Read-only RPC

The mobile app proxies common read-only EVM RPC calls through the current selected EVM network RPC URL.

eth_blockNumbereth_getBlockByNumbereth_getTransactionCounteth_gasPriceeth_estimateGaseth_calleth_getCodeeth_getLogseth_feeHistoryeth_maxPriorityFeePerGaseth_getTransactionReceipteth_getTransactionByHash
const blockNumber = await window.kasperia.ethereum.request({
  method: 'eth_blockNumber'
});

EVM Events

const provider = window.kasperia.ethereum;

provider.on('accountsChanged', (accounts) => {
  console.log('EVM accounts changed:', accounts);
});

provider.on('chainChanged', (chainId) => {
  console.log('EVM chain changed:', chainId);
});

provider.on('connect', ({ chainId }) => {
  console.log('Connected:', chainId);
});

provider.on('disconnect', (error) => {
  console.log('Disconnected:', error);
});

QR Scan Link Overview

Kasperia can scan a QR code, parse its text content, and open the matching app page with pre-filled parameters. QR scan links are intended to guide the user to the correct screen; they do not silently send funds. The user still reviews and confirms the action inside the app.

A QR code should contain plain text: either a Kaspa address, a protocol URL such as krc20://transfer?... , a Kasperia app route such as kasperia://bridge, an EVM transfer URL, or a normal https:// dApp URL.
Raw Kaspa address

Open Send KAS and pre-fill the recipient, amount, and optional payload.

kasperia://

Open a Kasperia app page such as Bridge, KRC20 token list, or Ecosystem Fund.

krc20://

Open KRC20 transfer, mint, or token detail flows.

ethereum://

Open an EVM native-token or contract-token transfer page. chainId is required.

https://

Open a dApp URL inside the Kasperia WebView.

General QR Link Format

Use URL query parameters for optional values. Always URL-encode user-generated text, especially payloads, spaces, symbols, and non-English characters.

ParameterUsed byDescriptionExample
to / addressKAS, Bridge, KRC20, EVMRecipient address. For Kaspa and KRC20, the address prefix must match the current Kaspa network.to=kaspatest:...
amountKAS, Bridge, KRC20, EVMOptional amount used to pre-fill the target page. Use a human-readable decimal value unless your own UI clearly tells users otherwise.amount=5
payloadKASOptional Kaspa transaction payload. Encode it with encodeURIComponent.payload=hello
tickKRC20KRC20 ticker symbol. Required for KRC20 transfer and mint.tick=JEMES
chainIdEVMRequired EVM chain id. The app must already have a matching network config.chainId=56
tokenEVMOptional ERC20 contract address. If omitted, the app opens the native-token transfer flow.token=0x...
targetAmountEcosystem FundOptional target amount for the Ecosystem Fund page.targetAmount=100
For QR content, prefer standard query syntax with ? after the route and & between parameters. Raw Kaspa address links may also use the compact form shown below, but query-style links are easier for developers to generate and debug.

KAS Transfer QR

A Kaspa QR can contain only a recipient address, or it can include amount and payload. Scanning the QR opens the Send KAS page with the parsed values pre-filled.

Address only kaspatest:qr24daqennp22ang7flqyzn47wrhn90vgvgnem92tk78ga3teewcgyngg85ey
Open the Send KAS page with only the recipient address filled.
Address + amount kaspatest:qr24daqennp22ang7flqyzn47wrhn90vgvgnem92tk78ga3teewcgyngg85ey&amount=5
Open the Send KAS page with recipient and amount pre-filled.
Address + amount + payload kaspatest:qr24daqennp22ang7flqyzn47wrhn90vgvgnem92tk78ga3teewcgyngg85ey&amount=5&payload=haha
Open the Send KAS page with recipient, amount, and payload pre-filled. Keep QR examples as plain text; encode special characters only when your payload contains spaces or symbols.

Alternative query-style format:

kaspa://transfer?to=kaspatest:qr24daqennp22ang7flqyzn47wrhn90vgvgnem92tk78ga3teewcgyngg85ey&amount=5&payload=haha

Generate a KAS transfer QR string:

function buildKasTransferQr({ to, amount, payload }) {
  const params = new URLSearchParams();
  params.set('to', to);
  if (amount !== undefined && amount !== '') params.set('amount', String(amount));
  if (payload) params.set('payload', payload);
  return `kaspa://transfer?${params.toString()}`;
}

const qrText = buildKasTransferQr({
  to: 'kaspatest:qr24daqennp22ang7flqyzn47wrhn90vgvgnem92tk78ga3teewcgyngg85ey',
  amount: 5,
  payload: 'haha'
});

Kasperia App Pages

Use the kasperia:// scheme to open supported Kasperia app pages. This is useful for QR codes printed on websites, campaigns, bridge pages, or offline materials.

QR contentSupported parametersResult in app
kasperia://bridgeto, address, amountOpen the Bridge page. If recipient or amount is provided, the page receives them as initial values.
kasperia://bridge?to=kaspatest:...&amount=5to, amountOpen Bridge with recipient and amount pre-filled.
kasperia://krc20_tokensNoneOpen the KRC20 token list page.
kasperia://eco_system_fund?to=kaspatest:...&amount=5&targetAmount=100to / address, amount, targetAmountOpen the Ecosystem Fund page with receive address and amounts.
kasperia://bridge?to=kaspatest:qr24daqennp22ang7flqyzn47wrhn90vgvgnem92tk78ga3teewcgyngg85ey&amount=5

KRC20 Transfer / Mint QR

Use the krc20:// scheme for KRC20 token actions. The app checks the current Kaspa network, looks up the current account token data, and opens the matching KRC20 page.

ActionQR contentRequired parametersResult in app
Transferkrc20://transfer?tick=JEMES&to=kaspatest:...&amount=5tick, optional to, optional amountOpen KRC20 Send page for the ticker.
Mintkrc20://mint?tick=JEMES&to=kaspatest:...&amount=5tick, optional to, optional amountOpen KRC20 Mint page. If to is missing, the current account Kaspa address is used.
Token detailkrc20://token?tick=JEMEStickOpen the KRC20 token detail page if the current account has token data.

Examples:

krc20://transfer?tick=JEMES&to=kaspatest:qr24daqennp22ang7flqyzn47wrhn90vgvgnem92tk78ga3teewcgyngg85ey&amount=5
krc20://mint?tick=JEMES&to=kaspatest:qr24daqennp22ang7flqyzn47wrhn90vgvgnem92tk78ga3teewcgyngg85ey&amount=5
krc20://token?tick=JEMES
function buildKrc20TransferQr({ tick, to, amount }) {
  const params = new URLSearchParams();
  params.set('tick', tick);
  if (to) params.set('to', to);
  if (amount !== undefined && amount !== '') params.set('amount', String(amount));
  return `krc20://transfer?${params.toString()}`;
}

EVM Transfer QR

Use the ethereum://transfer scheme to open the EVM Send page. chainId is required. If token is omitted, Kasperia opens the native-token transfer flow for that chain. If token is provided, Kasperia treats it as a contract token address and opens the token transfer flow.

Native token transfer ethereum://transfer?chainId=56&to=0xEe461548B7CA5b4A1C9E4c078054BD047b8786c1&amount=1.5
Open the EVM native-token Send page on chain id 56.
Contract token transfer ethereum://transfer?chainId=56&token=0x1234567890abcdef1234567890abcdef12345678&to=0xEe461548B7CA5b4A1C9E4c078054BD047b8786c1&amount=100
Open the EVM contract-token Send page for the given token contract.
The app must have a network configuration matching the scanned chainId. If the chain id is missing or not configured, the app will show an error instead of opening the send page.
function buildEvmTransferQr({ chainId, to, amount, token }) {
  const params = new URLSearchParams();
  params.set('chainId', String(chainId));
  params.set('to', to);
  if (amount !== undefined && amount !== '') params.set('amount', String(amount));
  if (token) params.set('token', token);
  return `ethereum://transfer?${params.toString()}`;
}

Open dApp URL QR

If the scanned QR content is a normal web URL, Kasperia opens it inside the app WebView. The dApp can then use window.kasperia and window.kasperia.ethereum after provider injection.

https://kas.fun/
https://kasbridge-tn10evm-m.kaspafoundation.org/

Recommended dApp behavior after being opened from a QR:

async function initAfterQrOpen() {
  const wallet = await ensureKasperiaReady();
  const accounts = await wallet.requestAccounts();
  const network = await wallet.getNetwork();
  return { accounts, network };
}

QR Builder Examples

Developers can generate QR codes with any QR library as long as the encoded content is the exact plain-text link.

import QRCode from 'qrcode';

const qrText = 'krc20://transfer?tick=JEMES&to=kaspatest:qr24daqennp22ang7flqyzn47wrhn90vgvgnem92tk78ga3teewcgyngg85ey&amount=5';
const dataUrl = await QRCode.toDataURL(qrText);

document.querySelector('#qr').src = dataUrl;

Plain JavaScript helper for building links safely:

const KAS_TEST_ADDRESS = 'kaspatest:qr24daqennp22ang7flqyzn47wrhn90vgvgnem92tk78ga3teewcgyngg85ey';

const examples = {
  kasWithoutAmount: KAS_TEST_ADDRESS,
  kasWithAmount: `${KAS_TEST_ADDRESS}&amount=5`,
  kasWithPayload: `${KAS_TEST_ADDRESS}&amount=5&payload=${encodeURIComponent('haha afasdfsdafasdf')}`,
  bridge: `kasperia://bridge?to=${encodeURIComponent(KAS_TEST_ADDRESS)}&amount=5`,
  krc20Transfer: `krc20://transfer?tick=JEMES&to=${encodeURIComponent(KAS_TEST_ADDRESS)}&amount=5`,
  krc20Mint: `krc20://mint?tick=JEMES&to=${encodeURIComponent(KAS_TEST_ADDRESS)}&amount=5`,
  evmTransfer: 'ethereum://transfer?chainId=56&to=0xEe461548B7CA5b4A1C9E4c078054BD047b8786c1&amount=1.5',
  dapp: 'https://kas.fun/'
};

Validation Notes

  1. Scanning a payment QR opens a pre-filled app page; the user must still confirm the transfer or mint operation.
  2. For Kaspa and KRC20 links, the recipient address prefix must match the current Kaspa network. A kaspatest: address should be used on testnet, and a kaspa: address should be used on mainnet.
  3. For KRC20 actions, tick is required. If the token cannot be found for the current account, the app shows an error.
  4. For EVM transfer links, chainId is required and must exist in the app network config.
  5. Use encodeURIComponent or URLSearchParams for payloads and addresses when generating QR links from JavaScript.
  6. Avoid putting private keys, seed phrases, passwords, or long sensitive data inside QR codes.
  7. Unsupported or unknown protocols should be treated as invalid QR content by the dApp or campaign page.

Network Reference

Use window.kasperia.getNetworks() to get the exact networks configured in the current app build. A network item may include the following fields:

{
  type: 'evm',
  id: '167012',
  name: 'Kasplex L2 Testnet',
  isCurrent: true,
  chainId: 167012,
  rpcUrl: 'https://...',
  explorerUrl: 'https://...',
  symbol: 'KAS',
  decimals: 18
}
Do not hard-code chain ids unless your dApp only supports a fixed network. Prefer reading getNetworks() and then switching to a chain that exists in the returned list.

Error Codes

CodeMeaningCommon reason
4001User rejectedUser tapped Cancel, Reject, or closed the request.
4100UnauthorizedThe site is not connected to Kasperia Wallet.
4200Unsupported methodThe method is not exposed by the current app service.
4900DisconnectedThe wallet provider was disconnected.
-32602Invalid paramsMissing address, invalid chain id, invalid transaction params, or mismatched from address.
-32603Internal errorWallet bridge, RPC, or transaction service failed.
try {
  await window.kasperia.ethereum.request({
    method: 'wallet_switchEthereumChain',
    params: [{ chainId: '0x28c64' }]
  });
} catch (error) {
  if (error.code === 4001) {
    console.log('User rejected the request');
  } else {
    console.error(error.code, error.message, error.data);
  }
}

Best Practices

  1. Use window.kasperia as the single canonical namespace in your dApp.
  2. Use window.kasperia.ethereum for EVM requests instead of mixing multiple provider names.
  3. Always call connect, switch network, signing, and transaction APIs from a user click or similar direct action.
  4. Disable your button while a wallet request is pending to avoid duplicate confirmation sheets.
  5. After switching EVM chains, re-read eth_chainId and update your UI from the chainChanged event.
  6. Pass EVM transaction value, gas, gasPrice, and nonce as hex quantities.
  7. Pass Kaspa transfer amounts in sompi, not decimal KAS.
  8. For external callback flows, generate a unique id for every request and verify the response id.

Unsupported Methods

MethodStatusRecommendation
kasperia_submitCommitRevealNot supported in mobile WebView yet.Do not expose KNS/KRC commit-reveal flows through the mobile dApp API until app service support is added.
kasperia_signTransactionNot exposed by current wallet services.Use send transaction flows that show confirmation and submit through the app.
eth_signTypedData_v4Not supported yet.Use personal_sign only if your use case allows it.
ERC20 balance by contractNot exposed by current mobile service.Use read-only RPC calls or your own RPC/indexer for token balances.