Creates a new Account Activity service instance
+Configuration options including messenger
+Readonly nameThe name of the service.
+Subscribe to account activity (transactions and balance updates) +Address should be in CAIP-10 format (e.g., "eip155:0:0x1234..." or "solana:0:ABC123...")
+Account subscription configuration with address
+Unsubscribe from account activity for specified address +Address should be in CAIP-10 format (e.g., "eip155:0:0x1234..." or "solana:0:ABC123...")
+Account subscription configuration with address to unsubscribe
+Accounts API Client. +Provides methods for interacting with the Accounts API.
+Protected Readonly clientProtected Readonly clientProtected Optional Readonly getGet the underlying QueryClient instance. +Exposed for cache management operations.
+The QueryClient instance.
+Protected fetchInternal HTTP fetch method with authentication and error handling.
+The base URL for the API.
+The API endpoint path.
+Optional options: InternalFetchOptionsOptional fetch configuration.
+The parsed JSON response.
+Get account address relationship (v1 endpoint).
+The chain ID.
+The from address.
+The to address.
+Optional options: FetchOptionsFetch options including cache settings.
+The account relationship result.
+Get account transactions (v1 endpoint).
+The account address.
+Optional queryOptions: { Query filter options.
+Optional chainChain IDs to filter by.
+Optional cursor?: stringPagination cursor.
+Optional endEnd timestamp filter.
+Optional sortSort direction (ASC/DESC).
+Optional startStart timestamp filter.
+Optional options: FetchOptionsFetch options including cache settings.
+The account transactions response.
+Get list of supported networks (v1 endpoint).
+Optional options: FetchOptionsFetch options including cache settings.
+The list of supported networks.
+Get a specific transaction by hash (v1 endpoint).
+The chain ID.
+The transaction hash.
+Optional queryOptions: { Query filter options.
+Optional includeWhether to include logs.
+Optional includeWhether to include transaction metadata.
+Optional includeWhether to include value transfers.
+Optional lang?: stringLanguage for metadata.
+Optional options: FetchOptionsFetch options including cache settings.
+The transaction details.
+Get NFTs owned by an account (v2 endpoint).
+The account address.
+Optional queryOptions: { Query filter options.
+Optional cursor?: stringPagination cursor.
+Optional networks?: number[]Networks to filter by.
+Optional options: FetchOptionsFetch options including cache settings.
+The NFTs response.
+Get ERC20 tokens detected for an account (v2 endpoint).
+The account address.
+Optional queryOptions: { Query filter options.
+Optional networks?: number[]Networks to filter by.
+Optional options: FetchOptionsFetch options including cache settings.
+The tokens response.
+Get active networks by CAIP-10 account IDs (v2 endpoint).
+Array of CAIP-10 account IDs.
+Optional queryOptions: { Query filter options.
+Optional filterMMListWhether to filter MM list tokens.
+Optional networks?: string[]Networks to filter by.
+Optional options: FetchOptionsFetch options including cache settings.
+The active networks response.
+Get account balances for a single address (v2 endpoint).
+The account address.
+Optional queryOptions: { Query filter options.
+Optional networks?: number[]Networks to filter by.
+Optional options: FetchOptionsFetch options including cache settings.
+The account balances response.
+Get account balances with additional options (v2 endpoint).
+The account address.
+Optional queryOptions: { Query filter options.
+Optional filterWhether to filter supported tokens.
+Optional includeWhether to include staked assets.
+Optional includeToken addresses to include.
+Optional networks?: number[]Networks to filter by.
+Optional options: FetchOptionsFetch options including cache settings.
+The account balances response.
+Get list of supported networks (v2 endpoint).
+Optional options: FetchOptionsFetch options including cache settings.
+The list of supported networks.
+Get balances for multiple accounts (v4 endpoint).
+Array of account addresses.
+Optional queryOptions: { Query filter options.
+Optional networks?: number[]Networks to filter by.
+Optional options: FetchOptionsFetch options including cache settings.
+The multi-account balances response.
+Get multi-account transactions (v4 endpoint).
+Array of CAIP-10 account IDs.
+Optional queryOptions: { Query filter options.
+Optional cursor?: stringPagination cursor.
+Optional includeWhether to include logs.
+Optional includeWhether to include transaction metadata.
+Optional includeWhether to include value transfers.
+Optional networks?: string[]Networks to filter by.
+Optional sortSort direction (ASC/DESC).
+Optional options: FetchOptionsFetch options including cache settings.
+The multi-account transactions response.
+Get balances for multiple accounts using CAIP-10 IDs (v5 endpoint).
+Array of CAIP-10 account IDs.
+Optional queryOptions: { Query filter options.
+Optional filterMMListWhether to filter MM list tokens.
+Optional includeWhether to include staked assets.
+Optional networks?: string[]Networks to filter by.
+Optional options: FetchOptionsFetch options including cache settings.
+The multi-account balances response.
+Invalidate the cached auth token. +Call this when the user logs out or the token expires.
+Uses resetQueries() instead of invalidateQueries() to completely remove +the cached value, ensuring the next request fetches a fresh token immediately.
+MetaMask API Platform Client with TanStack Query caching. +Provides cached access to all MetaMask backend APIs through a unified interface.
+Access API methods through the sub-clients:
+client.accounts - Accounts API (balances, transactions, NFTs, etc.)client.prices - Prices API (spot prices, exchange rates, historical prices)client.token - Token API (token metadata, trending, top gainers)client.tokens - Tokens API (bulk asset operations, supported networks)Readonly accountsAccounts API client. +Provides methods for balances, transactions, relationships, NFTs, and token discovery.
+Readonly pricesPrices API client. +Provides methods for spot prices, exchange rates, and historical prices.
+Readonly tokenToken API client. +Provides methods for token metadata, networks, trending tokens, and top assets.
+Readonly tokensTokens API client. +Provides methods for bulk asset operations and supported networks.
+Get the underlying QueryClient (for advanced usage).
+The underlying QueryClient instance.
+Get cached data for a query key.
+The query key to look up.
+The cached data or undefined.
+Invalidate the cached auth token. +Call this when the user logs out or the token expires.
+Uses resetQueries() instead of invalidateQueries() to completely remove +the cached value, ensuring the next request fetches a fresh token immediately.
+Set cached data for a query key.
+The query key to set data for.
+The data to cache.
+WebSocket Service with automatic reconnection, session management and direct callback routing
+Connection Management:
+Platform Responsibilities:
+Real-Time Performance Optimizations:
+Creates a new WebSocket service instance
+Configuration options for the WebSocket service
+Readonly nameThe name of the service.
+Register a callback for specific channels (local callback only, no server subscription)
+Key Difference from subscribe():
addChannelCallback(): Registers a local callback without creating a server-side subscription.
+The callback triggers on ANY message matching the channel name, regardless of subscriptionId.
+Useful for system-wide notifications or when you don't control the subscription lifecycle.
subscribe(): Creates a proper server-side subscription with a subscriptionId.
+The callback only triggers for messages with the matching subscriptionId.
+Includes proper lifecycle management (unsubscribe, automatic cleanup on disconnect).
When to use addChannelCallback():
When to use subscribe() instead:
Channel callback configuration
+Function to call when channel matches
+Channel name to match exactly
+// Listen to system notifications (no server subscription needed)
webSocketService.addChannelCallback({
channelName: 'system-notifications.v1',
callback: (notification) => {
console.log('System notification:', notification.data);
}
});
// For account-specific subscriptions, use subscribe() instead:
// const sub = await webSocketService.subscribe({
// channels: ['account-activity.v1.eip155:0:0x1234...'],
// callback: (notification) => { ... }
// });
+
+subscribe for creating proper server-side subscriptions with lifecycle management
+Establishes WebSocket connection with smart reconnection behavior
+Connection Requirements (all must be true):
+Platform code should call this when app opens/foregrounds. +Automatically called on KeyringController:unlock event.
+Promise that resolves when connection is established
+Finds all subscriptions that have channels starting with the specified prefix
+The channel prefix to search for (e.g., "account-activity.v1")
+Array of subscription info for matching subscriptions
+Forces a WebSocket reconnection to clean up subscription state
+This method is useful when subscription state may be out of sync and needs to be reset. +It performs a controlled disconnect-then-reconnect sequence:
+Use cases:
+Promise that resolves when disconnection is complete (reconnection is scheduled)
+Get all registered channel callbacks (for debugging)
+Array of all registered channel callbacks
+Gets current connection information
+Current connection status and details
+Gets all subscription information for a specific channel
+The channel name to look up
+Array of subscription details for all subscriptions containing the channel
+Sends a message through the WebSocket (fire-and-forget, no response expected)
+This is a low-level method for sending messages without waiting for a response.
+Most consumers should use sendRequest() instead, which handles request-response
+correlation and provides proper error handling with timeouts.
Use this method only when:
+The message to send
+Error if WebSocket is not connected or send fails
+sendRequest for request-response pattern with automatic correlation
+Sends a request and waits for a correlated response (recommended for most use cases)
+This is the recommended high-level method for request-response communication. +It automatically handles:
+The request message (can include optional requestId for testing)
+Promise that resolves with the response data
+Error if WebSocket is not connected, request times out, or response indicates failure
+sendMessage for fire-and-forget messaging without response handling
+Create and manage a subscription with server-side registration (recommended for most use cases)
+This is the recommended subscription API for high-level services. It creates a proper +server-side subscription and routes notifications based on subscriptionId.
+Key Features:
+When to use subscribe():
When to use addChannelCallback() instead:
Subscription configuration
+Handler for incoming notifications
+Channel type with version (e.g., 'account-activity.v1') for tracing and monitoring
+Channel names to subscribe to
+Optional requestOptional request ID for testing (will generate UUID if not provided)
+Subscription object with unsubscribe method
+// AccountActivityService usage
const subscription = await webSocketService.subscribe({
channels: ['account-activity.v1.eip155:0:0x1234...'],
callback: (notification) => {
this.handleAccountActivity(notification.data);
}
});
// Later, clean up
await subscription.unsubscribe();
+
+addChannelCallback for local callbacks without server-side subscription
+Readonly bodyOptional stackReadonly statusReadonly statusReadonly urlStatic Optional prepareOptional override for formatting stack traces
+Static stackStatic capturePrices API Client. +Provides methods for interacting with the Price API.
+Protected Readonly clientProtected Readonly clientProtected Optional Readonly getGet the underlying QueryClient instance. +Exposed for cache management operations.
+The QueryClient instance.
+Protected fetchInternal HTTP fetch method with authentication and error handling.
+The base URL for the API.
+The API endpoint path.
+Optional options: InternalFetchOptionsOptional fetch configuration.
+The parsed JSON response.
+Get price supported networks (v1 endpoint).
+Optional options: FetchOptionsFetch options including cache settings.
+The supported networks response.
+Get price supported networks in CAIP format (v2 endpoint).
+Optional options: FetchOptionsFetch options including cache settings.
+The supported networks response.
+Get crypto exchange rates (v1 endpoint).
+Optional options: FetchOptionsFetch options including cache settings.
+The exchange rates response.
+Get all exchange rates for a base currency (v1 endpoint).
+The base currency code.
+Optional options: FetchOptionsFetch options including cache settings.
+The exchange rates response.
+Get fiat exchange rates (v1 endpoint).
+Optional options: FetchOptionsFetch options including cache settings.
+The exchange rates response.
+Get historical price graph data by CoinGecko coin ID (v1 endpoint).
+The CoinGecko coin ID.
+Optional queryOptions: { Query options.
+Optional currency?: SupportedCurrencyThe currency for prices.
+Optional includeOHLC?: booleanWhether to include OHLC data.
+Optional options: FetchOptionsFetch options including cache settings.
+The historical price graph response.
+Get historical price graph data by token address (v1 endpoint).
+The chain ID (hex format).
+The token address.
+Optional queryOptions: { Query options.
+Optional currency?: SupportedCurrencyThe currency for prices.
+Optional includeOHLC?: booleanWhether to include OHLC data.
+Optional options: FetchOptionsFetch options including cache settings.
+The historical price graph response.
+Get historical prices for a single token (v1 endpoint).
+The chain ID (hex format).
+The token address.
+Optional queryOptions: { Query options.
+Optional currency?: SupportedCurrencyThe currency for prices.
+Optional timeThe time range.
+Optional options: FetchOptionsFetch options including cache settings.
+The historical prices response.
+Get historical prices by CoinGecko coin ID (v1 endpoint).
+The CoinGecko coin ID.
+Optional queryOptions: { Query options.
+Optional currency?: SupportedCurrencyThe currency for prices.
+Optional from?: numberStart timestamp.
+Optional timeThe time period.
+Optional to?: numberEnd timestamp.
+Optional options: FetchOptionsFetch options including cache settings.
+The historical prices response.
+Get historical prices for tokens on a chain (v1 endpoint).
+The chain ID (hex format).
+Array of token addresses.
+Optional queryOptions: { Query options.
+Optional currency?: SupportedCurrencyThe currency for prices.
+Optional from?: numberStart timestamp.
+Optional timeThe time period.
+Optional to?: numberEnd timestamp.
+Optional options: FetchOptionsFetch options including cache settings.
+The historical prices response.
+Get spot price for a single CoinGecko coin ID (v1 endpoint).
+The CoinGecko coin ID.
+The currency for prices.
+Optional options: FetchOptionsFetch options including cache settings.
+The spot price data.
+Get spot prices by CoinGecko coin IDs (v1 endpoint).
+Array of CoinGecko coin IDs.
+Optional options: FetchOptionsFetch options including cache settings.
+The spot prices by coin ID.
+Get spot price for a single token (v1 endpoint).
+The chain ID (hex format).
+The token address.
+The currency for prices.
+Optional options: FetchOptionsFetch options including cache settings.
+The market data or undefined.
+Get spot prices for tokens on a chain (v1 endpoint).
+The chain ID (hex format).
+Array of token addresses.
+Optional queryOptions: { Query options.
+Optional currency?: SupportedCurrencyThe currency for prices.
+Optional includeWhether to include market data.
+Optional options: FetchOptionsFetch options including cache settings.
+The token prices by address.
+Get spot prices for tokens on a chain with market data (v2 endpoint).
+The chain ID (hex format).
+Array of token addresses.
+Optional queryOptions: { Query options.
+Optional currency?: SupportedCurrencyThe currency for prices.
+Optional includeWhether to include market data.
+Optional options: FetchOptionsFetch options including cache settings.
+The spot prices with market data.
+Get historical prices by CAIP-19 asset ID (v3 endpoint).
+The CAIP-2 chain ID.
+The asset type portion of CAIP-19.
+Optional queryOptions: { Query options.
+Optional currency?: SupportedCurrencyThe currency for prices.
+Optional from?: numberStart timestamp.
+Optional interval?: "5m" | "hourly" | "daily"Data interval.
+Optional timeThe time period.
+Optional to?: numberEnd timestamp.
+Optional options: FetchOptionsFetch options including cache settings.
+The historical prices response.
+Get spot prices by CAIP-19 asset IDs (v3 endpoint).
+Array of CAIP-19 asset IDs.
+Optional queryOptions: { Query options.
+Optional cacheWhether to use cache only.
+Optional currency?: SupportedCurrencyThe currency for prices.
+Optional includeWhether to include market data.
+Optional options: FetchOptionsFetch options including cache settings.
+The spot prices response.
+Invalidate the cached auth token. +Call this when the user logs out or the token expires.
+Uses resetQueries() instead of invalidateQueries() to completely remove +the cached value, ensuring the next request fetches a fresh token immediately.
+Token API Client. +Provides methods for interacting with the Token API.
+Protected Readonly clientProtected Readonly clientProtected Optional Readonly getGet the underlying QueryClient instance. +Exposed for cache management operations.
+The QueryClient instance.
+Protected fetchInternal HTTP fetch method with authentication and error handling.
+The base URL for the API.
+The API endpoint path.
+Optional options: InternalFetchOptionsOptional fetch configuration.
+The parsed JSON response.
+Get network by chain ID.
+The chain ID.
+Optional options: FetchOptionsFetch options including cache settings.
+The network info.
+Get all networks.
+Optional options: FetchOptionsFetch options including cache settings.
+Array of network info.
+Get token description.
+The chain ID.
+The token address.
+Optional options: FetchOptionsFetch options including cache settings.
+The token description or undefined.
+Get token list for a chain.
+The chain ID.
+Optional queryOptions: { Query options.
+Optional includeInclude address.
+Optional includeInclude aggregators data.
+Optional includeInclude asset type data.
+Optional includeERC20Include ERC20 permit data.
+Optional includeInclude icon URL.
+Optional includeInclude name.
+Optional includeInclude occurrences data.
+Optional includeInclude storage data.
+Optional includeInclude token fees data.
+Optional options: FetchOptionsFetch options including cache settings.
+Array of token metadata.
+Get top assets for a chain.
+The chain ID.
+Optional options: FetchOptionsFetch options including cache settings.
+Array of top assets.
+Get suggested occurrence floors for all chains.
+Optional options: FetchOptionsFetch options including cache settings.
+The suggested occurrence floors response.
+Get token metadata by address.
+The chain ID.
+The token address.
+Optional queryOptions: { Query options.
+Optional includeInclude address.
+Optional includeInclude aggregators data.
+Optional includeInclude asset type data.
+Optional includeERC20Include ERC20 permit data.
+Optional includeInclude icon URL.
+Optional includeInclude name.
+Optional includeInclude occurrences data.
+Optional includeInclude storage data.
+Optional includeInclude token fees data.
+Optional options: FetchOptionsFetch options including cache settings.
+The token metadata or undefined.
+Get popular tokens (v3 endpoint).
+Array of chain IDs.
+Optional queryOptions: { Query options.
+Optional blockRegion filter (global/us).
+Optional maxMaximum market cap filter.
+Optional maxMaximum 24h volume filter.
+Optional minMinimum liquidity filter.
+Optional minMinimum market cap filter.
+Optional minMinimum 24h volume filter.
+Optional options: FetchOptionsFetch options including cache settings.
+Array of popular tokens.
+Get top gainers/losers (v3 endpoint).
+Array of chain IDs.
+Optional queryOptions: { Query options.
+Optional blockRegion filter (global/us).
+Optional maxMaximum market cap filter.
+Optional maxMaximum 24h volume filter.
+Optional minMinimum liquidity filter.
+Optional minMinimum market cap filter.
+Optional minMinimum 24h volume filter.
+Optional sort?: TopGainersSortOptionSort option.
+Optional options: FetchOptionsFetch options including cache settings.
+Array of top gainer tokens.
+Get trending tokens (v3 endpoint).
+Array of chain IDs.
+Optional queryOptions: { Query options.
+Optional maxMaximum market cap filter.
+Optional maxMaximum 24h volume filter.
+Optional minMinimum liquidity filter.
+Optional minMinimum market cap filter.
+Optional minMinimum 24h volume filter.
+Optional sortSort option.
+Optional options: FetchOptionsFetch options including cache settings.
+Array of trending tokens.
+Invalidate the cached auth token. +Call this when the user logs out or the token expires.
+Uses resetQueries() instead of invalidateQueries() to completely remove +the cached value, ensuring the next request fetches a fresh token immediately.
+Tokens API Client. +Provides methods for interacting with the Tokens API.
+Protected Readonly clientProtected Readonly clientProtected Optional Readonly getGet the underlying QueryClient instance. +Exposed for cache management operations.
+The QueryClient instance.
+Protected fetchInternal HTTP fetch method with authentication and error handling.
+The base URL for the API.
+The API endpoint path.
+Optional options: InternalFetchOptionsOptional fetch configuration.
+The parsed JSON response.
+Get token supported networks (v1 endpoint).
+Optional options: FetchOptionsFetch options including cache settings.
+The supported networks response.
+Get token supported networks (v2 endpoint). +Returns both fullSupport and partialSupport networks.
+Optional options: FetchOptionsFetch options including cache settings.
+The supported networks response.
+Fetch assets by IDs (v3) with caching.
+Array of CAIP-19 asset IDs.
+Optional queryOptions: V3AssetsQueryOptionsQuery options to include additional data in response.
+Optional fetchOptions: FetchOptionsFetch options including cache settings.
+Array of asset responses.
+Invalidate the cached auth token. +Call this when the user logs out or the token expires.
+Uses resetQueries() instead of invalidateQueries() to completely remove +the cached value, ensuring the next request fetches a fresh token immediately.
+WebSocket connection states
+This value is no longer used internally and will be removed in a future major release
+TThis value is no longer used internally and will be removed in a future major release
+Factory function to create an ApiPlatformClient.
+Configuration options for the client.
+A new ApiPlatformClient instance.
+@metamask/core-backendCore backend services for MetaMask, serving as the data layer between Backend services (REST APIs, WebSocket services) and Frontend applications (Extension, Mobile). Provides authenticated real-time data delivery including account activity monitoring, price updates, and WebSocket connection management with type-safe controller integration.
+@metamask/core-backend
+yarn add @metamask/core-backend
+
+or
+npm install @metamask/core-backend
+
+WebSocket for Real-time Updates:
+import {
BackendWebSocketService,
AccountActivityService,
} from '@metamask/core-backend';
// Initialize Backend WebSocket service
const backendWebSocketService = new BackendWebSocketService({
messenger: backendWebSocketServiceMessenger,
url: 'wss://api.metamask.io/ws',
timeout: 15000,
requestTimeout: 20000,
});
// Initialize Account Activity service
const accountActivityService = new AccountActivityService({
messenger: accountActivityMessenger,
});
// Connect and subscribe to account activity
await backendWebSocketService.connect();
await accountActivityService.subscribe({
address: 'eip155:0:0x742d35cc6634c0532925a3b8d40c4e0e2c6e4e6',
});
// Listen for real-time updates
messenger.subscribe('AccountActivityService:transactionUpdated', (tx) => {
console.log('New transaction:', tx);
});
messenger.subscribe(
'AccountActivityService:balanceUpdated',
({ address, updates }) => {
console.log(`Balance updated for ${address}:`, updates);
},
);
+
+HTTP API for REST Requests:
+import { ApiPlatformClient } from '@metamask/core-backend';
// Create API client
const apiClient = new ApiPlatformClient({
clientProduct: 'metamask-extension',
getBearerToken: async () => authController.getBearerToken(),
});
// Fetch data with automatic caching and deduplication
const balances = await apiClient.accounts.fetchV5MultiAccountBalances([
'eip155:1:0x742d35cc6634c0532925a3b8d40c4e0e2c6e4e6',
]);
const prices = await apiClient.prices.fetchV3SpotPrices([
'eip155:1/slip44:60', // ETH
'eip155:1/erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', // USDC
]);
+
+// Coordinate with TokenBalancesController for fallback polling
messenger.subscribe(
'BackendWebSocketService:connectionStateChanged',
(info) => {
if (info.state === 'CONNECTED') {
// Reduce polling when WebSocket is active
messenger.call(
'TokenBalancesController:updateChainPollingConfigs',
{ '0x1': { interval: 600000 } }, // 10 min backup polling
{ immediateUpdate: false },
);
} else {
// Increase polling when WebSocket is down
const defaultInterval = messenger.call(
'TokenBalancesController:getDefaultPollingInterval',
);
messenger.call(
'TokenBalancesController:updateChainPollingConfigs',
{ '0x1': { interval: defaultInterval } },
{ immediateUpdate: true },
);
}
},
);
// Listen for account changes and manage subscriptions
messenger.subscribe(
'AccountsController:selectedAccountChange',
async (selectedAccount) => {
if (selectedAccount) {
await accountActivityService.subscribe({
address: selectedAccount.address,
});
}
},
);
+
+graph TD
subgraph "FRONTEND"
subgraph "Presentation Layer"
FE[Frontend Applications<br/>MetaMask Extension, Mobile, etc.]
end
subgraph "Integration Layer"
IL[Controllers, State Management, UI]
end
subgraph "Data layer (core-backend)"
subgraph "Domain Services"
AAS[AccountActivityService]
PUS[PriceUpdateService<br/>future]
CS[Custom Services...]
end
subgraph "Transport Layer"
WSS[WebSocketService<br/>• Connection management<br/>• Automatic reconnection<br/>• Message routing<br/>• Subscription management]
HTTP[HTTP API Clients<br/>• REST API calls<br/>• Automatic caching<br/>• Request deduplication<br/>• Retry with backoff]
end
end
end
subgraph "BACKEND"
BS[Backend Services<br/>REST APIs, WebSocket Services, etc.]
end
%% Flow connections
FE --> IL
IL --> AAS
IL --> PUS
IL --> CS
AAS --> WSS
AAS --> HTTP
PUS --> WSS
PUS --> HTTP
CS --> WSS
CS --> HTTP
WSS <--> BS
HTTP <--> BS
%% Styling
classDef frontend fill:#e1f5fe
classDef backend fill:#f3e5f5
classDef service fill:#e8f5e8
classDef transport fill:#fff3e0
class FE,IL frontend
class BS backend
class AAS,PUS,CS service
class WSS,HTTP transport
+
+graph BT
%% External Controllers
AC["AccountsController<br/>(Auto-generated types)"]
AuthC["AuthenticationController<br/>(Auto-generated types)"]
TBC["TokenBalancesController<br/>(External Integration)"]
%% Core Services
AA["AccountActivityService"]
WS["BackendWebSocketService"]
%% Dependencies & Type Imports
AC -.->|"Import types<br/>(DRY)" | AA
AuthC -.->|"Import types<br/>(DRY)" | WS
WS -->|"Messenger calls"| AA
AA -.->|"Event publishing"| TBC
%% Styling
classDef core fill:#f3e5f5
classDef integration fill:#fff3e0
classDef controller fill:#e8f5e8
class WS,AA core
class TBC integration
class AC,AuthC controller
+
+sequenceDiagram
participant TBC as TokenBalancesController
participant AA as AccountActivityService
participant WS as BackendWebSocketService
participant HTTP as HTTP Services<br/>(APIs & RPC)
participant Backend as WebSocket Endpoint<br/>(Backend)
Note over TBC,Backend: Initial Setup
TBC->>HTTP: Initial balance fetch via HTTP<br/>(first request for current state)
WS->>Backend: WebSocket connection request
Backend->>WS: Connection established
WS->>AA: WebSocket connection status notification<br/>(BackendWebSocketService:connectionStateChanged)<br/>{state: 'CONNECTED'}
AA->>AA: call('AccountsController:getSelectedAccount')
AA->>WS: subscribe({channels, callback})
WS->>Backend: {event: 'subscribe', channels: ['account-activity.v1.eip155:0:0x123...']}
Backend->>WS: {event: 'subscribe-response', subscriptionId: 'sub-456'}
Note over WS,Backend: System notification sent automatically upon subscription
Backend->>WS: {event: 'system-notification', data: {chainIds: ['eip155:1', 'eip155:137', ...], status: 'up'}}
WS->>AA: System notification received
AA->>AA: Track chains as 'up' internally
AA->>TBC: Chain availability notification<br/>(AccountActivityService:statusChanged)<br/>{chainIds: ['0x1', '0x89', ...], status: 'up'}
TBC->>TBC: Increase polling interval from 20s to 10min<br/>(.updateChainPollingConfigs({0x89: 600000}))
Note over TBC,Backend: User Account Change
par StatusChanged Event
TBC->>HTTP: Fetch balances for new account<br/>(fill transition gap)
and Account Subscription
AA->>AA: User switched to different account<br/>(AccountsController:selectedAccountChange)
AA->>WS: subscribe (new account)
WS->>Backend: {event: 'subscribe', channels: ['account-activity.v1.eip155:0:0x456...']}
Backend->>WS: {event: 'subscribe-response', subscriptionId: 'sub-789'}
AA->>WS: unsubscribe (previous account)
WS->>Backend: {event: 'unsubscribe', subscriptionId: 'sub-456'}
Backend->>WS: {event: 'unsubscribe-response'}
end
Note over TBC,Backend: Real-time Data Flow
Backend->>WS: {event: 'notification', channel: 'account-activity.v1.eip155:0:0x123...',<br/>data: {address, tx, updates}}
WS->>AA: Direct callback routing
AA->>AA: Validate & process AccountActivityMessage
par Balance Update
AA->>TBC: Real-time balance change notification<br/>(AccountActivityService:balanceUpdated)<br/>{address, chain, updates}
TBC->>TBC: Update balance state directly<br/>(or fallback poll if error)
and Transaction and Activity Update (Not yet implemented)
AA->>AA: Process transaction data<br/>(AccountActivityService:transactionUpdated)<br/>{tx: Transaction}
Note right of AA: Future: Forward to TransactionController<br/>for transaction state management<br/>(pending → confirmed → finalized)
end
Note over TBC,Backend: System Notifications
Backend->>WS: {event: 'system-notification', data: {chainIds: ['eip155:137'], status: 'down'}}
WS->>AA: System notification received
AA->>AA: Process chain status change
AA->>TBC: Chain status notification<br/>(AccountActivityService:statusChanged)<br/>{chainIds: ['eip155:137'], status: 'down'}
TBC->>TBC: Decrease polling interval from 10min to 20s<br/>(.updateChainPollingConfigs({0x89: 20000}))
TBC->>HTTP: Fetch balances immediately
Backend->>WS: {event: 'system-notification', data: {chainIds: ['eip155:137'], status: 'up'}}
WS->>AA: System notification received
AA->>AA: Process chain status change
AA->>TBC: Chain status notification<br/>(AccountActivityService:statusChanged)<br/>{chainIds: ['eip155:137'], status: 'up'}
TBC->>TBC: Increase polling interval from 20s to 10min<br/>(.updateChainPollingConfigs({0x89: 600000}))
Note over TBC,Backend: Connection Health Management
Backend-->>WS: Connection lost
WS->>AA: WebSocket connection status notification<br/>(BackendWebSocketService:connectionStateChanged)<br/>{state: 'DISCONNECTED'}
AA->>AA: Mark all tracked chains as 'down'<br/>(flush internal tracking set)
AA->>TBC: Chain status notification for all tracked chains<br/>(AccountActivityService:statusChanged)<br/>{chainIds: ['0x1', '0x89', ...], status: 'down'}
TBC->>TBC: Decrease polling interval from 10min to 20s<br/>(.updateChainPollingConfigs({0x89: 20000}))
TBC->>HTTP: Fetch balances immediately
WS->>WS: Automatic reconnection<br/>with exponential backoff
WS->>Backend: Reconnection successful
Note over AA,Backend: Restart initial setup - resubscribe and get fresh chain status
AA->>WS: subscribe (same account, new subscription)
WS->>Backend: {event: 'subscribe', channels: ['account-activity.v1.eip155:0:0x123...']}
Backend->>WS: {event: 'subscribe-response', subscriptionId: 'sub-999'}
Backend->>WS: {event: 'system-notification', data: {chainIds: [...], status: 'up'}}
WS->>AA: System notification received
AA->>AA: Track chains as 'up' again
AA->>TBC: Chain availability notification<br/>(AccountActivityService:statusChanged)<br/>{chainIds: [...], status: 'up'}
TBC->>TBC: Increase polling interval back to 10min
+
+The WebSocket connects when ALL 3 conditions are true:
+isEnabled() callback returns true (feature flag)AuthenticationController.isSignedIn = trueKeyringController.isUnlocked = truePlus: Platform code must call connect() when app opens/foregrounds and disconnect() when app closes/backgrounds.
Idempotent connect():
Auto-Reconnect:
+The HTTP API provides type-safe clients for accessing MetaMask backend REST APIs. It uses @tanstack/query-core for intelligent caching, request deduplication, and automatic retries.
Available APIs:
+| API | +Base URL | +Purpose | +
|---|---|---|
| Accounts | +accounts.api.cx.metamask.io |
+Balances, transactions, NFTs, token discovery | +
| Prices | +price.api.cx.metamask.io |
+Spot prices, exchange rates, historical prices | +
| Token | +token.api.cx.metamask.io |
+Token metadata, trending, top gainers | +
| Tokens | +tokens.api.cx.metamask.io |
+Bulk asset operations, supported networks | +
import {
ApiPlatformClient,
createApiPlatformClient,
} from '@metamask/core-backend';
// Create unified client
const client = new ApiPlatformClient({
clientProduct: 'metamask-extension',
clientVersion: '12.0.0',
getBearerToken: async () => authController.getBearerToken(),
});
// Access API methods through sub-clients
const networks = await client.accounts.fetchV2SupportedNetworks();
const balances = await client.accounts.fetchV5MultiAccountBalances([
'eip155:1:0x742d35cc6634c0532925a3b8d40c4e0e2c6e4e6',
]);
const prices = await client.prices.fetchV3SpotPrices([
'eip155:1/erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
]);
const tokenList = await client.token.fetchTokenList(1);
const assets = await client.tokens.fetchV3Assets([
'eip155:1/erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
]);
+
+Or use individual clients:
+import { AccountsApiClient, PricesApiClient } from '@metamask/core-backend';
const accountsClient = new AccountsApiClient({
clientProduct: 'metamask-extension',
});
const pricesClient = new PricesApiClient({
clientProduct: 'metamask-extension',
getBearerToken: async () => token,
});
+
+Handles account-related operations including balances, transactions, NFTs, and token discovery.
+| Method | +Description | +
|---|---|
fetchV1SupportedNetworks() |
+Get supported networks (v1) | +
fetchV2SupportedNetworks() |
+Get supported networks (v2) | +
fetchV2ActiveNetworks(accountIds, options?) |
+Get active networks by CAIP-10 account IDs | +
fetchV2Balances(address, options?) |
+Get balances for single address | +
fetchV2BalancesWithOptions(address, options?) |
+Get balances with filters | +
fetchV4MultiAccountBalances(addresses, options?) |
+Get balances for multiple addresses | +
fetchV5MultiAccountBalances(accountIds, options?) |
+Get balances using CAIP-10 IDs | +
fetchV1TransactionByHash(chainId, txHash, options?) |
+Get transaction by hash | +
fetchV1AccountTransactions(address, options?) |
+Get account transactions | +
fetchV4MultiAccountTransactions(accountIds, options?) |
+Get multi-account transactions | +
fetchV1AccountRelationship(chainId, from, to) |
+Get address relationship | +
fetchV2AccountNfts(address, options?) |
+Get account NFTs | +
fetchV2AccountTokens(address, options?) |
+Get detected ERC20 tokens | +
invalidateBalances() |
+Invalidate all balance cache | +
invalidateAccounts() |
+Invalidate all account cache | +
Handles price-related operations including spot prices, exchange rates, and historical data.
+| Method | +Description | +
|---|---|
fetchPriceV1SupportedNetworks() |
+Get price-supported networks (v1) | +
fetchPriceV2SupportedNetworks() |
+Get price-supported networks in CAIP format (v2) | +
fetchV1ExchangeRates(baseCurrency) |
+Get exchange rates for base currency | +
fetchV1FiatExchangeRates() |
+Get fiat exchange rates | +
fetchV1CryptoExchangeRates() |
+Get crypto exchange rates | +
fetchV1SpotPricesByCoinIds(coinIds) |
+Get spot prices by CoinGecko IDs | +
fetchV1SpotPriceByCoinId(coinId, currency?) |
+Get single coin spot price | +
fetchV1TokenPrices(chainId, addresses, options?) |
+Get token prices on chain | +
fetchV1TokenPrice(chainId, address, currency?) |
+Get single token price | +
fetchV2SpotPrices(chainId, addresses, options?) |
+Get spot prices with market data | +
fetchV3SpotPrices(assetIds, options?) |
+Get spot prices by CAIP-19 asset IDs | +
fetchV1HistoricalPricesByCoinId(coinId, options?) |
+Get historical prices by CoinGecko ID | +
fetchV1HistoricalPricesByTokenAddresses(chainId, addresses, options?) |
+Get historical prices for tokens | +
fetchV1HistoricalPrices(chainId, address, options?) |
+Get historical prices for single token | +
fetchV3HistoricalPrices(chainId, assetType, options?) |
+Get historical prices by CAIP-19 | +
fetchV1HistoricalPriceGraphByCoinId(coinId, options?) |
+Get price graph by CoinGecko ID | +
fetchV1HistoricalPriceGraphByTokenAddress(chainId, address, options?) |
+Get price graph by token address | +
invalidatePrices() |
+Invalidate all price cache | +
Handles token metadata, lists, and trending/popular token discovery.
+| Method | +Description | +
|---|---|
fetchNetworks() |
+Get all networks | +
fetchNetworkByChainId(chainId) |
+Get network by chain ID | +
fetchTokenList(chainId, options?) |
+Get token list for chain | +
fetchV1TokenMetadata(chainId, address, options?) |
+Get token metadata | +
fetchTokenDescription(chainId, address) |
+Get token description | +
fetchV3TrendingTokens(chainIds, options?) |
+Get trending tokens | +
fetchV3TopGainers(chainIds, options?) |
+Get top gainers/losers | +
fetchV3PopularTokens(chainIds, options?) |
+Get popular tokens | +
fetchTopAssets(chainId) |
+Get top assets for chain | +
fetchV1SuggestedOccurrenceFloors() |
+Get suggested occurrence floors | +
Handles bulk token operations and supported network queries.
+| Method | +Description | +
|---|---|
fetchTokenV1SupportedNetworks() |
+Get token-supported networks (v1) | +
fetchTokenV2SupportedNetworks() |
+Get token-supported networks with full/partial support (v2) | +
fetchV3Assets(assetIds) |
+Fetch assets by CAIP-19 IDs | +
invalidateTokens() |
+Invalidate all token cache | +
type ApiPlatformClientOptions = {
/** Client product identifier (e.g., 'metamask-extension', 'metamask-mobile') */
clientProduct: string;
/** Optional client version (default: '1.0.0') */
clientVersion?: string;
/** Function to get bearer token for authenticated requests */
getBearerToken?: () => Promise<string | undefined>;
/** Optional custom QueryClient instance for shared caching */
queryClient?: QueryClient;
};
+
+Default Stale Times:
+| Data Type | +Stale Time | +
|---|---|
| Prices | +30 seconds | +
| Balances | +1 minute | +
| Transactions | +30 seconds | +
| Networks | +10 minutes | +
| Supported Networks | +30 minutes | +
| Token Metadata | +5 minutes | +
| Token List | +10 minutes | +
| Exchange Rates | +5 minutes | +
| Trending | +2 minutes | +
| Auth Token | +5 minutes | +
Override Stale Time:
+// Use custom stale time for specific request
const balances = await client.accounts.fetchV5MultiAccountBalances(
accountIds,
{ networks: ['eip155:1'] },
{ staleTime: 10000 }, // 10 seconds
);
+
+// Invalidate all caches
await client.invalidateAll();
// Invalidate auth token (on logout)
await client.invalidateAuthToken();
// Domain-specific invalidation
await client.accounts.invalidateBalances();
await client.prices.invalidatePrices();
await client.tokens.invalidateTokens();
// Clear all cached data
client.clear();
// Check if query is fetching
const isFetching = client.isFetching(['accounts', 'balances']);
// Access cached data directly
const cached = client.getCachedData(['accounts', 'balances', 'v5', { ... }]);
// Set cached data
client.setCachedData(queryKey, data);
// Access underlying QueryClient for advanced usage
const queryClient = client.queryClient;
+
+The core WebSocket client providing connection management, authentication, and message routing.
+interface BackendWebSocketServiceOptions {
messenger: BackendWebSocketServiceMessenger;
url: string;
timeout?: number;
reconnectDelay?: number;
maxReconnectDelay?: number;
requestTimeout?: number;
enableAuthentication?: boolean;
enabledCallback?: () => boolean;
}
+
+connect(): Promise<void> - Establish authenticated WebSocket connectiondisconnect(): Promise<void> - Close WebSocket connectionsubscribe(options: SubscriptionOptions): Promise<SubscriptionResult> - Subscribe to channelssendRequest(message: ClientRequestMessage): Promise<ServerResponseMessage> - Send request/response messageschannelHasSubscription(channel: string): boolean - Check subscription statusfindSubscriptionsByChannelPrefix(prefix: string): SubscriptionInfo[] - Find subscriptions by prefixgetConnectionInfo(): WebSocketConnectionInfo - Get detailed connection stateHigh-level service for monitoring account activity using WebSocket data.
+interface AccountActivityServiceOptions {
messenger: AccountActivityServiceMessenger;
subscriptionNamespace?: string;
}
+
+subscribe(subscription: SubscriptionOptions): Promise<void> - Subscribe to account activityunsubscribe(subscription: SubscriptionOptions): Promise<void> - Unsubscribe from account activityAccountActivityService:balanceUpdated - Real-time balance changesAccountActivityService:transactionUpdated - Transaction status updatesAccountActivityService:statusChanged - Chain/service status changesComplete transaction/balance update message
+Account address
+Transaction information
+Array of balance updates for different assets
+Configuration options for the account activity service
+Optional subscriptionCustom subscription namespace (default: 'account-activity.v1')
+Optional traceOptional callback to trace performance of account activity operations (default: no-op)
+Client product identifier (e.g., 'metamask-extension')
+Optional clientOptional client version
+Optional getFunction to get bearer token for authenticated requests
+Optional queryOptional custom QueryClient instance
+Asset information for balance updates
+Number of decimal places for the asset
+Whether the asset is fungible
+Asset type in CAIP format (e.g., "eip155:1/erc20:0x...")
+Asset unit/symbol (e.g., "USDT", "ETH")
+Configuration options for the WebSocket service
+Optional isOptional callback to determine if connection should be enabled (default: always enabled)
+Optional maxMaximum reconnection delay in milliseconds (default: 60000)
+The messenger for inter-service communication
+Optional reconnectInitial reconnection delay in milliseconds (default: 10000)
+Optional requestRequest timeout in milliseconds (default: 30000)
+Optional timeout?: numberConnection timeout in milliseconds (default: 10000)
+Optional traceOptional callback to trace performance of WebSocket operations (default: no-op)
+The WebSocket URL to connect to
+Balance information
+Balance amount as string
+Optional error?: stringOptional error message
+Channel-based callback configuration
+Callback function
+Channel name to match (also serves as the unique identifier)
+Client Request message +Used when client sends a request to the server
+Optional channels?: string[]CoinGecko spot price
+Optional allOptional allOptional circulatingOptional dilutedOptional high1d?: numberOptional low1d?: numberOptional marketOptional marketOptional priceOptional priceOptional priceOptional priceOptional priceOptional priceOptional priceOptional priceOptional totalExchange rate info
+Optional gcCustom GC time (ms)
+Optional staleCustom stale time (ms)
+Market data details from Price API spot-prices endpoint
+All-time high price
+All-time low price
+Circulating supply
+Currency code (e.g., 'ETH', 'USD')
+Diluted market cap
+24h high price
+24h low price
+Market capitalization
+Market cap 24h change percentage
+Current price in the requested currency
+24h price change amount
+14d price change percentage
+24h price change percentage
+1h price change percentage
+1y price change percentage
+200d price change percentage
+30d price change percentage
+7d price change percentage
+Total trading volume
+Network info
+Optional blockOptional iconOptional networkOptional tokenNFT item
+Optional attributes?: Record<string, unknown>[]Optional description?: stringOptional imageOptional name?: stringPagination info for paginated responses
+Optional cursor?: stringPrice supported networks response
+Server Notification message +Used when server sends unsolicited data to client +subscriptionId is optional for system-wide notifications
+Optional subscriptionServer Response message +Used when server responds to a client request
+Optional failed?: string[]Optional subscriptionOptional succeeded?: string[]Account subscription options
+Supported currencies for Price API
+System notification data for chain status updates
+Array of chain IDs affected (e.g., ['eip155:137', 'eip155:1'])
+Status of the chains: 'down' or 'up'
+Optional timestamp?: numberTimestamp of the notification
+Token discovery item
+Optional balance?: stringToken metadata from Token API v1 /tokens/{chainId} endpoint
+Optional aggregators?: string[]Optional iconOptional occurrences?: numberTop asset
+Top gainers sort options
+Basic transaction information
+Chain identifier in CAIP-2 format (e.g., "eip155:1")
+Address that initiated the transaction
+Transaction ID/hash
+Transaction status
+Timestamp when the transaction was processed
+Address that received the transaction
+Transfer information
+Transfer amount as string
+Address sending the transfer
+Address receiving the transfer
+Sort options for trending tokens (v3)
+Trending sort options
+Trending token data from Token API v3 /tokens/trending endpoint
+Optional labels?: string[]Optional priceOptional h1?: stringOptional h24?: stringOptional h6?: stringOptional m15?: stringOptional m30?: stringOptional m5?: stringAccount address relationship result from v1 endpoint
+Optional chainChain ID
+Optional count?: numberNumber of interactions
+Optional data?: { Transaction data details
+Optional error?: { Error information when relationship lookup fails
+Optional txTransaction hash of the relationship
+Account transactions response
+Exchange rates response
+V1 Historical prices response
+Array of price data points as [timestamp, price] tuples
+Suggested occurrence floors response
+V1 Supported networks response
+Token description response
+Token supported networks response (v1)
+Transaction by hash response
+Optional isOptional logs?: { Optional methodOptional transactionOptional transactionOptional transactionOptional valueActive networks response
+V2 Balance item
+Optional accountOptional timestamp?: stringOptional type?: stringV2 Balances response
+V2 Supported networks response
+Token supported networks response (v2) - includes partial support
+Asset response from V3 Assets endpoint. +All fields are stored in state (FungibleAssetMetadata).
+Optional aggregators?: string[]DEX/aggregator integrations
+CAIP-19 asset ID (e.g., "eip155:1/erc20:0x...")
+Optional coingeckoCoinGecko ID for price lookups
+Decimal places
+Optional description?: V3AssetDescriptionLocalized description (maps to metadata.description in state)
+Optional erc20Whether the token supports ERC-20 permit
+Optional fees?: V3AssetFeesFee information
+Optional honeypotHoneypot detection status
+Optional iconIcon URL (maps to image in state)
Optional isWhether the contract is verified
+Optional labels?: string[]Asset labels/tags (e.g., "stable_coin")
+Asset display name
+Optional occurrences?: numberNumber of token list occurrences
+Optional storage?: V3AssetStorageStorage slot information
+Asset symbol
+V3 Historical prices response
+Optional marketOptional totalV3 Spot prices response
+V4 Multi-account balances response
+V4 Multi-account transactions response
+Optional endV5 Balance Item from Accounts API
+V5 Multi-account balances response
+Value transfer within a transaction
+WebSocket connection info
+Optional connectedUnion type for all WebSocket messages
+Unified WebSocket subscription object used for both internal storage and external API
+Optional callback?: ((notification) => void)Callback function for handling notifications (optional for external use)
+Channel type with version (e.g., 'account-activity.v1') extracted from first channel
+Channel names for this subscription
+The subscription ID from the server
+Function to unsubscribe and clean up
+Optional requestId: stringConst Const Const API Base URLs
+Readonly ACCOUNTS: "https://accounts.api.cx.metamask.io"Readonly PRICES: "https://price.api.cx.metamask.io"Readonly TOKEN: "https://token.api.cx.metamask.io"Readonly TOKENS: "https://tokens.api.cx.metamask.io"Const Garbage collection times (ms)
+Readonly DEFAULT: numberReadonly EXTENDED: numberReadonly SHORT: numberConst Stale times for different data types (ms)
+Readonly AUTH_Readonly BALANCES: numberReadonly DEFAULT: numberReadonly EXCHANGE_Readonly NETWORKS: numberReadonly PRICES: numberReadonly SUPPORTED_Readonly TOKEN_Readonly TOKEN_Readonly TRANSACTIONS: numberReadonly TRENDING: number
High-performance service for real-time account activity monitoring using optimized +WebSocket subscriptions with direct callback routing. Automatically subscribes to +the currently selected account and switches subscriptions when the selected account changes. +Receives transactions and balance updates using the comprehensive AccountActivityMessage format.
+Performance Features:
++- Direct callback routing (no EventEmitter overhead)
+- Minimal subscription tracking (no duplication with BackendWebSocketService)
+- Optimized cleanup for mobile environments
+- Single-account subscription (only selected account)
+- Comprehensive balance updates with transfer tracking
+
+Architecture:
++- Uses messenger pattern to communicate with BackendWebSocketService
+- AccountActivityService tracks channel-to-subscriptionId mappings via messenger calls
+- Automatically subscribes to selected account on initialization
+- Switches subscriptions when selected account changes
+- No direct dependency on BackendWebSocketService (uses messenger instead)
+
+Example
+