BYTETOOLS

Amtraker (Amtrak) API

Free unofficial Amtrak API with no key: live train positions, delays, consists and every station with coordinates and scheduled services. Tested example and live response.

No API key requiredCORS enabledHTTPSFree tier

Endpoint tested and returned HTTP 200 on 2026-08-21

What is the Amtraker (Amtrak) API?

Amtraker is a free, key-free API for Amtrak data. It serves live train positions with delay information and per-stop timings, plus a complete station directory giving coordinates, timezone, street address and the trains scheduled to call at each one.

Amtrak publishes no public developer API, so everything in the American passenger rail ecosystem is reverse-engineered from the map on its own website. Amtraker does that work and re-exposes it as clean, documented JSON — which is why it has become the de facto source for hobbyist trackers, station displays and delay-analysis projects.

The station response is keyed by station code rather than being an array, so `stations.ABQ` addresses Albuquerque directly with no scanning. Each record carries a `trains` array listing the services that call there, using train identifiers in the form `3-19` — route number and departure day — which is how Amtrak distinguishes several instances of the same long-distance service running simultaneously over a multi-day journey. The `tz` field matters more here than in most countries: the Southwest Chief crosses four time zones, and comparing raw timestamps without it produces nonsense.

Quick facts

Base URL
https://api-v3.amtraker.com/v3
Authentication
No API key or account. Unofficial community project; not affiliated with or endorsed by Amtrak.
Rate limit
No published quota. Positions refresh on Amtrak's own cadence of a few minutes, so polling faster gains nothing.
Pricing
Free and open source.
CORS
Enabled — callable directly from browser JavaScript
Official docs
Read the docs

How to use the Amtraker (Amtrak) API

Every request below was executed against the live API on 2026-08-21, and the response shown is the real body it returned — not an illustration.

1. Fetch every Amtrak station with coordinates and services

GET https://api-v3.amtraker.com/v3/stations

curl
curl 'https://api-v3.amtraker.com/v3/stations'
JavaScript (fetch)
const res = await fetch("https://api-v3.amtraker.com/v3/stations");
if (!res.ok) throw new Error(`Request failed: ${res.status}`);
const data = await res.json();
console.log(data);
Python (requests)
import requests

res = requests.get("https://api-v3.amtraker.com/v3/stations", timeout=20)
res.raise_for_status()
print(res.json())
Response — HTTP 200 (truncated)
{
  "ABE": {
    "name": "Aberdeen",
    "code": "ABE",
    "tz": "America/New_York",
    "lat": 39.50844700040231,
    "lon": -76.1632600000959,
    "hasAddress": true,
    "address1": "18 East Bel Air Avenue",
    "address2": "",
    "city": "Aberdeen",
    "state": "MD",
    "zip": "21001-3701",
    "trains": []
  },
  "ABN": {
    "name": "Absecon",
    "code": "ABN",
    "tz": "America/New_York",
    "lat": 39.424040999819525,
    "lon": -74.50147500012103,
    "hasAddress": true,
    "address1": "Shore Road and Ohio Avenue",
    "address2": "",
    "city": "Absecon",
    "state": "NJ",
    "zip": "08201",
    "trains": []
  },
  "ABQ": {
    "name": "Albuquerque",
    "code": "ABQ",
    "tz": "America/Denver",
    "lat": 35.082061000451944,
    "lon": -106.64797500045553,
    "hasAddress": true,
    "address1": "320 1st Street SW",
    "address2": "",
    "city": "Albuquerque",
    "state": "NM",
    "zip": "87102-3405",
    "trains": [
      "3-19",
      "3-20",
      "4-19",
      "4-20"
    ]
  },
  "ACA": {
    "name": "Antioch-Pittsburg",
    "code": "ACA",
    "tz": "America/Los_Angeles",
    "lat": 38.017699999685725,
    "lon": -121.81602400045233,
    "hasAddress": true,
    "address1": "100 I Street",
    "address2": "",
    "city": "Antioch",
    "state": "CA",
    "zip": "94509-1122",
    "trains": [
      "718-20"
    ]
  },
  "ACD": {
    "name": "Arcadia Valley",
    "code": "ACD",
    "tz": "America/Chicago",
    "lat": 37.592161000273954,
    "lon": -90.62440299987063,
    "hasAddress": true,
    "address1": "13700 Highway 21",
    "address2": "",

Parameters

ParameterTypeRequiredDescription
(stations)pathOptional`/stations` returns every station keyed by its three-letter code. stations
(one station)pathOptional`/stations/{code}` returns a single station. ABQ
(trains)pathOptional`/trains` returns every train currently running, with positions and stop timings. trains
(one train)pathOptional`/trains/{number}` filters to one route number, which may return several active instances. 3

Response fields

(object keys)string
Three-letter Amtrak station codes — ABE, ABN, ABQ. The response is an object, not an array.
name / codestring
Station name and its code.
tzstring
IANA timezone for the station. Essential on routes that cross zones, which most long-distance services do.
lat / lonfloat
Station coordinates as plain numbers.
hasAddress / address1 / city / state / zipboolean / string
Street address where one exists. Some rural stops are platforms with no address at all.
trainsarray
Train identifiers scheduled to call here, in `route-day` form such as "3-19".
(trains endpoint) trainNum, routeName, velocity, headingmixed
On `/trains`: the service number, route name, speed and direction of travel.
(trains endpoint) stations[].schDep / arr, postCmntstring
Scheduled and actual times per stop, plus Amtrak's own delay comment such as "12 minutes late".

What you can build with the Amtraker (Amtrak) API

  • Build a live Amtrak train map
  • Show a departure board for a specific station
  • Alert a passenger when their train is running late
  • Analyse on-time performance across a route over time
  • Plot the full station network with accurate coordinates

Common errors and how to fix them

Iterating the stations response yields nothing

It is an object keyed by station code, not an array.

Fix: Use `Object.values()` or the equivalent. This shape is convenient for lookup and surprising if you expected a list.

Times compare incorrectly across a route

Stations sit in different time zones and the `tz` field is per-station.

Fix: Convert every timestamp to UTC before comparing. The Southwest Chief alone spans four zones.

A train identifier has a suffix

Identifiers are `route-day`, so one route number has several concurrent instances on multi-day services.

Fix: Match on the full identifier. Filtering on the route number alone conflates trains that departed on different days.

Data goes stale or the API is briefly unavailable

It depends on Amtrak's own undocumented endpoints, which change without notice.

Fix: Fail gracefully and cache the last good response. This is an unofficial source and it will occasionally break when Amtrak changes something.

Amtraker (Amtrak) API — frequently asked questions

Is the Amtrak API free?

Yes. Amtraker is a free, open-source community project with no key or account. It is not affiliated with Amtrak, which publishes no public developer API of its own.

Can I get live train positions?

Yes, from `/trains`, which returns every service currently running with position, speed, heading and per-stop scheduled and actual times, including Amtrak's own delay comments.

Why do train identifiers look like 3-19?

The first part is the route number and the second is the day of the month the service departed. Long-distance trains take more than a day end to end, so several instances of the same route are en route simultaneously and need distinguishing.

How reliable is it?

It is a reverse-engineered wrapper around Amtrak's internal endpoints, so it can break when Amtrak changes them. Cache the last good response and degrade gracefully rather than assuming continuous availability.

Tools that pair with this API

Amtraker (Amtrak) is an independent third-party service and is not affiliated with ByteTools or ByteVancer. Details on this page were verified on 2026-08-21; always check the official documentation before relying on this API in production, as terms and limits can change.