TypeScript / JavaScript SDK

Official typed SDK for Wirex BaaS — Account Abstraction (ZeroDev Kernel V3.1), token transfers, FX swaps, yield and smart deposit addresses in a single npm package.

Before You Start

RequirementNotes
Node.js ≥ 18Required runtime
viem ^2.49.3Peer dependency — install separately
CLIENT_ID / CLIENT_SECRETOAuth2 credentials from Wirex partner onboarding
COMPANY_IDYour company identifier in hex format

@wirexapp/wpay-baas-sdk is the SDK for integration with the Wirex BaaS platform. It supports Account Abstraction (ZeroDev Kernel V3.1), token transfers, FX swaps, yield, and smart deposit addresses, and wraps the BaaS REST API in typed services.

The SDK is published on npm: @wirexapp/wpay-baas-sdk.

This is not the card-data SDK. Card collection, card reveal and 3DS in a browser are covered by the PCI Compliant SDK, a separate package family. The two are installed and versioned independently and can be used together.


Installation

npm install @wirexapp/wpay-baas-sdk viem

Peer dependency: viem ^2.49.3


SDK Initialization

import { createSDK, type SDKEnvironment } from '@wirexapp/wpay-baas-sdk';

const sdk = await createSDK({
  env: 'dev',  // 'dev' | 'prod'
  companyId: '0x...', // Company ID in hex format
  chainId: 8453, // optional, defaults to the remote config's defaultChain
  getMainWalletClient: () => mainWalletClient, // Embedded wallet with EthereumProvider
  enableLogging: true, // optional, default false
  logger: customLogger, // optional, custom logger
});

Configuration Parameters

ParameterTypeRequiredDescription
env'dev' | 'prod'YesEnvironment
companyIdstringYesCompany ID in hex format
companyNamestringNoSent as X-Company-Name on the remote-config fetch, selects that company's chain / contracts / default company
configUrlstringNoExplicit remote-config URL, overrides env
chainIdnumberNoChain to run on: 8453 Base, 84532 Base Sepolia, 5042 Arc, 5042002 Arc Testnet. Defaults to remote config defaultChain
getMainWalletClient() => MainWalletClientYesFunction that returns embedded wallet with EthereumProvider
enableLoggingbooleanNoEnable logging (default false)
loggerLoggerNoCustom logger (requires enableLogging: true)
rhinoApiKeystringNoRhino.fi API key, required only for sdk.crypto.smartDepositAddress

MainWalletClient Contract

getMainWalletClient must return an object implementing this interface:

interface MainWalletClient {
  address: string;
  getEthereumProvider(): Promise<{
    request(args: { method: string; params?: unknown[] }): Promise<unknown>;
  }>;
}

The EIP-1193 provider must handle at minimum:

RPC MethodUsed for
eth_accountsResolve the signer address
personal_signSign messages (SIWE, auth challenges)
eth_signTypedData_v4Sign typed data (UserOperations, EIP-712)

Adapter example — raw private key (tests / embedded wallets)

import { createWalletClient, http } from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
import { baseSepolia } from 'viem/chains';
import type { MainWalletClient } from '@wirexapp/wpay-baas-sdk';

export function createWalletClientFromKey(
  privateKey: `0x${string}`,
  rpcUrl: string,
): MainWalletClient {
  const account = privateKeyToAccount(privateKey);
  const client = createWalletClient({ account, chain: baseSepolia, transport: http(rpcUrl) });

  return {
    address: account.address,
    getEthereumProvider: async () => ({
      request: async ({ method, params = [] }) => {
        if (method === 'eth_accounts') return [account.address];
        if (method === 'personal_sign') {
          const [data] = params as [`0x${string}`, string];
          return client.signMessage({ account, message: { raw: data } });
        }
        if (method === 'eth_signTypedData_v4') {
          const [, json] = params as [string, string];
          const { domain, types, primaryType, message } = JSON.parse(json);
          const { EIP712Domain: _, ...filteredTypes } = types;
          return client.signTypedData({ account, domain, types: filteredTypes, primaryType, message });
        }
        return (client.transport as any).request({ method, params });
      },
    }),
  };
}

Adapter example — Privy embedded wallet

import type { MainWalletClient } from '@wirexapp/wpay-baas-sdk';

