PTV Timetable API – API Key and Signature information

Table of Contents
Getting your API key and user Id
How to register for an API key and user Id
How to calculate a signature
Sample code for creating a signature
Example in .net C#
Example in Java
Example in Objective C
Example in Python

Getting your API key and user Id
You’ll need to pass along a signature and a user Id – or “devid” - with every request using HTTP GET.
To calculate the signature, you’ll need the request, which includes your user Id, and an API key.
The API key consists of a 128bit GUID.
Note
The API key and the request (including user Id) are used to calculate a signature for every request.

How to register for an API key and user Id
•	Send an email to APIKeyRequest@ptv.vic.gov.au with the following information in the subject line of the email:
•	“PTV Timetable API – request for key”
•	Once we’ve got your email request, we’ll send you an API key and a user Id by return email.
Note
A high volume of requests may result in a delay in providing you with your API key and user Id. We’ll try to get it to you as soon as we can.

•	We’ll also add your email address to our API mailing list so we can keep you informed about the API.
Note
PTV does not provide technical support for the API.
The “APIKeyRequest” email address is only used to send you the API key and user ID as well as any relevant notifications. Only requests for keys will be responded to.

Note
We’ll be monitoring the use of our API to make sure our mailing list is current and sustainable. If you haven’t used the API for over 3 months, we may disable your API key and remove you from the list – but you can always register for a new key if you need one.

Privacy
Your email address is the only bit of information about you that PTV will hold in its register. View PTV’s privacy policy online.

How to calculate a signature
Once you have obtained your API key and user ID you can calculate a signature.
•	The signature value is a HMAC-SHA1 hash of the completed request (minus the base URL but including your user ID, known as “devid”) and the API key:
•	signature	=	crypto.HMACSHA1(request,key)
•	The calculation of a signature is based on a case-sensitive reading of the request message. This means that the request message used to calculate the signature must not be modified later on in your code or the signature will not work. If you do modify the case of the request message, you will need to calculate a new signature.
For example, “http://timetableapi.ptv.vic.gov.au/v2/healthcheck?devid=ABCXYZ” and “http://timetableapi.ptv.vic.gov.au/v2/HealthCheck?devid=ABCXYZ” require different signatures to be calculated; the same signature will not work for both requests.
•	The signature itself is also case-sensitive

Sample code for creating a signature
Example in .net C#
The following is the .net C#  code snippet for the signature calculation.
Note: key values are used for example purposes only.

string key = "9c132d31-6a30-4cac-8d8b-8a1970834799"; // supplied by PTV
int developerId = 2; // supplied by PTV
string url = "/v2/mode/2/line/787/stops-for-line"; // the PTV api method we want

// add developer id
url = string.Format("{0}{1}devid={2}",url,url.Contains("?") ? "&" : "?",developerId);
System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
// encode key
byte[] keyBytes = encoding.GetBytes(key);
// encode url
byte[] urlBytes = encoding.GetBytes(url);
byte[] tokenBytes = new System.Security.Cryptography.HMACSHA1(keyBytes).ComputeHash(urlBytes);
var sb = new System.Text.StringBuilder();
// convert signature to string
Array.ForEach<byte>(tokenBytes, x => sb.Append (x.ToString("X2")));
// add signature to url
url = string.Format("{0}&signature={1}",url,sb.ToString());

// extra code to add base URL – the resultant url should be:
//  http://timetableapi.ptv.vic.gov.au/v2/mode/2/line/787/stops-for-line?devid=2&signature=D5474F344CDAA7B92F2253169F6C1D66C1A15001

