PT OPS

Trains

Create, read, update, and delete trains and their routes.

Last updated: October 8, 2026

A train document contains trainNumber, operator, extraTrain, routeNumber, continuesAs, a static defaultRoute (scheduled timetable, using hour/minute time objects), and a live currentRoute (actual dates used for real-time tracking), plus currentFormation, position, and messages.

POST /trains Authentication required

Creates a new train. defaultRoute is validated and converted into a UTC currentRoute automatically.

Body

{
  "trainNumber": "301",
  "operator": "PTR",
  "extraTrain": false,
  "routeNumber": "R81",
  "continuesAs": null,
  "defaultRoute": [
    {
      "name": "Skogviken",
      "code": "SK",
      "type": "stasjon",
      "track": "1",
      "arrival": { "hours": 8, "minutes": 0 },
      "departure": { "hours": 8, "minutes": 2 },
      "stopType": "passenger"
    }
  ]
}

Returns 400 for missing fields or an invalid route, 409 if trainNumber already exists.

GET /trains Public

Returns all trains, or filters by query string (e.g. /trains?operator=PTR). Query parameters are matched against top-level train fields. Returns 200 with a JSON array of train documents (see the example below), or [] if no trains match.

Response (200 OK)

[
  {
    "_id": "665f1c2e9b1e8a0012a4b7c3",
    "trainNumber": "301",
    "operator": "PTR",
    "extraTrain": false,
    "routeNumber": "R81",
    "continuesAs": null,
    "defaultRoute": [
      {
        "name": "Skogviken",
        "code": "SK",
        "type": "stasjon",
        "track": "1",
        "arrival": { "hours": 8, "minutes": 0 },
        "departure": { "hours": 8, "minutes": 2 },
        "stopType": "passenger",
        "passed": false,
        "cancelledAtStation": false
      }
    ],
    "currentRoute": [
      {
        "name": "Skogviken",
        "code": "SK",
        "type": "stasjon",
        "track": "1",
        "arrival": "2026-10-08T06:00:00.000Z",
        "departure": "2026-10-08T06:02:00.000Z",
        "stopType": "passenger",
        "passed": false,
        "cancelledAtStation": false
      }
    ],
    "currentFormation": {},
    "position": [],
    "messages": [],
    "__v": 0
  }
]

Times in defaultRoute are local Norway time as hours/minutes objects. Times in currentRoute are UTC ISO 8601 strings. messages entries look like { "yellow": false, "message": { "NOR": "...", "ENG": "..." }, "from": "<ISO date>", "to": "<ISO date>" }.

GET /trains/:trainNumber Public

Returns a single train document by its train number (same shape as one element of GET /trains), or 404 with { "error": "Train not found" } if it doesn't exist.

Example: GET /trains/301 → 200 with a single train object.

GET /trains/:trainNumber/norwayTimeRoute Public

Returns the train's currentRoute with arrival/departure times formatted in Norway local time (dd.MM.yyyy HH:mm) instead of raw UTC dates. 404 if the train doesn't exist.

Response (200 OK)

[
  {
    "name": "Skogviken",
    "code": "SK",
    "type": "stasjon",
    "track": "1",
    "arrival": "08.10.2026 08:00",
    "departure": "08.10.2026 08:02",
    "stopType": "passenger",
    "passed": false,
    "cancelledAtStation": false
  }
]

arrival and departure are null if the stop has no time set.

PATCH /trains/:trainNumber Authentication required

Partially updates a train. Any arrival/departure values in the body are converted to Date objects. Returns 409 if renaming to a trainNumber already in use, 404 if the train doesn't exist.

PUT /trains/:trainNumber Authentication required

Replaces a train entirely (upserts). Body must be { "trainData": { ... } } containing all of: trainNumber, operator, extraTrain, defaultRoute, currentRoute, currentFormation, position.

Returns 409 if changing to a trainNumber that's already used by another train.

DELETE /trains/:trainNumber Authentication required

Deletes a train and its associated FIDO train claim. Returns 204 No Content on success, 404 if not found.