// Inside a React component / hook where usePrivy is available:
function getPrivyWalletClient(wallet: ConnectedWallet): MainWalletClient {
  return {
    address: wallet.address,
    getEthereumProvider: () => wallet.getEthereumProvider(),
  };
}

Authentication

The SDK supports three authentication paths depending on your integration type.

Option A — Company OAuth2 (client_credentials)

Used when your backend calls the Wirex API on behalf of users. This is the standard B2B partner flow.

// Step 1 — Exchange company credentials
const tokenRes = await sdk.api.baas.token.getToken({
  grant_type: 'client_credentials',
  client_id:  process.env.CLIENT_ID,
  client_secret: process.env.CLIENT_SECRET,
  audience: 'https://api-business.wirexpaychain.tech', // same for dev and prod
});

// Step 2 — Prime SDK auth state with the company token + user EOA wallet
sdk.auth.setAuthState(
  { access_token: tokenRes.access_token, expires_at: tokenRes.expires_at },
  userEoaWallet,
);

// Step 3 — (After user registration) Login to get a per-user PSI token.
// All sdk.api.baas.* calls automatically use the PSI token after this.
await sdk.auth.login({
  authorizationToken: tokenRes.access_token,
  userWallet: userEoaWallet,
});

console.log('Authenticated:', sdk.auth.isAuthenticated()); // true
console.log('Token:', sdk.auth.getAccessToken());

Option B — Privy

Used in consumer apps where users authenticate through Privy.

import { getAccessToken, useIdentityToken } from '@privy-io/react-auth';

const accessToken  = await getAccessToken();
const { identityToken } = useIdentityToken();

// Login (existing user)
const authResponse = await sdk.auth.login({
  privy: { accessToken, identityToken },
});

// Or register (new user)
const userResponse = await sdk.auth.registerUser({
  privy: { accessToken, identityToken },
  country: 'FR',
});

Option C — JWT

Used when you issue your own tokens or use an auth provider other than Privy.

// Login
const authResponse = await sdk.auth.login({
  authorizationToken: 'your-jwt-token',
  userWallet: userEoaWallet,
});

// Register
const userResponse = await sdk.auth.registerUser({
  authorizationToken: 'your-jwt-token',
  userWallet: userEoaWallet,
  country: 'FR',
  initialData, // see Step 6 below
});

Token Management

After login the SDK holds the token internally. Use these methods to inspect or manage auth state:

MethodReturnsDescription
sdk.auth.isAuthenticated()booleanWhether a valid token is held
sdk.auth.getAccessToken()string | nullCurrent token, or null if expired
sdk.auth.ensureAuthenticated()voidThrows AuthenticationError if not authenticated
sdk.auth.getAuthHeaders()object{ Authorization, X-User-Wallet } headers
sdk.auth.getUserWallet()stringCurrent user wallet address
sdk.auth.setUserWallet(wallet)voidUpdate user wallet address
sdk.auth.setAuthState(response, wallet?)voidRestore auth state from a stored response
sdk.auth.clearAuth()voidClear all auth state (logout)

User Registration Flow

1: Get Smart Wallet Address

const address = await sdk.crypto.wallet.getSmartWalletAddress();
console.log('Smart Wallet:', address);

2: Check Policy & Executor Status

const isPolicyInstalled = await sdk.crypto.accountAbstraction.isPolicyInstalled();
const isExecutorInstalled = await sdk.crypto.accountAbstraction.isExecutorInstalled();

console.log('Policy installed:', isPolicyInstalled);
console.log('Executor installed:', isExecutorInstalled);

3: Install Policy & Executor (if not installed)

if (!isPolicyInstalled || !isExecutorInstalled) {
  const result = await sdk.crypto.accountAbstraction.signInPolicyAndExecutor();
  console.log('Transaction hash:', result?.receipt?.transactionHash);
}

Single-signature alternative (steps 3 + 5 combined). For a wallet with neither the executor nor the policy installed, sdk.crypto.onboarding.allInOneStepOnboarding() batches the executor install, the root-validator switch and the Accounts registration into one UserOperation, so the user signs once instead of three times:

if (!isPolicyInstalled && !isExecutorInstalled) {
  const receipt = await sdk.crypto.onboarding.allInOneStepOnboarding();
  console.log('Transaction hash:', receipt.receipt.transactionHash);
} else {
  // fall back to the per-step calls below
}

