Skip to main content
This guide will walk you through creating, developing, and deploying your first Towns bot. You’ll learn how to:
  1. Create a bot in Towns
  2. Set up your development environment
  3. Deploy to Render.com
  4. Configure your bot in Towns

Prerequisites

Before you begin, make sure you have:

Create a Bot

  1. Visit the Developer Portal Go to app.towns.com/developer
  2. Create New Bot Fill in the details and click “Create Bot”.
  3. Save Your Credentials After creation, you’ll receive two critical values:
    • APP_PRIVATE_DATA - Your bot’s private key and encryption device (base64 encoded string)
    • JWT_SECRET - Used to verify webhook requests from Towns servers
Store these securely - you’ll need them for deployment.
After following the steps above, you should be redirected to the bot settings page. Follow the instructions below to deploy your bot and set your webhook url.

Develop Your Bot

Now let’s set up your bot development environment.

Initialize Your Project

Create a new bot project using the Towns bot CLI:
bunx towns-bot init my-bot
This creates a new directory with a basic bot template.

Install Dependencies

cd my-bot
bun install

Add Bot Discovery Endpoint

Open src/index.ts and add this route after the /webhook route:
// After your /webhook route
app.get('/.well-known/agent-metadata.json', async (c) => {
  return c.json(await bot.getIdentityMetadata())
})
This endpoint is required for bot directories to discover and index your bot. After deploying your bot, go to the developer dashboard and click the Boost button to submit your bot for indexing.

Configure Environment

Copy the .env.sample file in your project root:
cp .env.sample .env

Push to GitHub

Create a new repository on GitHub, follow their instructions, commit all your changes and push your bot code to it.

Deploy Your Bot

We’ll deploy to Render.com, which offers a generous free tier perfect for bot hosting.
  1. Sign up for Render Go to render.com and create an account (can use GitHub login)
  2. Create New Web Service
    • Click “New +” → “Web Service”
    • Connect your GitHub account if prompted
    • Select your bot repository
  3. Configure the Service Fill in the deployment settings:
    SettingValue
    Namemy-bot (or any name you prefer)
    LanguageNode
    Build Commandbun install
    Start Commandbun run start
  4. Add Environment Variables In the “Environment” section, you can either paste your .env file contents or add each variable manually.
    KeyValue
    APP_PRIVATE_DATAYour app private data from bot creation
    JWT_SECRETYour JWT secret from bot creation
    PORT5123
  5. Deploy Click “Create Web Service”. Render will:
    • Clone your repository
    • Run bun install to build your bot
    • Start your bot with bun run start
    Wait for the deploy to finish. You’ll get a URL like:
    https://my-bot.onrender.com
    
Free tier services on Render may spin down after 15 minutes of inactivity. The first request after spin-down may take 30-60 seconds. Consider upgrading to a paid plan for production bots.

Configure in Towns

Now that your bot is deployed and publicly accessible, connect it to Towns.

Set Webhook URL

  1. Go back to app.towns.com/developer
  2. Click on your bot
  3. Under “Webhook URL”, enter:
    https://my-bot.onrender.com/webhook
    
    Don’t forget the /webhook path at the end!
  4. Click “Save”

Configure Forwarding Settings

In the bot settings page, under “Forwarding Settings”, choose which messages your bot receives.
  • All Messages - Bot receives every event in channels it’s in
    • All event handlers available. See Events for more information.
    • Use for: AI agents, moderation bots, analytics, or when you need tip/membership events
  • Mentions, Commands, Replies & Reactions (Default) - Bot only receives:
    • Direct @mentions, replies to bot’s messages, reactions, and slash commands
    • Available handlers: onMessage (filtered), onSlashCommand, onReaction, onMessageEdit, onRedaction
    • NOT available: onTip, onChannelJoin, onChannelLeave, onEventRevoke
    • Use for: Most interactive bots
  • No Messages - Bot receives no message events
    • Use for: External-only bots (e.g., GitHub webhooks, scheduled tasks)
Click “Save” after selecting your preference.

Install Bot to a Space

Finally, install your bot to a space to start using it:
  1. In Towns app, go to a space you own or admin
  2. Go to Space Settings → Bots
  3. Search for your bot by username
  4. Click “Install”
  5. Grant permissions as needed
Your bot is now live! 🎉

Understanding Your Bot’s Wallet Architecture

Your bot has two wallets that work together:

Bot Treasury Wallet

The Bot Treasury Wallet (bot.appAddress) is a SimpleAccount (ERC-4337) smart contract that holds your bot’s funds:
  • Receives funds: All tips and payments sent to your bot are stored here
  • Stores assets: This is where ETH and tokens are held
  • Source for payments: When your bot sends tips to users, funds come from this wallet
To fund your bot treasury, send Base ETH directly to bot.appAddress from any wallet.

Gas Wallet

The Gas Wallet (bot.viem.account) pays for gas fees on bot transactions:
  • Signs transactions: Authorizes all operations on behalf of the bot treasury
  • Pays gas fees: Needs Base ETH to cover transaction costs
  • Fund this wallet: Required for any blockchain transactions
Your gas wallet MUST be funded with Base ETH to execute any blockchain transactions (sending tips, banning users, etc.). Without gas, your bot cannot perform onchain operations.

When to Fund Each

Fund your Gas Wallet when:
  • Your bot needs to send tips to users
  • Your bot performs moderation actions (ban/unban)
  • Your bot interacts with smart contracts
  • You see “insufficient funds for gas” errors
Fund your Bot Treasury when:
  • Your bot needs to send tips from its treasury
  • You want to receive payments and tips
  • Your bot needs to hold ETH/tokens for operations
The gas wallet credentials are provided in APP_PRIVATE_DATA during bot creation. You can extract the wallet address from this value to fund it.

Testing Your Bot

Try these to verify everything works: In the channel you installed your bot to, mention your bot:
@mybot hello
The bot should respond with “Hello there! 👋“

Next Steps

Now that your bot is running, explore more capabilities: