How to Check Indian Railway PNR Status Programmatically (Node.js & Python Guide)
Original Guide: This article was originally published on IRCTC Developer Platform. Checking the status of an Indian Railways Passenger Name Record (PNR) programmatically has historically been frustrating: brittle web s
Original Guide: This article was originally published on IRCTC Developer Platform.
Checking the status of an Indian Railways Passenger Name Record (PNR) programmatically has historically been frustrating: brittle web scrapers, OCR-based captcha captchas, and random IP bans.
In this guide, we'll cover how to query official CRIS PRS live PNR records in under 100ms using Node.js and Python with zero scraping maintenance.
Anatomy of a 10-Digit PNR
A PNR number consists of:
-
First 3 Digits: PRS Reservation Zone (e.g.,
226for Northern Railway CRIS PRS). - Last 7 Digits: Unique transaction serial number.
Method 1: Node.js & TypeScript with irctc-api
The official client SDK handles authentication, keep-alive connections, and TypeScript types out of the box.
Installation
npm install irctc-api
Code
import { IrctcApi } from 'irctc-api';
const client = new IrctcApi({
apiKey: process.env.IRCTC_API_KEY || 'irctc_live_9a8f2c7e01d4'
});
async function verifyBooking(pnrNumber: string) {
try {
const pnr = await client.pnr.check(pnrNumber);
console.log(`🚆 Train: ${pnr.trainNumber} - ${pnr.trainName}`);
console.log(`🛣️ Route: ${pnr.from} -> ${pnr.to} | Date: ${pnr.doj}`);
console.log(`📊 Chart Status: ${pnr.chartStatus}`);
pnr.passengers.forEach((p, idx) => {
console.log(` • Passenger ${idx + 1}: ${p.currentStatus} | Coach: ${p.coach || 'N.A'} | Berth: ${p.berthNumber || 'N.A'} [${p.berth || 'N.A'}]`);
});
} catch (error: any) {
console.error('PNR verification error:', error.message);
}
}
verifyBooking('2265248473');
Method 2: Python with requests
If you are building in Python (Django, Flask, FastAPI, Celery):
Installation
pip install requests
Code
import os
import requests
API_KEY = os.getenv("IRCTC_API_KEY", "irctc_live_9a8f2c7e01d4")
PNR = "2265248473"
url = f"https://api.irctc.dev/api/v1/pnr/{PNR}"
headers = {
"x-api-key": API_KEY,
"accept": "application/json",
"User-Agent": "pnr-client/v1.0"
}
response = requests.get(url, headers=headers, timeout=5.0)
if response.status_code == 200:
data = response.json().get("data", {})
print(f"Train: {data.get('trainNumber')} - {data.get('trainName')}")
print(f"Date: {data.get('doj')} ({data.get('from')} -> {data.get('to')})")
print(f"Chart: {data.get('chartStatus')}")
for idx, p in enumerate(data.get("passengers", []), 1):
print(f" P{idx}: {p.get('currentStatus')} | Coach: {p.get('coach', 'N.A')} | Seat: {p.get('berthNumber', 'N.A')} [{p.get('berth', 'N.A')}]")
else:
print(f"Error {response.status_code}: {response.text}")
Understanding Passenger Fields
| Field | Description | Values |
|---|---|---|
currentStatus |
Current booking status |
CNF, RAC 12, WL 45
|
coach |
Reserved coach |
B2, S4, M1, N.A
|
berthNumber |
Specific berth number |
18, 45, N.A
|
berth |
Clean normalized berth type |
LOWER BERTH, MIDDLE BERTH, UPPER BERTH, SIDE LOWER, SIDE UPPER
|
chartStatus |
PRS charting status |
CHART NOT PREPARED, CHART PREPARED
|
Recommended Polling Schedule (Smart Backoff)
Do NOT poll PNR every few seconds. PNR statuses only update upon ticket cancellation or chart preparation.
- > 48 hours to departure: Poll once every 24 hours.
- 12 – 48 hours to departure: Poll every 4 hours.
- < 4 hours to departure: Poll every 15 minutes to catch chart preparation.
Resources
- Interactive PNR Sandbox: https://irctc.dev/playground
- Standalone PNR API Guide: https://irctc.dev/pnr-status-api
- Official NPM SDK: https://www.npmjs.com/package/irctc-api
Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.