REST API for Racing, Driving and Social event registration

We have a new mailing list for Developer support and REST API announcements. Please subscribe to motorsportreg-api-developers at Google Groups.
we have released free Wordpress & Joomla plugins for displaying an event calendar on your website. Learn more.

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:

  1. 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
  2. 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 https://api.motorsportreg.com/crossdomain.xml. We also respond to every request with the HTTP Header 'Access-Control-Allow-Origin' set to '*'. 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.

Resources and Locations

A REST interface presents resources at published locations. Access them securely over SSL. 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
Optionally append ?archive=true to include events in the past
GET /rest/calendars/organization/{organization_id}/type/{type_id}
Return a calendar for a single organization/club for a single event type
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. Optionally specify "start" and "end" to limit date range with ISO8601 dates like yyyy-mm-dd.
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}/attendees
Authenticated request returns a complete list of attendees including all statuses.
Questions may be included in partial response by passing ?fields=questions in URL
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) including all statuses. Provides internal links to profiles and vehicles to obtain more details about an assignment.
Co-drivers/Teams may be included in partial response by passing ?fields=team in URL
Instructors may be included in partial response by passing ?fields=instructors in URL
GET /rest/events/{event_id}/segments/{segment_id}/assignments
Return a list of assignments for a single segment of an event
GET /rest/events/{event_id}/segments
Return a list of segments with number, class, modifier and group options
GET /rest/members
Return a list of all members
GET /rest/members/{member_id}
Return a single member
Registration history may be included in partial response by passing ?fields=history in URL
Member questions may be included in partial response by passing ?fields=questions in URL
GET /rest/profiles/{profile_id}
Return a single profile and the corresponding member_id
GET /rest/members/{member_id}/vehicles
Return a list of vehicles for a single profile
GET /rest/members/{member_id}/vehicles/{vehicle_id}
Return a single vehicle for a single profile
GET /rest/members/{member_id}/logbook
Return a list of log book entries about a single profile
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:

Successful POST requests (e.g., to create a new resource) 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 resource) will return a status code of 200, and (usually) include the representation in the response.

Successful DELETE requests (e.g., to delete an existing resource) will return a status code of 204 (No Content) and no body.

Data Formats

If no format is specified, XML is the default, although these days we would recommend working with JSON instead. Most resources on api.motorsportreg.com support the following values passed in an Accept header to specify the response format:

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 which is not purist REST but is more pragmatic than an Accept header. 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 https://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-Encodinggzip,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 3000 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 suggest you look at 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 -X GET https://api.motorsportreg.com/rest/calendars.json

Using an existing administrative account, pass in the X-Organization-Id header:

curl -u userid:password -H "X-Organization-Id: {your-id-here}" \
    -X GET https://api.motorsportreg.com/rest/calendars.json

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 -d '<?xml version="1.0" encoding="UTF-8"?>XML Data' -X POST https://api.motorsportreg.com/rest/calendars.json

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 -d '{JSON Data}' -X PUT https://api.motorsportreg.com/rest/calendars/event_id.json

The DELETE method permanently removes a resource. For example:

curl -u userid:password -X DELETE https://api.motorsportreg.com/rest/calendars/event_id.json

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 -d '<?xml version="1.0" encoding="UTF-8"?>XML Data' -X POST https://api.motorsportreg.com/rest/calendars.xml?_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="https://api.motorsportreg.com/rest/calendars.json" method="get">
</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 your personal account, pass in the Organization ID as a header:

<cfhttp username="user" password="password" url="https://api.motorsportreg.com/rest/calendars.json" method="get">
	<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.

Note: we have released free Wordpress and Joomla plugins for displaying an event calendar on your website. Learn more.
<?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);
			curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
			// set content-type and authorization headers
			$headers = array(
				"Accept: application/vnd.pukkasoft+json" // an alternative way of specifying content type
			);
			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><td>' . date("m/d/y", $dte) . '</td><td><a href="' . $event["detailuri"] . '">' . $event["venue"]["name"] . '</a></td><td>' . $event["venue"]["city"] . ', ' . $event["venue"]["region"] . '</td></tr>'; 
		}
	}
	else
	{
		echo '<tr><td colspan="3">No events matched your search!</td></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('https://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="https://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.


https://api.motorsportreg.com/rest/calendars/organization/{your-id-here}.rss  (RSS 2.0)
https://api.motorsportreg.com/rest/calendars/organization/{your-id-here}.atom (Atom 1.0)
https://api.motorsportreg.com/rest/calendars/organization/{your-id-here}.ics  (iCalendar)