Developer Documentation

API Documentation

Complete reference for the Malaysia Transit API. Build powerful transit applications with real-time data.

Base URL:https://malaysiatransit.techmavie.digital/api

Note: This documentation is free to read and explore. However, accessing the actual API endpoints requires an API key subscription.

Last updated: 11 May 2026

Authentication

API Key Required

The Malaysia Transit API requires authentication via API key. Subscribe through our Developer Portal to get your unique API key and start building.

$25/month subscription(RM99)

How to Authenticate

Include your API key using one of these methods:

# Option 1: X-API-Key header (recommended)
X-API-Key: mtk_live_your_api_key_here

# Option 2: Authorization Bearer header
Authorization: Bearer mtk_live_your_api_key_here

# Option 3: Query parameter (fallback)
?api_key=mtk_live_your_api_key_here
API Key Formats
mtk_pub_ + 32 hex (public)mtk_sec_ + 32 hex (secret)mtk_live_ + 32 hex (legacy)

The middleware accepts all three prefixes. Legacy keys auto-classify based on whether allowed origins are set.

Security
  • • Keys are hashed (SHA-256) in storage
  • • Full key shown only once upon generation
  • • Keys invalidated when subscription ends
  • • Public and secret keys can be regenerated independently

Public vs Secret Keys (Stripe-style pair)

Every subscriber gets two keys with distinct roles. You mint them independently from the dashboard, and regenerating one does not affect the other.

mtk_pub_*Public

Browser-safe. Pair with an Allowed Origins allowlist so a scraped key cannot be reused from any other site.

  • Use in SPAs, mobile webviews, static sites
  • Origin allowlist enforced server-side
  • Reject counters surfaced in the dashboard
mtk_sec_*Secret

Server-side only. No origin restriction, since back-end clients cannot send a trustworthy Origin header.

  • Use in ChatGPT custom GPTs, Zapier, n8n
  • Use in your backend or scheduled jobs
  • Never embed in browser bundles

Allowed Origins (public keys)

Configure an allowlist on your public key from the Developer Portal dashboard. The middleware then rejects browser requests whose Origin header (or Referer fallback) does not match. Empty allowlist means no restriction (backwards-compatible).

Pattern syntax
https://example.comExact host match
https://*.example.comSingle-label subdomain wildcard
https://*--myapp.netlify.appMid-label wildcard (Netlify deploy previews)
http://localhost:5173Local dev with explicit port

Default ports (:443, :80) are normalised away. The matcher rejects overly-broad patterns like https://*, https://*.com, and any wildcard with fewer than 3 labels. The literal Origin: null (file://, sandboxed iframes) is always rejected.

Threat model (honest framing)
  • Protects against: a key scraped from a SPA bundle and reused on another website in a browser context. The browser sends a true Origin header that the middleware verifies.
  • Does NOT protect against: a scripted client (curl, server-side scraper, malicious automation) that forges Origin: https://yoursite.com. For full theft prevention, keep keys out of public bundles and proxy through a backend (or use a secret key on the server).

The dashboard surfaces a lifetime + last-7-days reject counter, backed by a sharded Firestore subcollection so high-traffic abuse bursts increment atomically.

Authentication Errors

401
Unauthorized — Missing or invalid API key
403
Forbidden — Subscription expired or key revoked
429
Too Many Requests — Rate limit exceeded

Quick Start

// Initialize API client
const API_BASE = 'https://malaysiatransit.techmavie.digital/api';
const API_KEY = 'mtk_live_your_api_key_here'; // Get from Developer Portal

// Helper function with authentication
async function apiRequest(endpoint) {
  const response = await fetch(`${API_BASE}${endpoint}`, {
    headers: { 'X-API-Key': API_KEY }
  });
  if (!response.ok) throw new Error(`API error: ${response.status}`);
  return response.json();
}

// Get real-time vehicles in Penang
async function getVehicles(area = 'penang') {
  const data = await apiRequest(`/realtime?area=${area}`);
  console.log(`Found ${data.vehicleCount} vehicles`);
  return data;
}

// Get arrivals for a stop
async function getArrivals(stopId, area = 'penang') {
  const data = await apiRequest(`/stops/${stopId}/arrivals?area=${area}`);
  data.arrivals.forEach(arrival => {
    console.log(`Route ${arrival.routeShortName}: ${arrival.etaMinutes} min`);
  });
  return data;
}

// Search for stops
async function searchStops(query, area = 'penang') {
  return apiRequest(`/stops/search?q=${encodeURIComponent(query)}&area=${area}`);
}

Service Areas Reference

Important: Most API endpoints require an area parameter. Use the exact Area ID values from the table below. The default area is penang if not specified.

