How to Build a Telegram Bot with Built-In Crypto Wallets

Joan Alavedra, Co-Founder at Openfort6 min read

TL;DR

Telegram is the distribution channel; the wallet is the product. This guide builds a Telegram bot where every user gets their own on-chain wallet the moment they type /start — no app install, no seed phrase, no gas. The bot maps each Telegram user ID to an Openfort backend wallet and signs transactions server-side, with gas sponsored by a policy. You can run the whole flow locally without a bot token, then go live with one BotFather command. A final section covers the client-side alternative: non-custodial embedded wallets inside a Telegram Mini-App.

How to Build a Telegram Bot with Built-In Crypto Wallets

Telegram reaches around a billion people who already know how to chat. That makes it one of the shortest paths from "no wallet" to "on-chain": no app store, no extension, no onboarding screen — just a bot that answers /start.

There are two ways to put wallets inside Telegram:

  1. Bot-first (this guide) — the wallet lives server-side. Users chat commands; your bot creates wallets, checks balances, and sends transactions on their behalf. Trading bots, payment bots, and agent-style assistants all work this way.
  2. App-first — a Telegram Mini-App built with React, where each user gets a non-custodial embedded wallet. Covered at the end.

We'll build the bot-first version with Openfort backend wallets: three commands, one wallet per user, all gas sponsored.

The full recipe is in the Openfort Recipe Hub:


_10
pnpx gitpick openfort-xyz/recipes-hub/tree/main/telegram-bot openfort-telegram-bot
_10
cd openfort-telegram-bot && pnpm install

What you'll build

A bot with three commands:

  • /start — creates a wallet for the Telegram user, keyed by their Telegram user ID
  • /balance — ETH and USDC balances on Base Sepolia
  • /send <address> <amount> — sends USDC, gas-free

The architecture is one mapping and one signer:


_10
Telegram user ──/send──▶ bot (grammY) ──▶ Openfort backend wallet ──▶ Base Sepolia
_10
_10
telegram_user_id → account_id

Openfort generates and stores the encrypted keys; your server authorizes each signature with a project-scoped wallet secret. Because signing is server-side, the UX is pure chat, and because a gas sponsorship policy covers fees, a wallet works the second it's created, holding nothing.

This pattern is custodial by design, which is what makes it instant. Be upfront about it with users, cap what wallets can do with signing policies, and remember users can always export their key and leave. If you want the user to hold the keys, jump to the Mini-App section.

Step 1: Create the bot

Message @BotFather, run /newbot, and follow the prompts. You'll get a token like 123456:ABC-DEF.... Keep it for later — you won't need it until the bot goes live.

Step 2: Configure Openfort

Copy .env.example to .env and fill in three values from the Openfort dashboard:


_10
OPENFORT_SECRET_KEY=sk_test_... # API keys
_10
OPENFORT_WALLET_SECRET=... # Backend wallets → Setup
_10
OPENFORT_GAS_POLICY_ID=pol_... # Gas sponsorship (Base Sepolia)
_10
TELEGRAM_BOT_TOKEN= # optional until you go live

Initialize the SDK once and reuse it:


_10
import Openfort from '@openfort/openfort-node'
_10
_10
export const openfort = new Openfort(process.env.OPENFORT_SECRET_KEY!, {
_10
walletSecret: process.env.OPENFORT_WALLET_SECRET!,
_10
})

Step 3: One wallet per Telegram user

The first time a user types /start, create a backend wallet and store the mapping. The recipe uses a JSON file; in production this is one column on your users table.


_10
export async function getOrCreateWallet(telegramUserId: number) {
_10
const stored = getStoredWallet(telegramUserId)
_10
if (stored) return openfort.accounts.evm.backend.get({ id: stored.accountId })
_10
_10
const account = await openfort.accounts.evm.backend.create()
_10
saveStoredWallet(telegramUserId, { accountId: account.id, address: account.address })
_10
return account
_10
}

Wire it to the command with grammY:


_10
import { Bot } from 'grammy'
_10
_10
const bot = new Bot(process.env.TELEGRAM_BOT_TOKEN!)
_10
_10
bot.command('start', async (ctx) => {
_10
if (!ctx.from) return
_10
const account = await getOrCreateWallet(ctx.from.id)
_10
await ctx.reply(`Wallet created! All gas is sponsored — you never need ETH.\n\nAddress: ${account.address}`)
_10
})

