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.
Top comments (0)