Original Resource: This guide is officially published on the IRCTC Developer Platform.
Have you ever been stuck at a railway platform frantically refreshing slow apps to find out where your train is or whether your RAC/WL ticket confirmed?
In this tutorial, we will build a production-ready WhatsApp bot in Node.js & TypeScript that lets you check live train running status, delay minutes, and 10-digit PNR status directly in WhatsApp with zero Twilio or Meta WhatsApp Business API costs.
Architecture Overview
User sends WhatsApp message (!live 12557) │ ▼ [@whiskeysockets/baileys Multi-Device Socket] │ ▼ Command Parser (!live <train> | !pnr <pnr>) │ ▼ [IRCTC API Gateway: https://api.irctc.dev] │ ▼ Formatted WhatsApp Response (Delays, Halts, Coach & Berths) Prerequisites
- Node.js 18+ LTS installed on your system.
- A mobile phone with WhatsApp installed to scan the QR code.
- A free IRCTC API Key from irctc.dev/dashboard (every developer receives 10,000 free requests upon 1-click Google signup with zero credit card required).
Step 1: Initialize Project & Install Dependencies
Create a new directory and install @whiskeysockets/baileys (for WhatsApp Web multi-device connection), qrcode-terminal, irctc-api, and dotenv:
mkdir irctc-whatsapp-bot && cd irctc-whatsapp-bot npm init -y npm install @whiskeysockets/baileys qrcode-terminal irctc-api dotenv npm install -D typescript @types/node ts-node npx tsc --init Step 2: Configure Environment Variables
Create a .env file in your root folder:
IRCTC_API_KEY=your_irctc_api_key_here BOT_PREFIX=! NODE_ENV=production Step 3: Implement WhatsApp Socket & Railway Commands
Create src/index.ts and set up the Baileys socket with persistent multi-file authentication so you only have to scan the QR code once:
import makeWASocket, { DisconnectReason, useMultiFileAuthState } from '@whiskeysockets/baileys'; import { Boom } from '@hapi/boom'; import qrcode from 'qrcode-terminal'; import { IrctcApi } from 'irctc-api'; import dotenv from 'dotenv'; dotenv.config(); const irctc = new IrctcApi({ apiKey: process.env.IRCTC_API_KEY || '' }); async function startBot() { const { state, saveCreds } = await useMultiFileAuthState('auth_info_baileys'); const sock = makeWASocket({ auth: state, printQRInTerminal: false }); sock.ev.on('connection.update', (update) => { const { connection, lastDisconnect, qr } = update; if (qr) { console.log('⚡ Scan this QR code with WhatsApp on your phone:'); qrcode.generate(qr, { small: true }); } if (connection === 'close') { const shouldReconnect = (lastDisconnect?.error as Boom)?.output?.statusCode !== DisconnectReason.loggedOut; if (shouldReconnect) startBot(); } else if (connection === 'open') { console.log('✅ IRCTC WhatsApp Bot is online!'); } }); sock.ev.on('creds.update', saveCreds); // Incoming Message Handler sock.ev.on('messages.upsert', async ({ messages, type }) => { if (type !== 'notify') return; const msg = messages[0]; if (!msg.message || msg.key.fromMe) return; const sender = msg.key.remoteJid!; const text = msg.message.conversation || msg.message.extendedTextMessage?.text || ''; const trimmed = text.trim(); // 1. Live Running Status Command (!live 12557) if (trimmed.startsWith('!live ')) { const trainNo = trimmed.replace('!live ', '').trim(); try { await sock.sendMessage(sender, { text: `🔍 Checking live status for ${trainNo}...` }); const live = await irctc.live.getStatus(trainNo); const reply = `🚆 *Train ${live.trainNumber} — ${live.trainName}* 📍 *Current Location:* ${live.currentLocation} (${live.locationStatus}) ⏱️ *Status:* ${live.currentDelayMin > 0 ? `Delayed by ${live.currentDelayMin} mins 🔴` : 'Running On Time 🟢'} 🎯 *Next Station:* ${live.stops?.find((s: any) => s.status === 'upcoming')?.stationName || 'In Transit'} ⚡ _Powered by irctc.dev_`; await sock.sendMessage(sender, { text: reply }); } catch (err: any) { await sock.sendMessage(sender, { text: `❌ ${err.message}` }); } } // 2. Real-Time PNR Status Command (!pnr 2265248473) if (trimmed.startsWith('!pnr ')) { const pnr = trimmed.replace('!pnr ', '').trim(); try { await sock.sendMessage(sender, { text: `🔍 Verifying PNR ${pnr}...` }); const data = await irctc.pnr.check(pnr); const passengerList = (data.passengers || []) .map((p: any, i: number) => ` • P${i + 1}: *${p.currentStatus}* (Coach ${p.coach || 'N.A'}, Seat ${p.berthNumber || 'N.A'} [${p.berth || 'N.A'}])`) .join('\n'); const reply = `🎫 *IRCTC PNR Status: ${pnr}* 🚆 *Train:* ${data.trainNumber} - ${data.trainName} 🗓️ *Date:* ${data.journeyDate} (${data.from?.code} ➔ ${data.to?.code}) 📊 *Charting:* ${data.chartStatus} 👥 *Passenger Manifest:* ${passengerList} ⚡ _Powered by irctc.dev_`; await sock.sendMessage(sender, { text: reply }); } catch (err: any) { await sock.sendMessage(sender, { text: `❌ ${err.message}` }); } } }); return sock; } startBot(); Step 4: Run the Bot
Start your bot in development:
npx ts-node src/index.ts - Scan the terminal QR code using WhatsApp on your phone (Linked Devices ➔ Link a Device).
- Once connected, open any WhatsApp chat and send:
-
!live 12557(Fetches live GPS status, platform, and delay in under 400ms). -
!pnr 2265248473(Fetches passenger coach and berth allocations).
-
Test it right now in your terminal (No code required)
If you want to test the underlying Indian Railways API directly without setting up WhatsApp, run:
npx irctc-api live 12557 npx irctc-api pnr 2265248473 You can claim 10,000 free requests directly at irctc.dev/dashboard.

