JSON API for British rail fares queries

Home Page

In order to gauge interest in a professionally supported version, I have decided to publicise the API that the BR Fares website uses to access the fares database. Access to the API is currently free and unrestricted, and it will remain so for low volume use. However very heavy or non-compressed use can currently expect to be blocked—but I don't want to rule out the possibility of introducing a charge for regular use of a professionally-supported API in the future. Queries regarding the API may be directed to info@brfares.com.

Using the API

Using the API is a simple two-step process, or three-step if you wish to query railcard-discounted fares. It involves making HTTP requests to a specified URL, and parsing the response received in JavaScript Object Notation (JSON). API clients must support receiving results in compressed format, and should set the Accept-Encoding HTTP header to indicate which compression format they prefer. The API server supports deflate and gzip compression. The server will include a response header of

Access-Control-Allow-Origin: *
to support Cross-Origin Resource Sharing and allow the API to be called from JavaScript running in another website.

Step 1: Find the unique code corresponding to the location(s) of interest

Send a HTTP request to

http://api.brfares.com/ac_loc?term=XXXXXX
where XXXXXX is the first few letters from the location of interest. E.g. a request to
http://api.brfares.com/ac_loc?term=lds
returns the following JSON
[
{"label":"(LDS) LEEDS.","value":"LEEDS.","code":"LDS"}
]
and
http://api.brfares.com/ac_loc?term=oxf
returns
[
{"label":"(OXF) OXFORD","value":"OXFORD","code":"OXF"},
{"label":"OXFORD CIRC UND","value":"OXFORD CIRC UND","code":"ZOC"},
{"label":"OXFORD+BUS","value":"OXFORD+BUS","code":"J931"}
]
Make a note of the code parameter for the location you are interested in.

Step 2: Load all fares between two locations