Area IDNameStateProvidersTypesStatus
klang-valleyKlang ValleyKuala Lumpur & SelangorRapid Rail KL (LRT/MRT/Monorail/BRT), Rapid Bus KL, MRT Feeder, KTM Komuter Klang Valley, KLIA Ekspres, KLIA Transit
BusRail
Live
penangPenangPenang Island & Seberang PeraiRapid Penang, Penang Ferry, KTM Komuter Utara, SRT International Shuttle
BusFerryRail
Live
kangarKangarPerlisBAS.MY Kangar, KTM Komuter Utara, SRT International Shuttle
BusRail
Live
alor-setarAlor SetarKedahBAS.MY Alor Setar, KTM Komuter Utara, SRT International Shuttle
BusRail
Live
kota-bharuKota BharuKelantanBAS.MY Kota Bharu, KTM Intercity
BusRail
Live
kuala-terengganuKuala TerengganuTerengganuBAS.MY Kuala Terengganu
Bus
Live
melakaMelakaMelakaBAS.MY Melaka, KTM Komuter Klang Valley (Seremban Line)
BusRail
Live
johorJohor BahruJohorBAS.MY Johor Bahru, Bas Muafakat Johor (BMJ), KTM Shuttle Tebrau
BusRail
Live
kuchingKuchingSarawakBAS.MY Kuching, City Public Link S19
Bus
Live
ipohIpohPerakBAS.MY Ipoh, KTM Komuter Utara, SRT International Shuttle
BusRail
Live
serembanSerembanNegeri SembilanBAS.MY Seremban (2 operators), KTM Komuter Klang Valley (Seremban Line), KTM Intercity
BusRail
Live
kuantanKuantanPahangBAS.MY Kuantan (pending)
Bus
Maintenance
kota-kinabaluKota KinabaluSabahComing Soon
Bus
Soon

Transit Types

busBus services only
railRail services only
ferryFerry services only

Schedule Endpoints

Supported areas:

ipohserembanpenangkangaralor-setarkota-bharukuala-terengganumelakajohorkuching

Direction values:

outboundAway from origin
inboundTowards origin
loopCircular routes

Fare Calculator Areas

For BAS.MY & Rapid Penang buses:

ipohserembanpenangkangaralor-setarkota-bharukuala-terengganumelakajohorkuching

KTM Komuter, KTM Intercity & Penang Ferry have separate endpoints.

Note: KTM Intercity fare API returns 501 (not implemented yet).

API Endpoints

Arrival Predictions (v2.0)

The API calculates bus arrival times using shape-based distance calculation instead of straight-line distance, resulting in 40-60% more accurate predictions.

Calculation Methods

  • shape-based: Uses route geometry (most accurate)
  • straight-line: Fallback when shape data unavailable

Confidence Levels

  • high: Shape-based, vehicle within 50m of route
  • medium: Shape-based, vehicle 50-200m from route
  • low: Straight-line fallback

Time-of-Day Factors

Rush Hour AM
7-9 AM: 40% slower
Rush Hour PM
4-7 PM: 45% slower
Midday
9 AM-4 PM: 15% slower
Evening/Night
Normal speed

Example Response

{
  "routeShortName": "301",
  "destination": "Komtar",
  "vehicleId": "PKX1234",
  "etaMinutes": 18,
  "distance": 6500,
  "calculationMethod": "shape-based",
  "confidence": "high",
  "timeFactor": 0.6
}

Best Practices

Caching Strategy

  • Static Data: Cache for 24 hours (routes, stops, schedules)
  • Real-time Data: Cache for max 30 seconds
  • Arrivals: Cache for 15-30 seconds maximum

Error Handling

  • • Handle 429 (rate limit) with exponential backoff
  • • Use cached data when 503 (service unavailable)
  • • Implement graceful degradation for failures

Polling Strategy

  • • Poll real-time data every 10-30 seconds
  • • Adjust polling based on data freshness
  • • Reduce frequency when data is stale

Batch Requests

  • • Batch multiple stop arrivals in parallel
  • • Limit batch size to 5 concurrent requests
  • • Add small delays between batches

API Analytics Dashboard

The middleware includes a built-in analytics dashboard to track API usage, monitor performance, and identify popular endpoints and service areas.

Access the dashboard:

Dashboard Features

  • Cumulative Statistics: Track total API calls across all time
  • Real-time Metrics: Requests/hour, avg response time, error rate
  • Endpoint Breakdown: See which API endpoints are most used
  • Service Area Analytics: Track usage per area

Dashboard Metrics

Total Requests (All Time)Cumulative count
Requests (24h / 1h)Rolling windows
Avg Response TimeMilliseconds
Error Rate4xx/5xx %
UptimeSince server start

Client Tracking

The dashboard tracks which apps and websites use the API. Apps can voluntarily identify themselves:

X-App-Name: MyTransitApp
📱app

Apps using X-App-Name header

🌐website

Requests from websites (Referer/Origin)

🔗direct

Direct API calls (curl, Postman)

Ready to Start Building?

Get your API key from the Developer Portal and start integrating today.

Powered by Malaysia Transit

This API is brought to you by Malaysia Transit. Try the web app to see the data in action, or learn more about the project.

Learn More
TechMavie Digital Logo

TechMavie Digital Services

Business Registration Number: 202503258894

Copyright 2025 TechMavie Digital. All rights reserved.

Made with ❤️ by

Privacy Notice

This website uses Plausible, a privacy-focused analytics tool. Your data is anonymized and stored in Nuremberg, Germany. No cookies are used and no personal information is collected. I respect your privacy.