4: If you use Privy as auth — Link Smart Wallet to Privy (SIWE)

import { useLinkWithSiwe } from '@privy-io/react-auth';

const { generateSiweMessage, linkWithSiwe } = useLinkWithSiwe();

const smartWalletClient = await sdk.crypto.wallet.getSmartWalletClient();
const message = await generateSiweMessage({
  address: smartWalletClient.account.address,
  chainId: 'eip155:' + smartWalletClient.chain?.id,
});

const signature = await smartWalletClient.signMessage({
  account: smartWalletClient.account,
  message: message,
});

await linkWithSiwe({
  message: message,
  chainId: 'eip155:' + smartWalletClient.chain?.id,
  signature,
  walletClientType: 'smart_wallet',
  connectorType: 'kernel',
});

5: Register in Accounts Smart Contract

const receipt = await sdk.crypto.accountContract.registerInAccounts();
const isRegistered = await sdk.crypto.accountContract.isWalletInAccounts();
console.log('Registered in contract:', isRegistered);

6: Register in API

Option A: Using Privy auth

import { getAccessToken, useIdentityToken } from '@privy-io/react-auth';

const accessToken = await getAccessToken();
const { identityToken } = useIdentityToken();

const userResponse = await sdk.auth.registerUser({
  privy: {
    accessToken: accessToken,
    identityToken: identityToken,
  },
  country: 'FR',
});

Option B: Using JWT token

// The API sees the wallet a few seconds after step 5, once its indexer has picked up the
// Accounts registration. Until then this returns 400 ErrorNotFound — wait and call again.
const userResponse = await sdk.auth.registerUser({
  authorizationToken: 'your-jwt-token',
  userWallet: userEoaAddress, // the user's EOA, sent as wallet_address
  country: 'FR',              // required by the type, not sent on this path
  initialData: {              // required for companies on the Full verification model
    profile: {
      first_name: 'Alex',
      last_name: 'Grey',
      date_of_birth: '1990-01-15',
      nationality: 'FR',
      phone_number: '+33612345678',
      email: '[email protected]',
    },
    residence_address: {
      line1: '10 Rue de Rivoli',
      city: 'Paris',
      post_code: '75001',
      country: 'FR',
    },
  },
});

Option A posts to POST /api/v1/user/retail; Option B posts to POST /api/v2/user.

7: Login to API

Option A: Using Privy auth

const authResponse = await sdk.auth.login({
  privy: {
    accessToken: accessToken,
    identityToken: identityToken,
  },
});
console.log('Access token:', authResponse.access_token);

Option B: Using JWT token

const authResponse = await sdk.auth.login({
  authorizationToken: 'your-jwt-token',
  userWallet: userEoaAddress, // sent as X-User-Wallet on every later call
});

SDK Modules

sdk.auth — Authentication Service

MethodDescription
login(params)Login retail user (Privy or JWT)
loginCompany(params)Login company/corporation
registerUser(params)Register retail user
registerCompany(params)Register company/corporation
getAccessToken()Get current access token (returns null if expired)
isAuthenticated()Check if user is authenticated
getUserWallet()Get current user wallet address
setUserWallet(wallet)Set user wallet address
setAuthState(response, userWallet?)Manually set auth state from an auth response
ensureAuthenticated()Throws AuthenticationError if not authenticated
clearAuth()Clear all authentication state
getAuthHeaders()Get Authorization and X-User-Wallet headers

Authentication Parameters:

All auth methods accept either Privy tokens or a JWT authorization token:

// Option 1: Privy authentication
{
  privy: {
    accessToken: string;   // Privy access token
    identityToken: string; // Privy identity token
  }
}

// Option 2: JWT authentication
{
  authorizationToken: string; // Your JWT token
}

Company Registration Parameters:

interface RegisterCompanyParams {
  privy?: PrivyAuth;
  authorizationToken?: string;
  companyAddress: string;
  companyName: string;
  registrationCountry: string;
  registrationNumber: string;
}

sdk.crypto.wallet — Wallet Service