Picking the code values out of the above responses, you can then do a fares query for Leeds to Oxford (for example) as follows:
http://api.brfares.com/querysimple?orig=LDS&dest=OXF
which returns
{
  "orig": {"nlc":"8487","crs":"LDS","name":"LEEDS.","code":"LDS"},
  "dest": {"nlc":"3115","crs":"OXF","name":"OXFORD.","code":"OXF"},
  "travelcard_orig": false,
  "travelcard_dest": false,
  "zonal_orig": false,
  "zonal_dest": false,
  "railcard": {"code":"   ","name":"PUBLIC"},
  "railcard_valid": true,
  "fares": [
  {
    "category": {"code":0,"desc":"WALKUP"},
    "flow_orig": {"nlc":"Q083","crs":"","name":"","code":"Q083"},
    "flow_dest": {"nlc":"Q475","crs":"","name":"","code":"Q475"},
    "group_orig": {},
    "group_dest": {},
    "travelcard_orig": false,
    "travelcard_dest": false,
    "zonal_orig": false,
    "zonal_dest": false,
    "fare_setter": {"code":"IXC","name":"CROSSCOUNTRY"},
    "route": {"code":700,"name":"NOT VIA LONDON"},
    "london_code": {"code":0,"desc":"NO"},
    "ticket": {"code":"7DF","name":"SEVEN DAY   1ST","type": {"code":2,"desc":"SEASON"},
               "tclass": {"code":0,"desc":"1ST"}},
    "restriction_code": "  ",
    "railcard_restrictions": [],
    "reversible": true,
    "adult": {"status": {"code":"000","name":"ADULT","id":0}, "fare": 64000},
    "child": {"status": {"code":"001","name":"CHILD","id":1}, "fare": 32000}
  },
  {
    "category": {"code":0,"desc":"WALKUP"},
    "flow_orig": {"nlc":"R629","crs":"","name":"","code":"R629"},
    "flow_dest": {"nlc":"R675","crs":"","name":"","code":"R675"},
    "group_orig": {},
    "group_dest": {},
    "travelcard_orig": false,
    "travelcard_dest": false,
    "zonal_orig": false,
    "zonal_dest": false,
    "fare_setter": {"code":"IEC","name":"EAST COAST"},
    "route": {"code":0,"name":"ANY PERMITTED"},
    "london_code": {"code":1,"desc":"YES"},
    "ticket": {"code":"FOR","name":"ANYTIME 1R","type": {"code":1,"desc":"RETURN"},
               "tclass": {"code":0,"desc":"1ST"}},
    "restriction_code": "  ",
    "railcard_restrictions": [],
    "reversible": true,
    "adult": {"status": {"code":"000","name":"ADULT","id":0}, "fare": 41200},
    "child": {"status": {"code":"001","name":"CHILD","id":1}, "fare": 20600}
  },
and so on (with a lot more where that came from!).

Step 3: Adding a railcard to the query

If you want to use a railcard then you can look up the database ID for the railcard by sending a request to

http://api.brfares.com/ac_rlc?term=16-25
which will return something like
[
{"label":"16-25 RAILCARD","value":"YNG 16-25 RAILCARD","code":"YNG"}
]
The unique railcard code can then be added to the fares query URL as follows:
http://api.brfares.com/querysimple?orig=LDS&dest=OXF&rlc=YNG

Further Notes

  1. The location and railcard codes are not likely to change very often, if at all, and may be cached between queries if you wish.
  2. You can replace ?querysimple in the URL with ?queryexpert, to get results formatted differently with a bit more detail.

Interpreting the Data

Note: This is not a full description of all the data returned in a query, and consists merely of a few hints and general pointers.

Location and Railcard ID Codes

All locations have a National Location Code (NLC). This 4-character alphanumeric code uniquely identifies the location within the fares database. Fares locations that are also actual railway stations have in addition a Computer Reservation System (CRS) code. These 3-character alphabetic codes are widely used, although not ideal for uniquely identifying fares locations—since fares exist to lots of places that aren't railway stations (and thus don't have a CRS code), and there are even some duplicate CRS codes (e.g. as of July 2013, ZCW can refer either to Canada Water, or to Canary Wharf DLR station). However NLC codes aren't much used beyond the fares database and ticket encoding, so CRS codes are useful for interfacing with other systems.

Railcards also all have a code in the fares data, e.g. YNG = 16-25 Railcard, NEW = Network Railcard, NGC = Network Gold Card etc. These are fairly consistent and non-changing. Note however that they are different to the discount codes actually printed on tickets.

Fares

The bulk of the JSON data comprising a query result consists of an array of fares available between the origin and destination locations. The relevant and/or interesting parameters associated with each fare are as follows:

category
Possible values are 0 (WALKUP), 1 (QUOTA), 2 (OTHER). Fares that require a reservation to be made in order to be purchased are categorised as quota-controlled fares. Fares priced at 10p or less, with a pence component of 99p or where the remainder after dividing the pounds component by 1000 is £999, or that are neither First Class nor Standard, are categorised as other fares. All others are assumed to be available at the station on the day of travel and are categorised as walk-up fares.
group_orig/group_dest
If either if these is not an empty object, it means that the fare's origin or destination, i.e. what will be printed on the ticket, is derived from a group that covers multiple locations. If zonal_orig/zonal_dest are true it indicates the group is a zonal location (e.g. ZONE U1* LONDN); if travelcard_orig/travelcard_dest are true it indicates the group is a London Travelcard location (e.g. LONDON ZONES 1-6), otherwise it is a normal group location (e.g. LONDON TERMINALS or READING STATIONS).
If group_orig/group_dest are empty, then the origin/destination location printed on the ticket is the same as the query origin/destination.
fare_setter
This indicates the train company or other body responsible for pricing and maintaining the fare
route
This describes the route printed on the ticket, which may restrict the services on which the fare is valid.
london_code
Indicates the cross-London status of the ticket, primarily whether it will operate London Underground ticket barriers for a cross-London journey. This is not necessarily the same thing as whether the ticket is valid via London!
ticket
Includes details of the ticket name, type (single, return or season) and class (first or standard).
restriction_code
If the fare has validity restrictions, this will contain a 2-character alphanumeric code. This is sometimes printed on tickets. An API describing the restrictions is planned for the future, but it will involve a lot of work (they are very complicated!) and is not available yet.
adult.fare/child.fare
Gives the price of the adult and/or child versions of the fare, in pence.

Licensing

The copyright in the fares data is held by Rail Settlement Plan Ltd., and is licensed for all forms of copying, publishing, distribution etc. under the Creative Commons CC BY 2.0 Licence. All third party use of the data from the API is automatically covered by this license.

A credit and link to BRfares.com as the API provider on any website on which it is used would also be very much appreciated.

Home Page