Client for Walt, the crypto app in Telegram (ex @wallet).
Warning
This is an unofficial client. It is not affiliated with, endorsed by or supported by Walt or Telegram. It uses a private, undocumented API. Using it likely violates the Walt and Telegram terms of service and may get your account restricted or banned. The software is provided as is, without warranty of any kind. The authors accept no liability for any loss of funds, account access or data, or any other damage arising from its use. Use it at your own risk.
npm install @2bad/waltESM only. Requires Node.js 26 or later.
import { TelegramTokenSource, WaltClient } from '@2bad/walt'
const source = new TelegramTokenSource({ session: 'SESSION_STRING', apiId: 12345, apiHash: 'API_HASH' })
const client = new WaltClient({ tokenProvider: (rejected) => source.token(rejected) })
const { entries, total, fiatCurrency } = await client.portfolio()
console.log(entries[0], total, fiatCurrency) // { currency: 'TON', amount: '120.5', fiatValue: 381.2 } 1250.4 USD
await source.disconnect()- Connecting: Telegram credentials, token storage, retries and pacing
- Balances: accounts, portfolio, profit and loss, staked funds
- Prices: coin rates, charts and past prices
- Exchange: available pairs, quotes, exchanges and limit orders
- Transactions: history, details and reading a transaction
- Errors:
WaltRequestError,WaltAuthErrorand what is retried
A runnable script is in examples/portfolio.ts.
new TelegramTokenSource(options: TelegramTokenSourceOptions)
type TelegramTokenSource = {
token(rejected?: string): Promise<string>
disconnect(): Promise<void>
}
new WaltClient(options: WaltClientOptions)
type WaltClient = {
accounts(): Promise<AccountsResponse>
portfolio(): Promise<Portfolio>
pnl(): Promise<PnlResponse>
portfolioHistory(dateFrom: Date | string, resolution: '1d' | '1m'): Promise<PortfolioHistory>
frozenBalances<T = unknown>(): Promise<T[]>
earnCampaigns(): Promise<EarnCampaignsResponse>
earnCampaignTransactions(campaignId: number | string, limit?: number, after?: EarnTransactionsPage): Promise<EarnTransactionsPage>
allEarnCampaignTransactions(campaignId: number | string, limit?: number): AsyncGenerator<EarnTransaction>
earnRate(from: string, to: string): Promise<EarnRate>
coins(fiatCurrency: FiatCurrency): Promise<Coin[]>
coinDetails(currency: string, fiatCurrency: FiatCurrency): Promise<CoinDetails>
charts(currency: string, fiatCurrency: FiatCurrency): Promise<Charts>
priceForFiatAtTime(crypto: string, fiat: FiatCurrency, amount: number | string, time: Date | string | number): Promise<PriceAtTime>
localCurrency(): Promise<FiatCurrency>
availableExchanges(): Promise<AvailableExchanges>
quote(fromCurrency: string, toCurrency: string, fromAmount: number): Promise<ExchangeQuote>
createExchange(request: ExchangeRequest): Promise<Exchange> // moves real money, never retried
limitOrders(options?: { status?: string[]; limit?: number }): Promise<LimitOrder[]>
limitOrder(id: string): Promise<LimitOrder>
limitOrderQuote(baseCurrency: string, side: 'BUY' | 'SELL', priceLimit: number | string, size: { amount: number | string } | { quantity: number | string }): Promise<LimitOrderQuote>
limitOrderBounds(baseCurrency: string): Promise<LimitOrderBounds>
limitOrderTokens(): Promise<LimitOrderToken[]>
transactions(limit?: number, cursor?: string): Promise<TransactionsPage>
accountTransactions(currency: string, limit?: number, cursor?: string): Promise<TransactionsPage>
allTransactions(limit?: number): AsyncGenerator<Transaction>
allAccountTransactions(currency: string, limit?: number): AsyncGenerator<Transaction>
transactionDetails(id: number | string, gateway?: TransactionGateway): Promise<TransactionDetails>
detailsFor(transactions: AsyncIterable<Transaction> | Iterable<Transaction>): AsyncGenerator<TransactionDetails>
unconfirmedTransactions<T = unknown>(limit?: number): Promise<{ transactions: T[]; size: number }>
}
function normalizeTransaction(details: TransactionDetails): NormalizedTransactionResponse fields keep the API's snake_case. Amounts are decimal strings, except in the exchange responses.
The API publishes no schemas. Every type was derived from real responses and is loose where a value has not been seen.
MIT