MethodDescription
getSmartWalletAddress()Get Smart Wallet address
getSmartWalletClient()Get Kernel client with Policy
getSmartWalletClientWithoutPolicy()Get Kernel client without Policy
getSmartAccountSigner()Get signer for Smart Account
getMainWalletClient()Get main wallet client
sendUserOperationsAndWaitReceipt(callData, smartWalletClient?, config?)Send user operations and wait for receipt
sendUserOperationsWithNonceAndWaitReceipt(callData, nonce, config?)Send user operations with specific nonce
invalidateLocalCache()Clear cached wallet clients

config on both send methods is { waitOnChainBlocks?: number; applyUnwrapGasFloor?: boolean }. applyUnwrapGasFloor estimates the UserOperation first and raises callGasLimit to a gas floor when the estimate comes back lower. The transfer service sets it for the batches that unwrap a synthetic token before transferring (makeErc20TransferFull execution step, makeErc20TransferFinal, makeTransferWithoutDelayPolicy); plain transfers, policy installs and batch transfers keep the bundler estimate.

sdk.crypto.accountAbstraction — Account Abstraction Service

MethodDescription
isPolicyInstalled()Check if Execution Delay Policy is installed
isExecutorInstalled()Check if Funds Management Executor is installed
signInPolicyAndExecutor()Install Policy and Executor together
signInPolicy()Install Policy only
signInExecutor()Install Executor only
getExecutorInstallCall()Executor install as a batchable call (used by onboarding)
getPolicyInstallCall()Policy install as a batchable call (used by onboarding)

sdk.crypto.accountContract — Account Contract Service

MethodDescription
isWalletInAccounts()Check if wallet is registered in Accounts contract
registerInAccounts()Register wallet in Accounts contract (retail)
isWalletInCorporateAccounts()Check if wallet is registered in Corporate Accounts contract
registerInCorporateAccounts()Register wallet in Corporate Accounts contract (B2B)
getAccountRegistrationCall()Accounts registration as a batchable call (used by onboarding)

sdk.crypto.onboarding — Onboarding Service

MethodDescription
allInOneStepOnboarding()Executor install + policy switch + Accounts registration in a single UserOperation, signed by the pre-policy client. Use only when neither the executor nor the policy is installed; otherwise run the per-step methods.

sdk.crypto.transfer — Transfer Service

MethodDescription
makeErc20TransferFull(params)Full transfer in one call: request(...) → wait out the ExecutionDelayPolicy delay on-chain → submit the final execution under its custom nonce. No backend/withdrawal-request polling.
makeFullErc20Transfer(params)Full transfer driven by the backend: firstPart → poll withdrawal requests and wait for valid_after → final. Requires the Withdrawal API.
makeErc20TransferFirstPart(params)First part only: submit the ExecutionDelayPolicy request(...) (creates the withdrawal request)
makeErc20TransferFinal(callData)Second part only: complete the transfer with the request's calldata under its custom nonce
makeErc20TransferSynthetic(params)Transfer synthetic tokens directly (no unwrap, no delay policy)
makeTransferWithoutDelayPolicy(params)Unwrap a synthetic and transfer its base token in a single op, bypassing the ExecutionDelayPolicy. Used for the on-chain payment leg of an FX swap.
batchTransfer(params)Execute multiple transfers in a batch

Transfer Parameters:

interface Erc20TransferParams {
  tokenAddress: `0x${string}`;
  recipientAddress: `0x${string}`;
  amount: number;
}

interface BatchTransferParams {
  tokenAddress: `0x${string}`;
  responses: BatchTransferResponse[];
}

interface BatchTransferResponse {
  transaction_id: string; // GUID
  operation_id: string;   // GUID
  crypto_transfers: {
    address: string;
    precise_amount: string; // amount in the token's smallest unit
  }[];
}

// Used by makeTransferWithoutDelayPolicy (FX swap payment leg)
interface SwapTransferParams {
  tokenAddress: `0x${string}`;     // wrapped synthetic token to unwrap and send (e.g. WUSD)
  recipientAddress: `0x${string}`; // FX deposit address returned by swap.estimate
  amount: string;                  // amount of the source token (decimal string)
}

sdk.crypto.yield — Yield Service

MethodDescription
fetchYieldData()Get yield data (APY, pending, weekly, lifetime)
getYieldDataForGraphic()Get data for graph visualization
getWeeklyYield()Get weekly yield
withdraw()Withdraw accumulated yield
switchYieldToken(token)Switch yield token (TokenInfo, e.g. sdk.crypto.getToken('WEUR'))