That's the whole onboarding. No seed phrase, no download, no funding step.

Step 4: Check balances

Reads don't need Openfort at all. Query the chain directly with viem:


_14
const publicClient = createPublicClient({ chain: baseSepolia, transport: http() })
_14
_14
export async function getBalances(address: `0x${string}`) {
_14
const [wei, usdcUnits] = await Promise.all([
_14
publicClient.getBalance({ address }),
_14
publicClient.readContract({
_14
address: USDC_ADDRESS,
_14
abi: erc20Abi,
_14
functionName: 'balanceOf',
_14
args: [address],
_14
}),
_14
])
_14
return { eth: formatEther(wei), usdc: formatUnits(usdcUnits, 6) }
_14
}

Step 5: Send USDC, gas-free

sendTransaction does the heavy lifting in one call: it upgrades the wallet to an EIP-7702 delegated account if needed, builds the intent, signs it server-side, and submits it through the sponsor.


_17
export async function sendUsdc(telegramUserId: number, to: `0x${string}`, amount: string) {
_17
const account = await getOrCreateWallet(telegramUserId)
_17
const data = encodeFunctionData({
_17
abi: erc20Abi,
_17
functionName: 'transfer',
_17
args: [to, parseUnits(amount, 6)],
_17
})
_17
_17
const result = await openfort.accounts.evm.backend.sendTransaction({
_17
account,
_17
chainId: 84532, // Base Sepolia
_17
interactions: [{ to: USDC_ADDRESS, data }],
_17
policy: process.env.OPENFORT_GAS_POLICY_ID,
_17
})
_17
_17
return result.response?.transactionHash
_17
}

The user's wallet holds zero ETH, and the transaction still lands — the sponsor relayer pays. Fund test wallets with USDC from Circle's faucet.

Step 6: Try it without Telegram, then go live

The recipe keeps command handlers as plain functions, so pnpm demo drives the exact flow — /start/balance/send — with a fake Telegram user and prints explorer links for each transaction. No bot token required.

When it looks right, add TELEGRAM_BOT_TOKEN to .env and run pnpm start. grammY long-polls Telegram, so there's nothing to deploy or expose. It runs from a laptop or any server with outbound internet.

App-first: non-custodial wallets in a Mini-App

The bot-first pattern trades custody for zero-friction chat. If your product needs users to hold their own keys — or a real UI — build a Telegram Mini-App instead: a React app running inside Telegram, using Openfort embedded wallets.

The flow: BotFather's /newapp links a web app to your bot, Telegram hands the app a signed initData object identifying the user, your backend validates it and exchanges it for an Openfort session via custom auth — and the user gets a non-custodial wallet with the same no-seed-phrase onboarding.

Building a game? The Unity WebGL guide covers the same flow for game engines.

Both patterns can share one Openfort project: bot-created backend wallets for instant chat UX, embedded wallets for users who graduate to self-custody.

Production checklist

  • Swap the JSON store for your database. Store only the account id and address — Openfort holds the keys, you hold references.
  • Constrain the wallets. Signing policies cap contracts, methods, and amounts per wallet — defense-in-depth if your bot server is ever compromised.
  • Guard commands with rate limits. Telegram user IDs are stable and spoofing-resistant inside the Bot API, but your bot is still a public endpoint.
  • Plan the exit. Key export means "custodial" never means "locked in" — make it a command or a support flow.
Share this article

Related Articles

  1. Best Embedded Wallet Providers for Stablecoin Payments (2026)

    The best embedded wallet SDKs and WaaS providers for stablecoin payments in 2026 — compared on custody model, chain coverage, gas sponsorship, self-hosting, and pricing for USDC/USDT apps.

  2. Best Agent Wallets for Developers in 2026 (Agentic & AI Agent Wallets)

    The best agentic wallets and AI agent wallets for developers in 2026 — compared on payment rails (x402, AP2, MCP), spending controls, self-hosting, and pricing.

  3. Best Embedded Wallets in 2026: Top 10 SDKs Compared (Pricing, Auth, Smart Accounts)

    Side-by-side comparison of 10 embedded wallet SDKs for 2026: pricing, auth options, smart accounts (4337/7702), and vendor lock-in scored for builders.

Ship your first wallet in minutes