REST API
Introduction
MotorsportReg.com provides a RESTful API. If you wish to create a software application that uses our service, then you will need to know which resources are available, what their locations are, what methods each resource supports, and what the responses might be. All this information is available on this page.
Who Is This For?
Our REST API is not intended for regular web users. This API requires technical skills and is intended for programmers, developers and hackers who wish to access our system programmatically for integration with their own systems.
Authentication
Many API requests require a valid username and password to authenticate your requests as detailed below in the resources section. There are two ways to authenticate:
- Use your existing MSR administrative username and password
- Account must have read and write access
- Each request must pass an X-Organization-Id header which contains the 35-character unique organization ID to access
- Use custom API credentials provided by MotorsportReg.com (deprecated as we prefer you to use #1)
For questions about credentials or authentication, contact us.
For user agents that support it, we have a crossdomain.xml file located at http://api.motorsportreg.com/crossdomain.xml. We also respond to every request with the HTTP Header 'Access-Control' set to 'allow <*>'. This permits building mashups with our data from any domain.
Licensing & Attribution
Use of the API is subject to prior approval and may be revoked at any time without warning. Content that is displayed must include one of the following three snippets of code exactly as it appears and display the badge at its original size (190x30). We may provide other sizes upon request.
(white background)
<a href="http://www.MotorsportReg.com/"><img src="http://msr-hotlink.s3.amazonaws.com/msr_red_on_white_190x30.gif" height="30" width="190" alt="Online registration and event management service for motorsport events powered by MotorsportReg.com" title="Online registration and event management service for motorsport events powered by MotorsportReg.com" /></a>-
(transparent background)
<a href="http://www.MotorsportReg.com/"><img src="http://msr-hotlink.s3.amazonaws.com/msr_red_on_transparent_190x30.png" height="30" width="190" alt="Online registration and event management service for motorsport events powered by MotorsportReg.com" title="Online registration and event management service for motorsport events powered by MotorsportReg.com" /></a>
<a href="http://www.MotorsportReg.com/"><img src="http://msr-hotlink.s3.amazonaws.com/msr_black_on_white_190x30.gif" height="30" width="190" alt="Online registration and event management service for motorsport events powered by MotorsportReg.com" title="Online registration and event management service for motorsport events powered by MotorsportReg.com" /></a>
<a href="http://www.MotorsportReg.com/"><img src="http://msr-hotlink.s3.amazonaws.com/msr_white_on_black_190x30.gif" height="30" width="190" alt="Online registration and event management service for motorsport events powered by MotorsportReg.com" title="Online registration and event management service for motorsport events powered by MotorsportReg.com" /></a>
Resources and Locations
A REST interface presents resources at published locations. Here are the locations of the MotorsportReg.com REST API resources.
Unauthenticated
- GET /rest/calendars/organization/{organization_id}
- Return a calendar of events for a single organization/club (ProAutoSports, BMW CCA GGC, ...)
- Supports geospatial filtering by passing URL parameter "postalcode" with a five-digit American Zip Code or six-character Canadian Postal Code. Optionally specify "radius" which defaults to 300 miles.
- GET /rest/calendars/venue/{venue_id}
- Return a calendar of events for a single venue (Laguna Seca, Road Atlanta, ...)
- GET /rest/calendars/type/{type_id}
- Return a calendar of events for a single type of event (HPDE, Autocross, Rally, ...)
- Supports geospatial filtering by passing URL parameter "postalcode" with a five-digit American Zip Code or six-character Canadian Postal Code. Optionally specify "radius" which defaults to 300 miles.
- GET /rest/events/{event_id}/entrylist
- Unauthenticated request returns the same data as the public attendee list. The contents of the list are controlled by the organizer and may return a limited or empty result set. For the full assignment list, authenticate first and use the assignments resource.
- GET /rest/postalcodes/{postal_code}
- Return postal codes within 300 miles of the passed value. Optionally filter with URL parameter "radius" to another value.
Requires Authentication
- GET /rest/calendars
- All events from all calendars starting today or later.
- Supports geospatial filtering by passing URL parameter "postalcode" with a five-digit American Zip Code or six-character Canadian Postal Code. Optionally specify "radius" which defaults to 300 miles.
- GET /rest/events/{event_id}/attendees
- Authenticated request returns a complete list of attendees for an event that handles registration through MSR.
- GET/PUT/POST/DELETE /rest/events/{event_id}/attendees/{attendee_id}/checkin
- Read, create, update or remove the check in history and notes associated with an attendee
- GET /rest/events/{event_id}/assignments
- Authenticated request returns a complete list of assignments (aka entries) for an event that handles registration through MSR. Provides internal links to members and vehicles to obtain more details about an assignment.
- GET /rest/events/{event_id}/segments/{segment_id}/assignments
- Return a list of assignments for a single segment of an event
- GET /rest/members
- Return a list of all members
- GET /rest/members/{member_id}
- Return a single member
- GET /rest/members/{member_id}/vehicles
- Return a list of vehicles for a single member
- GET /rest/members/{member_id}/vehicles/{vehicle_id}
- Return a single vehicle for a single member
- GET /rest/members/{member_id}/logbook
- Return a list of log book entries about a single member
- GET /rest/logbooks/types
- Return a list of log book entry types
- GET/PUT/DELETE /rest/logbooks/{logbook_entry_id}
- Return, update or delete a single log book entry
- POST /rest/logbooks
- Create a log book entry
Future updates will permit accessing details on organizations and venues as well as updating events for authorized clubs.
Status Codes
Each resource location supports a number of methods, which may send or receive a piece of data. All response codes are included in the HTTP Status response header. Possible status codes include:
- 200: Success (upon a successful GET or PUT request)
- 201: Created (upon a successful POST request)
- 204: Success (upon a successful DELETE request)
- 401: Unauthorized (incorrect or missing username and password)
- 403: Authorized but forbidden request
- 404: Resource Not Found
- 405: Method Not Allowed
- 415: Unsupported Media Type
- 500: Application Error
Successful POST requests (e.g., to create a new invoice) will return a status code of 201, include a Location header with the URI of the newly-created resource, and (usually) include the representation in the response.
Successful PUT requests (e.g., to update an existing invoice) will return a status code of 200, and (usually) include the representation in the response.
Successful DELETE requests (e.g., to delete an existing invoice) will return a status code of 204 (No Content) and no body.
Data Formats
If no format is specified, XML is the default. Most resources on api.motorsportreg.com support the following:
| Name | Format |
|---|---|
| application/vnd.pukkasoft+xml | XML representation |
| application/vnd.pukkasoft+json | JSON representation |
Certain resources, notably calendars, also support the following:
| Name | Format |
|---|---|
| application/vnd.pukkasoft+rss | RSS representation |
| application/vnd.pukkasoft+atom | Atom representation |
| application/vnd.pukkasoft+calendar | iCalendar/ics representation |
You may also append the "file extension" to the URL to signal the response format you would like. Use .xml for XML, .json for JSON and so forth.
Authorized Requests
All requests requiring authentication must be sent with a valid username and password or the request will be denied with a 401 Unauthorized response. You can pass a username and password to most HTTP libraries like in this example with cURL:
curl -u userid:password http://api.motorsportreg.com/rest/resource/etc
Most HTTP libraries will handle Basic Authentication details automatically. To do it manually, include an Authorization header with a value like Basic credentials, in every request. The credentials string should be the Base64-encoded version of the string userid:password. For example:
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
If your credentials are correct but you lack sufficient authorization, the request will be denied with a 403 Forbidden response.
Data Compression
Our REST API supports gzip/deflate compression for transmission. You can signal to our API you wish to receive compressed data by sending an additional header:
| Header | Value |
|---|---|
| Accept-Encoding | gzip,deflate |
Your software will need to decompress the data before using it (which may happen automatically). This is especially useful for the full events feed which can include more than 1000 events at a time and may be several megabytes uncompressed.
Testing and Debugging
The best tool to have in your arsenal is Firebug and Poster, two plugins for Firefox, that will let you inspect, modify and view requests sent from your browser to our API. If you prefer to develop from the command line, curl is an HTTP client that is very flexible and is used in some of our examples below. We also would like to suggest that you try using the apigee developer console which lets you consume a REST API from a web browser with a lot of flexibility. Point it at our resources and you'll see the power quickly.
Example Interactions
Most developers use cURL to test and debug RESTful APIs. This is a simple command-line tool that you can use to get up to speed with our API. We will be providing code samples for common languages in the future.
To retrieve a representation, use the GET method. For example (using cURL's -X option to specify the request method):
curl -u userid:password -H 'Accept: application/vnd.pukkasoft+xml' \
-X GET http://api.motorsportreg.com/rest/calendars
Using an existing administrative account, pass in the X-Organization-Id header:
curl -u userid:password -H 'X-Organization-Id: {your-id-here}' -H 'Accept: application/vnd.pukkasoft+xml' \
-X GET http://api.motorsportreg.com/rest/calendars
To create a new resource, use the POST method on a collection. The body of the request should be an XML or JSON representation of the member resources. For example, (using cURL's -d option to provide a request body):
curl -u userid:password -H 'Accept: application/vnd.pukkasoft+xml' \
-d '<?xml version="1.0" encoding="UTF-8"?>XML Data' -X POST http://api.motorsportreg.com/rest/calendars
The PUT method changes existing resources. The body of the request should be an XML or JSON representation of the member resource. For example:
curl -u userid:password -H 'Accept: application/vnd.pukkasoft+xml' \
-d '<?xml version="1.0" encoding="UTF-8"?>XML Data' -X PUT http://api.motorsportreg.com/rest/calendars/event_id
The DELETE method permanently removes a resource. For example:
curl -u userid:password -H 'Accept: application/vnd.pukkasoft+xml' \
-X DELETE http://api.motorsportreg.com/rest/calendars/event_id
Note that in some cases, deleting a resource will cascade to related resources. For example, deleting an event will also delete the attendees associated with the event.
Because not all HTTP libraries support the PUT and DELETE methods, they can be tunneled through POST by including a _method query parameter in the request, with a value of either PUT or DELETE:
curl -u userid:password -H 'Accept: application/vnd.pukkasoft+xml' \
-d '<?xml version="1.0" encoding="UTF-8"?>XML Data' -X POST http://api.motorsportreg.com/rest/calendars?_method=PUT
ColdFusion Samples
MotorsportReg.com uses Adobe ColdFusion. We whipped up a few samples to give you an idea for how to use our first resource, events:
<cfhttp username="user" password="password" url="http://api.motorsportreg.com/rest/calendars" method="get">
<cfhttpparam type="header" name="Accept" value="application/vnd.pukkasoft+xml" />
</cfhttp>
<-- dump the entire results -->
<cfdump var="#cfhttp#" label="Full Dump" />
<-- list just the event names -->
<cfset x = xmlSearch(xmlParse(cfhttp.FileContent), "/response/events/event/name/") />
<cfloop from="1" to="#arrayLen(x)#" index="ii">
<cfoutput>#x[ii].xmlText#<br /></cfoutput>
</cfloop>
If you authenticate using an existing administrative account, pass in the Organization ID as a header:
<cfhttp username="user" password="password" url="http://api.motorsportreg.com/rest/calendars" method="get">
<cfhttpparam type="header" name="Accept" value="application/vnd.pukkasoft+json" />
<cfhttpparam type="header" name="X-Organization-Id" value="{your-id-here}" />
</cfhttp>
PHP Samples
Here is a simple example of fetching the events as JSON using PHP and caching them in a file. You must have the cURL extension compiled in which is common in most builds of PHP. You can check by using phpinfo() which will include details about cURL if it is available.
<?php
// function handles requesting and caching the json
function request_cache($url, $dest_file, $timeout, $flush = false)
{
if (!file_exists($dest_file) || filemtime($dest_file) < (time()-$timeout) || $flush === TRUE)
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt ($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30);
curl_setopt($ch, CURLOPT_TIMEOUT, 90);
// set content-type and authorization headers
$headers = array(
"Accept: application/vnd.pukkasoft+json",
);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
$data = curl_exec($ch);
curl_close($ch);
$tmpf = tempnam('/tmp','motorsportreg-api-request');
if (!$fp = fopen($tmpf, 'w'))
{
echo "Cannot open temporary file ($tmpf)";
exit;
}
if (fwrite($fp, $data) === FALSE)
{
echo 'Failed to write data to file';
exit;
}
fclose($fp);
if (!rename($tmpf, $dest_file))
{
echo 'Failed to rename temporary file to cache file! This usually happens because PHP cannot write to the file: ' . $dest_file . '. Check permissions or consider placing the file in /tmp';
}
return $data;
}
else
{
return file_get_contents($dest_file);
}
}
// uri to data, cached for 6 hours at a time
// if you receive "failed to rename temporary file..." errors, try changing the 2nd argument to /tmp/apimotorsportregcom.json
$json = request_cache(URL_TO_THE_RESOURCE, './apimotorsportregcom.json', 21600);
$data = json_decode($json, true);
$events = $data["response"]["events"];
// now display the events
echo '<table>';
if (count($events))
{
foreach($events as $event)
{
$dte = strtotime($event["start"]);
echo '<tr><th scope="col">' . date("m/d/y", $dte) . '</th><th scope="col"><a href="' . $event["detailuri"] . '">' . $event["venue"]["name"] . '</a></th><th scope="col">' . $event["venue"]["city"] . ', ' . $event["venue"]["region"] . '</th></tr>';
}
}
else
{
echo '<tr><th scope="col" colspan="3" class="CLD style1">No events matched your search!</th></tr>';
}
echo '</table>';
?>
Javascript Samples
Javascript is the language du jour for building interactive applications and mash-ups and we support returning data as JSON and JSONP. We posted some REST consumer examples in our blog and have included one below for creating a per-organization calendar list. This sample uses the popular Javascript library jQuery.
<html>
<head>
<title>MotorsportReg.com API Test</title>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
</head>
<body>
<script>
$(document).ready(function()
{
$.getJSON('http://api.motorsportreg.com/rest/calendars/organization/{your-id-here}.jsonp?jsoncallback=?'
,{
dataType: "jsonp"
,cacheBuster: new Date()
}
,function(json)
{
var tbl = '<table>';
$.each(json.response.events, function(i, evt)
{
tbl += '<tr>';
tbl += '<td><a href="' + evt.detailuri + '">' + evt.name + '</a></td>';
tbl += '<td>' + evt.type + '</td>';
tbl += '<td>' + evt.venue.city + ', ' + evt.venue.region + '</td>';
tbl += '<td>' + evt.start + '</td>';
tbl += '<td>' + evt.end + '</td>';
tbl += '<td>' + ((typeof(evt.registration.start) === 'undefined') ? '' : evt.registration.start) + '</td>';
tbl += '</tr>';
});
tbl += '<' + '/table>';
$('#msrCalendar').append(tbl);
}
);
});
</script>
<div id="msrCalendar"></div>
</body></html>
IFRAME Sample
In certain cases, it's possible to ask our API to return the results as HTML such that they may be embedded into another site with one line of code. Currently this only works for the per-organization calendar because it does not require authentication but may be expanded in time. Never embed your API key in a public web page or code snippet!
<iframe src="http://api.motorsportreg.com/rest/calendars/organization/EF396322-CFC3-7452-49FF38E2C1A34BD0.html" height="200" width="100%" style="border: 1px solid #ccc; margin: 10px 0;"></iframe>
RSS/Atom/iCalendar Formats
In certain cases, it's possible to ask our API to return the results as a common format such as RSS, Atom or iCalendar. These feeds are easily digested by many applications because of their ubiquity. This example shows the per-club (unauthenticated) calendar feed for each of the three types. The api.motorsportreg.com feeds are NOT designed for end-user consumption. They may change over time or move locations so we recommend that you retrieve the data, cache it and serve it from your own application.
http://api.motorsportreg.com/rest/calendars/organization/{your-id-here}.rss (RSS 2.0)
http://api.motorsportreg.com/rest/calendars/organization/{your-id-here}.atom (Atom 1.0)
http://api.motorsportreg.com/rest/calendars/organization/{your-id-here}.ics (iCalendar)