Skip to main content
The OneBalance API provides chain abstraction capabilities that enable seamless token swaps and transfers across multiple blockchains without requiring users to switch networks or hold native gas tokens.

API client setup

The application uses an Axios-based API client configured to proxy requests through Next.js API routes:
lib/api.ts
import axios from 'axios';

export const apiClient = axios.create({
  baseURL: '/api',
  headers: {
    'Content-Type': 'application/json',
  },
});
This client is used by all API modules to make authenticated requests to the OneBalance backend.

API modules

The API is organized into specialized modules, each handling a specific domain:

Quotes API

Handle quote generation and execution for swaps and transfers.
lib/api/quotes.ts
import { apiClient } from '@/lib/api';
import type { QuoteRequest, Quote, QuoteStatus } from '@/lib/types/quote';

export const quotesApi = {
  getQuote: async (request: QuoteRequest): Promise<Quote> => {
    const response = await apiClient.post('/v1/quote', request);
    return response.data;
  },

  executeQuote: async (quote: Quote): Promise<any> => {
    const response = await apiClient.post('/quotes/execute-quote', quote);
    return response.data;
  },

  getQuoteStatus: async (quoteId: string): Promise<QuoteStatus> => {
    const response = await apiClient.get(`/status/get-execution-status?quoteId=${quoteId}`);
    return response.data;
  },
};
Key endpoints:
  • POST /v1/quote - Request a quote for a swap or transfer
  • POST /quotes/execute-quote - Execute a signed quote
  • GET /status/get-execution-status - Check quote execution status

Assets API

Retrieve information about supported aggregated assets.
lib/api/assets.ts
import { apiClient } from '@/lib/api';
import { Asset } from '@/lib/types/assets';

export const assetsApi = {
  getAssets: async (): Promise<Asset[]> => {
    const response = await apiClient.get('/assets/list');
    return response.data;
  },
};
Endpoint:
  • GET /assets/list - Get all supported aggregated assets

Balances API

Track aggregated balances across multiple chains.
lib/api/balances.ts
import { apiClient } from '@/lib/api';
import { BalancesResponse } from '@/lib/types/balances';

export const balancesApi = {
  getAggregatedBalance: async (address: string): Promise<BalancesResponse> => {
    const response = await apiClient.get(`/v2/balances/aggregated-balance?address=${address}`);
    return response.data;
  },
};
Endpoint:
  • GET /v2/balances/aggregated-balance - Get aggregated balance for an address

Chains API

Get information about supported blockchain networks.
lib/api/chains.ts
import { apiClient } from '@/lib/api';
import { Chain } from '@/lib/types/chains';

export const chainsApi = {
  getChains: async (): Promise<Chain[]> => {
    const response = await apiClient.get('/chains/supported-list');
    return response.data;
  },
};
Endpoint:
  • GET /chains/supported-list - Get all supported chains

Account API

Manage account information and address prediction.
lib/api/account.ts
import { apiClient } from '@/lib/api';

export const accountApi = {
  predictAddress: async (sessionAddress: string, adminAddress: string): Promise<string> => {
    const response = await apiClient.post('/account/predict-address', {
      sessionAddress,
      adminAddress,
    });
    return response.data?.predictedAddress;
  },
};
Endpoint:
  • POST /account/predict-address - Get predicted account address

Transactions API

Retrieve transaction history and status.
lib/api/transactions.ts
import { apiClient } from '@/lib/api';
import { TransactionHistoryResponse, TransactionHistoryParams } from '@/lib/types/transaction';

export const transactionsApi = {
  getTransactionHistory: async (
    params: TransactionHistoryParams
  ): Promise<TransactionHistoryResponse> => {
    const queryParams = new URLSearchParams({
      user: params.user,
      limit: params.limit.toString(),
    });

    if (params.continuation) {
      queryParams.append('continuation', params.continuation);
    }

    const response = await apiClient.get(`/status/get-tx-history?${queryParams.toString()}`);
    return response.data;
  },
};
Endpoint:
  • GET /status/get-tx-history - Get paginated transaction history

Quote workflow

The quote workflow is the core of the chain abstraction experience:
1

Request a quote

Submit a quote request with source and destination assets
const quoteRequest: QuoteRequest = {
  from: {
    account: {
      sessionAddress: wallet.address,
      adminAddress: wallet.address,
      accountAddress: predictedAddress,
    },
    asset: {
      assetId: 'ob:usdc',
    },
    amount: '1000000', // 1 USDC (6 decimals)
  },
  to: {
    asset: {
      assetId: 'ob:eth',
    },
  },
};

const quote = await quotesApi.getQuote(quoteRequest);
2

Sign the quote

Sign chain operations using the user’s wallet
const signedQuote = await signQuote(quote, embeddedWallet);
3

Execute the quote