Yield Data Structure:

interface IYieldData {
  apy: number;                 // annual rate in percent
  currentPendingYield: string; // accumulated yield pending withdrawal
  weeklyYield: string;         // weekly yield
  lifeTimeYield: string;       // claimed + pending
}

sdk.crypto.smartDepositAddress — Smart Deposit Addresses

MethodDescription
initializeSmartDepositAddresses(forceRefresh?)Create/get all deposit addresses
getAddresses()Get cached addresses
getDestinationChain()Rhino.fi chain code funds are bridged to
clearAddresses()Clear address cache

Destination chain follows the SDK chainId: 8453 / 84532 → BASE, 5042 / 5042002 → ARC. Rhino.fi has no testnet chains, so testnet ids resolve to the mainnet code.

The destination chain is itself requested as a deposit chain, so the EVM group also holds a same-chain address — ARC → ARC when the SDK runs on Arc, BASE → BASE on Base.

Deposit chains the destination rejects are skipped with a warning and the remaining chains in the group are still created: no bridgeable route (Rhino.fi DepositAddressNoBridgableTokens, e.g. USDT-only Kaia and TRON towards Arc) and chains Rhino.fi has not enabled for deposit addresses (DepositAddressChainsNotSupported).

Supported deposit networks:

  • EVM: the destination chain (Base or Arc), Base, Arbitrum, BNB Chain, Ethereum, Kaia, Polygon, Optimism
  • TRON
  • Solana
  • Stellar

sdk.api.withdrawal — Withdrawal API

MethodDescription
getWithdrawalRequests()Get list of withdrawal requests

sdk.api.baas — BaaS Module

Banking-as-a-Service module with the following sub-services:

sdk.api.baas.user — User Service

MethodDescription
getUser()Get current user
getUserV2()Get current user (v2)
createUser(request)Create a new user
createRetailUser(request)Create a retail user
validateRetailUser()Validate retail user
authorizeUser(params)Authorize user
updatePhoneNumber(request)Update phone number
confirmPhoneNumber(request)Confirm phone number via OTP
uploadDocument(formData)Upload verification document
updateFreshdeskId(request)Update Freshdesk ID
getSharingToken(request)Get sharing token
setSharingToken(request)Set sharing token
getVerificationToken()Get verification token
getVerificationLink()Get verification link

sdk.api.baas.activity — Activity Service

MethodDescription
getFeed(request?)Get activity feed
getById(request)Get activity by ID
getFullStatement(request)Get full statement
getRequestedErcWithdrawals()Get requested ERC withdrawals

sdk.api.baas.bank — Bank Service

MethodDescription
getAccounts(request?)Get bank accounts
activateAccount(request)Activate bank account
estimateTransfer(request)Estimate bank transfer
executeTransfer(request)Execute bank transfer
estimateCorridorTransferV2(corridor, request)Estimate corridor transfer (v2)
executeCorridorTransferV2(corridor, request)Execute corridor transfer (v2)

sdk.api.baas.swap — Swap Service (FX)

Circle FX stablecoin swaps. Three-step flow: estimate (issues a deposit address) → on-chain payment to that address (crypto.transfer.makeTransferWithoutDelayPolicy) → execute.

MethodDescription
estimate(request)Create a swap estimation and deposit address. Send exactly one of source_asset_amount / destination_asset_amount.
execute(request)Execute the swap after the source tokens were sent to the deposit address.
type SwapEstimateRequest = {
  source_asset_address: string;      // token to swap from (e.g. USDC)
  destination_asset_address: string; // token to receive (e.g. EURC)
  correlation_id?: string;
} & (
  | { source_asset_amount: string; destination_asset_amount?: never }
  | { destination_asset_amount: string; source_asset_amount?: never }
);

interface SwapEstimateResponse {
  estimation_id: string;
  destination_address: string;       // send source tokens here (preferred)
  deposit_address: string;           // @deprecated — mirrors destination_address
  source_asset_address: string;
  source_asset_amount: string;
  destination_asset_address: string;
  destination_asset_amount: string;
  trade_rate: string;
  expiration_time: string;           // RFC3339, estimation expiry
}

interface SwapExecuteRequest {
  estimation_id: string;
  payment_transaction_hash: string;  // hash of the on-chain payment
}

interface SwapExecuteResponse {
  trade_id: string;
}