Example in Java
The following is the Java code snippet for the signature calculation.
Note: key values are used for example purposes only.

   /**
     * Method to demonstrate building of Timetable API URL 
     * 
     * @param baseURL    - Timetable API base URL without slash at the end ( Example :http://timetableapi.ptv.vic.gov.au ) 
     * @param privateKey - Developer Key supplied by PTV (((Example :"9c132d31-6a30-4cac-8d8b-8a1970834799")
     * @param uri - Request URI with parameters(Example :/v2/mode/0/line/8/stop/1104/directionid/0/departures/all/limit/5?for_utc=2014-08-15T06:18:08Z)
     * @param developerId- Developer ID supplied by PTV 
     * @return Complete URL with signature
     * @throws Exception
     * 
     */
    public String buildTTAPIURL(final String baseURL, final String privateKey, final String uri,
            final int developerId) throws Exception
    {
        
        String HMAC_SHA1_ALGORITHM = "HmacSHA1";
        StringBuffer uriWithDeveloperID = new StringBuffer().append(uri).append(uri.contains("?") ? "&" : "?")
                .append("devid=" + developerId);
        byte[] keyBytes = privateKey.getBytes();
        byte[] uriBytes = uriWithDeveloperID.toString().getBytes();
        Key signingKey = new SecretKeySpec(keyBytes, HMAC_SHA1_ALGORITHM);
        Mac mac = Mac.getInstance(HMAC_SHA1_ALGORITHM);
        mac.init(signingKey);
        byte[] signatureBytes = mac.doFinal(uriBytes);
        StringBuffer signature = new StringBuffer(signatureBytes.length * 2);
        for (byte signatureByte : signatureBytes)
        {
            int intVal = signatureByte & 0xff;
            if (intVal < 0x10)
            {
                signature.append("0");
            }
            signature.append(Integer.toHexString(intVal));
        }
        StringBuffer url = new StringBuffer(baseURL).append(uri).append(uri.contains("?") ? "&" : "?")
                .append("devid=" + developerId).append("&signature=" + signature.toString().toUpperCase());

        return url.toString();

    }

Example in Objective C
The following is the Objective C code snippet for the signature calculation.
Note: key values are used for example purposes only.

-(NSURL*) generateURLWithDevIDAndKey:(NSString*)urlPath {
    
    NSString *hardcodedURL = @” http://timetableapi.ptv.vic.gov.au”;
    NSString *hardcodedDevID = @”developerID provided by PTV”;
    NSString *hardcodedkey = @”developer key provided by PTV”;
    
/*    urlPath = @" http://timetableapi.ptv.vic.gov.au/v2/mode/2/line/787/stops-for-line";
*/
    NSRange deleteRange ={0,[hardcodedURL length]};
    NSMutableString *urlString = [[NSMutableString alloc]initWithString:urlPath];
    [urlString deleteCharactersInRange:deleteRange];
    if( [urlString containsString:@"?"])
        [urlString appendString:@"&"];
    else
        [urlString appendString:@"?"];
    
    [urlString appendFormat:@"devid=%@",hardcodedDevID];

    const char *cKey  = [hardcodedkey cStringUsingEncoding:NSUTF8StringEncoding];
    const char *cData = [urlString cStringUsingEncoding:NSUTF8StringEncoding];
    unsigned char cHMAC[CC_SHA1_DIGEST_LENGTH];
    CCHmac(kCCHmacAlgSHA1, cKey, strlen(cKey), cData, strlen(cData), cHMAC);
    
    NSString *hash;
    
    NSMutableString* output = [NSMutableString stringWithCapacity:CC_SHA1_DIGEST_LENGTH * 2];
    
    for(int i = 0; i < CC_SHA1_DIGEST_LENGTH; i++)
        [output appendFormat:@"%02x", cHMAC[i]];
    hash = output;
    
    NSString* signature = [hash uppercaseString];
    NSString *urlSuffix = [NSString stringWithFormat:@"devid=%@&signature=%@", hardcodedDevID,signature];
    
    NSURL *url = [NSURL URLWithString:urlPath];
    NSString *urlQuery = [url query];
    if(urlQuery != nil && [urlQuery length] > 0){
        url = [NSURL URLWithString:[NSString stringWithFormat:@"%@&%@",urlPath,urlSuffix]];
    }else{
        url = [NSURL URLWithString:[NSString stringWithFormat:@"%@?%@",urlPath,urlSuffix]];
    }
    
    return url;
}

Example in Python
The following is the Python code snippet for the signature calculation (our thanks to Serge in the developer community for providing this after the initial API release in 2014).
Note: key values are used for example purposes only.

from hashlib import sha1
import hmac
import binascii
def getUrl(request):
    devId = 2
    key = '7car2d2b-7527-14e1-8975-06cf1059afe0'
    request = request + ('&' if ('?' in request) else '?')
    raw = request+'devid={0}'.format(devId)
    hashed = hmac.new(key, raw, sha1)
    signature = hashed.hexdigest()
    return 'http://tst.timetableapi.ptv.vic.gov.au'+raw+'&signature={1}'.format(devId, signature)
print getUrl('/v2/healthcheck')