Submit the signed quote for execution
await quotesApi.executeQuote(signedQuote);
4

Poll for status

Monitor execution status until completion
const status = await quotesApi.getQuoteStatus(quote.id);
// Poll every 1-2 seconds until status is COMPLETED or FAILED

Quote types

Quote request structure

lib/types/quote.ts
export interface QuoteRequest {
  from: {
    account: {
      sessionAddress: string;    // Wallet address for signing
      adminAddress: string;       // Admin wallet address
      accountAddress: string;     // Predicted OneBalance account
    };
    asset: {
      assetId: string;           // Aggregated asset ID (e.g., 'ob:usdc')
    };
    amount: string;              // Amount in smallest unit
  };
  to: {
    asset: {
      assetId: string;           // Destination asset ID
    };
    account?: string;            // Optional CAIP account ID for transfers
    amount?: string;             // Optional for exact output quotes
  };
}

Quote response structure

lib/types/quote.ts
export interface Quote {
  id: string;                              // Unique quote ID
  account: Account;                         // Account information
  originToken: TokenInfo;                   // Source token details
  destinationToken: TokenInfo;              // Destination token details
  expirationTimestamp: string;              // Unix timestamp (seconds)
  tamperProofSignature: string;             // Server signature
  originChainsOperations: ChainOperation[]; // Operations to execute on source chains
  destinationChainOperation?: ChainOperation; // Optional destination operation
}
Quotes expire after 30 seconds. Always check the expirationTimestamp before executing.

Chain operation structure

lib/types/quote.ts
export interface ChainOperation {
  userOp: {
    sender: string;
    nonce: string;
    callData: string;
    callGasLimit: string;
    verificationGasLimit: string;
    preVerificationGas: string;
    maxFeePerGas: string;
    maxPriorityFeePerGas: string;
    paymaster: string;
    paymasterVerificationGasLimit: string;
    paymasterPostOpGasLimit: string;
    paymasterData: string;
    signature: string;  // Populated after signing
  };
  typedDataToSign: {  // EIP-712 typed data
    domain: unknown;
    types: unknown;
    primaryType: string;
    message: unknown;
  };
  assetType: string;  // CAIP-19 asset identifier
  amount: string;
}

Custom hooks

The application provides React hooks that wrap the API modules:

useQuotes hook

Manages quote requests, signing, and execution with automatic status polling.
lib/hooks/useQuotes.ts
import { useQuotes } from '@/lib/hooks';

function SwapComponent() {
  const {
    quote,
    status,
    loading,
    error,
    isPolling,
    getQuote,
    executeQuote,
    resetQuote,
  } = useQuotes();

  const handleSwap = async () => {
    // Request quote
    await getQuote({
      fromTokenAmount: '1000000',
      fromAggregatedAssetId: 'ob:usdc',
      toAggregatedAssetId: 'ob:eth',
    });

    // Execute quote (signs automatically)
    await executeQuote();
  };

  return (
    <div>
      {loading && <p>Processing...</p>}
      {isPolling && <p>Transaction in progress...</p>}
      {status?.status === 'COMPLETED' && <p>Success!</p>}
    </div>
  );
}
See the full implementation at lib/hooks/useQuotes.ts:1.

useBalances hook

Fetches aggregated balances across chains.
import { useBalances } from '@/lib/hooks';

function BalanceComponent() {
  const { balances, loading, error, fetchBalances } = useBalances(predictedAddress);

  return (
    <div>
      {balances?.totalBalance?.fiatValue && (
        <p>Total: ${balances.totalBalance.fiatValue.toFixed(2)}</p>
      )}
    </div>
  );
}
See the full implementation at lib/hooks/useBalances.ts:1.

Error handling

The API proxy handles errors consistently:
app/api/[...path]/route.ts
try {
  const response = await fetch(apiUrl.toString(), {
    headers: {
      'Content-Type': 'application/json',
      'x-api-key': API_KEY,
    },
  });

  const data = await response.json();

  // Forward error status codes
  if (data.error && data.statusCode) {
    return NextResponse.json(data, { status: data.statusCode });
  }

  if (!response.ok) {
    return NextResponse.json(data, { status: response.status });
  }

  return NextResponse.json(data);
} catch (error) {
  return NextResponse.json(
    { message: 'Failed to fetch data', error },
    { status: 400 }
  );
}

Best practices

Cache quote data

Store quote responses to avoid redundant API calls during the 30-second validity window.

Handle expiration

Always validate expirationTimestamp before executing quotes to prevent failed transactions.

Poll efficiently

Use 1-2 second intervals for status polling and stop immediately on COMPLETED or FAILED status.

Show progress

Display loading states during quote requests, signing, and execution to improve UX.

Next steps

Privy wallet integration

Learn how to integrate Privy for wallet signing and authentication

Build docs developers (and LLMs) love