sdk.api.baas.cards — Cards Service

MethodDescription
getCards(request?)Get user cards
getCard(cardId)Get card details
getCardTransactions(request?)Get card transactions
issuePlasticCard(request)Issue a plastic card
issueVirtualCard(request)Issue a virtual card
activateCard(cardId, request)Activate card
blockCard(cardId)Block card
unblockCard(cardId)Unblock card
closeCard(cardId)Close card
getCardDetails(cardId, request)Get card PAN and expiry
getCardCvv(cardId, request)Get card CVV
getCardPin(cardId, request)Get card PIN
changeCardLimit(cardId, request)Change card limit
changeCardName(cardId, request)Change card name
estimateCardTransfer(request)Estimate card transfer
executeCardTransfer(request)Execute card transfer
estimateCardWithdrawal(cardId, request)Estimate card withdrawal
executeCardWithdrawal(cardId, request)Execute card withdrawal
getActive3dsRequests()Get active 3DS requests
approve3dsRequest(transactionId)Approve 3DS request
decline3dsRequest(transactionId)Decline 3DS request
getDeliveryCountries()Get card delivery countries
getDeliveryMethods(country)Get card delivery methods
getOrderFees(type, country)Get card order fees
createOrderFeesInvoice(type, country, request)Create order fees invoice

Sensitive card data (PAN, CVV, PIN) requires an action token obtained via SMS OTP:

// 1. Request SMS OTP
const session = await sdk.api.baas.confirmation.requestSms({
  action_type: 'GetCardDetails',
});

// 2. Verify OTP → receive action token (UAT code is '000000')
const tokenRes = await sdk.api.baas.confirmation.verifySms({
  session_id: session.session_id,
  code: userInputCode,
});
const actionToken = tokenRes.token;

// 3. Use action token to retrieve sensitive data
const details = await sdk.api.baas.cards.getCardDetails(cardId, { action_token: actionToken });
// → { card_number: '4111111111111111', expiry_date: '12/2028' }

const cvv = await sdk.api.baas.cards.getCardCvv(cardId, { action_token: actionToken });
// → { cvv: '123' }

sdk.api.baas.config — Config Service

MethodDescription
getConfig()Get client app config

sdk.api.baas.confirmation — Confirmation Service

MethodDescription
verifySignature(request)Verify signature for action confirmation
requestSms(request)Request SMS confirmation code
verifySms(request)Verify SMS confirmation code

sdk.api.baas.recipients — Recipients Service

MethodDescription
getRecipients(request?)Get all recipients
getRecipientsByCatalog(request)Get recipients by catalog
getRecipientsByCurrency(request)Get recipients by currency
getRecipientsByName(request)Get recipients by name
getRecipientsByType(request)Get recipients by type
getRecipientById(recipientId)Get recipient by ID
createRecipient(request)Create recipient
createRecipientV2(request)Create recipient (v2)
updateRecipient(recipientId, request)Update recipient
deleteRecipient(recipientId)Delete recipient
createRecipientPaymentDetails(recipientId, request)Create payment details
updateRecipientPaymentDetails(recipientId, paymentDetailsId, request)Update payment details
deleteRecipientPaymentDetails(recipientId, paymentDetailsId)Delete payment details
incrementRecipientUsage(recipientId)Increment recipient usage counter

sdk.api.baas.rates — Rates Service

MethodDescription
getRates(request)Get exchange rates

sdk.api.baas.token — Token Service

MethodDescription
getToken(request)Get OAuth2 token

sdk.api.baas.wallet — Wallet Service

MethodDescription
getWallet(request?)Get wallet by ID or default
getWallets()Get all wallets
createGlobalWallet(request)Create global wallet

Examples

Full Token Transfer (single call, on-chain delay)

Runs the whole ExecutionDelayPolicy cycle in one call — no backend/withdrawal-request polling. tokenAddress must be a synthetic token (it is unwrapped, then its base token is transferred).

const finalTxHash = await sdk.crypto.transfer.makeErc20TransferFull({
  tokenAddress: '0x...', // synthetic token, e.g. WUSD
  recipientAddress: '0x...',
  amount: 100,
});

console.log('Final tx:', finalTxHash);

Full Token Transfer (backend-driven)

