Last week on March 7 Public Transport Victoria finally released something many Melbourne coders and app developers have been waiting for – a public API to query their timetable data.
Unfortunately the new API isn’t perfect – it doesn’t meet the Google-defined GTFS standard that many existing apps support, and no real-time arrival data is available – for trams you have to turn to TramTracker, and for trains and buses you’re on your own.
Despite the above limitations, I jumped into playing around with the API. The full set of documentation can be found at www.data.vic.gov.au, and after I made my API key request on the evening of March 6, I received a reply yesterday – March 11.
With my developer ID and security key received, the first thing to try out is the ‘healthcheck’ endpoint. Each API request needs to be digitally signed with a HMAC-SHA1 hash – this ensures that each request to the PTV servers is coming from a registered developer – and the healthcheck page allows a developer to test if their requests are being built up correctly.
For some people, working out the HMAC-SHA1 signature of each request is easy – the API documentation includes sample code in C#, Java and Objective-C to do just that. Unfortunately for me, my random hacking about is done in PHP, so I needed to roll my own version.
(jump to the end of my sample code)
My initial attempt generated something that looked like a HMAC-SHA1 signature, but it didn’t pass validation – I screwed something up! An hour or so of bashing my head against the wall followed, as I played around with Base64 encoding and byte arrays. but it still wasn’t working
I then tried a different tack – getting the sample C# code working in Powershell. For such an odd tactic it was simple enough to achieve, and I was able to get the code to run and generating a valid signature, which I used to make my first valid API hit. From there I was able to hack about my PHP code until it generated the same signature as the C# code generated – the bit I missed was the upper casing.
The end result from PTV – a small snippet of JSON.
Sample code
Here is the method I wrote to take an API endpoint URL (for example “/v2/healthcheck”) and build up a valid signed URL to request data from.
function generateURLWithDevIDAndKey($apiEndpoint, $developerId, $key) { // append developer ID to API endpoint URL if (strpos($apiEndpoint, '?') > 0) { $apiEndpoint .= "&"; } else { $apiEndpoint .= "?"; } $apiEndpoint .= "devid=" . $developerId; // hash the endpoint URL $signature = strtoupper(hash_hmac("sha1", $apiEndpoint, $key, false)); // add API endpoint, base URL and signature together return "http://timetableapi.ptv.vic.gov.au" . $apiEndpoint . "&signature=" . $signature; } |
And here is a sample usage of the above method. (note the sample data for key and developer ID!)
$key = "9c132d31-6a30-4cac-8d8b-8a1970834799"; // supplied by PTV $developerId = 2; // supplied by PTV $date = gmdate('Y-m-d\TH:i:s\Z'); $healthcheckEndpoint = "/v2/healthcheck?timestamp=" . $date; $signedUrl = generateURLWithDevIDAndKey($healthcheckEndpoint, $developerId, $key); |
Now all I need to do is build the wonderful app I have in mind…
Code in GitHub
You can find the above sample code on GitHub at https://github.com/wongm/ptv-api-php-test-harness – all you need to do is update the $key and $developerId values with your own credentials, and it should work on your own server.
Footnote
It looks like plenty of other people are interested in the API – here is a media release from Data.Vic, who host it on behalf of PTV.
The recent release of the PTV Timetable API has, not surprisingly, created the highest level of interest and activity for a single data release on Data.Vic.
In the 7 days since the release of the API data record we have seen:
– Over 3500 data record page views
– More than 700 downloads of the API document, and
– Close to 100 API key requests
Given the rather limited queries that can be performed through the API, I’m struggling to come up with a good idea for an app beyond the boring examples in the doc provided. Will be interesting to see if anyone can use it in a creative way.
Transport information and journey planning is a pretty well solved problem – plenty of incredibly smart people around the world have built amazing apps that consume General Transit Feed Specification (GTFS) feeds and present it in different ways.
The only app ideas I’ve had so far are for displaying data in interesting ways, but not actually indispensable in everyday life.
Hey mate,
Just wanted to say that I had the exact same problem, and you saved me presumably hours of angst. Thanks for writing this up, and I look forward to seeing your app.
I’ve also had someone else on Twitter point out they had the same issue – getting caught out by the uppercase signature requirement! I would have never discovered it if I didn’t compare the results from my PHP code to PTV’s C# reference implementation.
Thank you thank you thank you. I have exactly the same problem, and I have been racking my brains and bleeding from the eyes for two days trying to get this to work. There is no technical assistance from PTV at all, but your solution worked for me straight off.
Glad that my post helped you out – creating a valid signature seems to be the hardest bit of using the API!
I’m guessing the reason they don’t give technical assistance is they don’t want to be swamped with people asking questions like “how do I build an iPhone app” which have nothing to do with their API.
Your help solving the access problem has meant I’ve been able to develop and publish a simple extension to our website that draws data from the PTV API.
See this link http://www.railmaps.com.au/stationdetails.php?StationSelect=15
The “Next Trains” panel below the map uses the API. At the moment it’s enabled only for stations on the Craigieburn line, and it shows only Metro trains. But I’ll extend it to all stations, lines and modes in coming days.
Thanks again for your help cracking this one.
Good to hear!
[…] a result, I took inspiration from my recent experiments with PTV’s new API, and came up with a simple website to give access to TramTracker […]
Have you managed to get the ‘Specific Next Departures’ working?
I keep getting the message:
{“Error”:”Forbidden (403): Supplied signature is invalid for request.”}
Although my signature/devId combo works for all other requests.
Sounds like an rather odd issue to have it fail on just one method call. I just tested a request to the same method with my PHP implementation of the signature generation, with no issues.
This was the URL I hit:
http://timetableapi.ptv.vic.gov.au/v2/mode/1/line/887/stop/3164/directionid/19/departures/all/limit/1?devid=%5BID%5D&signature=%5BSIG%5D
If you leave out the “1” after the “limit” then the result is a HTTP 404, and if you input an incorrect “directionid” value, then you get an empty JSON result set.
Possibly there is a bug in your signature generation code that is getting tripped up the length of the URL? Using one of the reference implementations with your own developer key would allow you to isolate the issue to an issue with your account, or the signature generation code.
Thanks. I will try once more later in the day.
Regarding the directionid, it is mentioned in the api doc that directionid towards the city is 0, how do we determine the directionid in the opposite direction? That would vary for each line.
The ‘directionid’ parameter isn’t a simple 0/1 value – it is an integer that depends on the current route you are requesting data for.
It appears chaining of API calls will be required to get the relevant ID – from the documentation:
To find out the value for my above example, I called the ‘Broad Next Departures’ method first to see which directions were available at the stop, and then I reused the value in the ‘Specific Next Departures’ call.
One more thing if you can please try for me… Can you please confirm if the
It worked for me – this is for a stop on route 402 somewhere in West Melbourne:
http://timetableapi.ptv.vic.gov.au/v2/mode/2/line/783/stop/23806/directionid/46/departures/all/limit/1?devid=%5BID%5D&signature=%5BSIG%5D
If you get the mode or direction IDs wrong, it returns an empty JSON object.
Thanks Marcus.
Makes sense what you said, however, this chaining of API calls just to get the specific departures, seems like double work.
Hi Mike,
I used the signature code that has given by PTV and I get the same error as yours – {“Error”:”Forbidden (403): Supplied signature is invalid for request.”}
Have you able to sort that out?
Now it works for me 🙂
@Ash – Cool.
So how did you fix it, for those playing along at home? 😛
[…] for every API call and provides example code for Objective C, C#, Java and Python. I found Marcus Wong’s PHP implementation, however, to be the most useful for writing a
[…] Back in March 2014 Public Transport Victoria finally opened up the application program interface (API) which powers their mobile apps, so I decided to have a play around with it. […]