const result = await sdk.crypto.transfer.makeFullErc20Transfer({
  tokenAddress: '0x...', // synthetic token, e.g. WUSD
  recipientAddress: '0x...',
  amount: 100,
});

console.log('First part tx:', result.firstPartTxHash);
console.log('Final tx:', result.finalTxHash);
console.log('Success:', result.success);

Two-Step Transfer

// Step 1: Initiate transfer
const txHash = await sdk.crypto.transfer.makeErc20TransferFirstPart({
  tokenAddress: '0x...', // synthetic token, e.g. WUSD
  recipientAddress: '0x...',
  amount: 100,
});

// Step 2: Get withdrawal requests
const withdrawals = await sdk.api.withdrawal.getWithdrawalRequests();
const withdrawal = withdrawals.find(w => w.to_address === recipientAddress && w.amount === 100);

// Step 3: Complete transfer (after valid_after time)
await sdk.crypto.transfer.makeErc20TransferFinal(withdrawal.call_data);

Batch Transfer

const txHashes = await sdk.crypto.transfer.batchTransfer({
  tokenAddress: '0x...', // token to send
  responses: [
    {
      transaction_id: '6f1c2a4e-8b3d-4f5a-9c7e-1d2b3c4d5e6f',
      operation_id: '7a2d3b5f-9c4e-4a6b-8d1f-2e3c4d5e6f7a',
      crypto_transfers: [
        { address: '0x...', precise_amount: '100000000' },
        { address: '0x...', precise_amount: '50000000' },
      ],
    },
  ],
});

FX Swap (estimate → pay → execute)

// Step 1: estimate — issues a deposit address and locks a rate
const estimate = await sdk.api.baas.swap.estimate({
  source_asset_address: '0x...',      // e.g. USDC
  destination_asset_address: '0x...', // e.g. EURC
  source_asset_amount: '100',
});

// Step 2: on-chain payment to the deposit address (unwraps the synthetic, no delay policy)
const paymentTransactionHash = await sdk.crypto.transfer.makeTransferWithoutDelayPolicy({
  tokenAddress: '0x...', // wrapped synthetic of the source asset, e.g. WUSD
  recipientAddress: estimate.destination_address,
  amount: estimate.source_asset_amount,
});

// Step 3: execute — settles the swap
const { trade_id } = await sdk.api.baas.swap.execute({
  estimation_id: estimate.estimation_id,
  payment_transaction_hash: paymentTransactionHash,
});

Yield Operations

const yieldData = await sdk.crypto.yield.fetchYieldData();
console.log('APY:', yieldData.apy);
console.log('Pending yield:', yieldData.currentPendingYield);
await sdk.crypto.yield.withdraw();

Smart Deposit Addresses

const addresses = await sdk.crypto.smartDepositAddress.initializeSmartDepositAddresses();

addresses.forEach(addr => {
  console.log(`Chain: ${addr.depositChain}`);
  console.log(`Address: ${addr.depositAddress}`);
  console.log(`Tokens: ${addr.supportedTokens.join(', ')}`);
});

Types

import type {
  SDKConfig,
  SDKEnvironment,
  Logger,
  TokenInfo,
  ContractAddresses,
  Hex,
  TransactionHash,
  MainWalletClient,
  PrivyAuth,
  LoginUserParams,
  LoginCompanyParams,
  RegisterUserParams,
  RegisterCompanyParams,
  AuthResponse,
  RegisterUserResponse,
} from '@wirexapp/wpay-baas-sdk';

Error Handling

The SDK provides typed error classes:

ErrorDescription
SDKErrorBase error class
ConfigurationErrorInvalid configuration
NetworkErrorNetwork/HTTP errors
ContractErrorSmart contract interaction errors
WalletErrorWallet-related errors
TransactionErrorTransaction execution errors
AuthenticationErrorAuthentication failures
ValidationErrorInput validation errors
import { SDKError, AuthenticationError } from '@wirexapp/wpay-baas-sdk';

try {
  await sdk.auth.login({ authorizationToken: 'token' });
} catch (error) {
  if (error instanceof AuthenticationError) {
    // handle auth error
  }
}

Next Steps

GuideDescription
Getting StartedPlatform overview and environments
Wallet DeploymentFull ZeroDev / Crossmint deployment options
Developer OnboardingUser registration and KYC flows
AuthenticationToken exchange and header management

Did this page help you?