REST and GraphQL APIs for Racing, Driving and Social event registration
Support
We offer a mailing list for Developer support and API announcements. Please subscribe to motorsportreg-api-developers at Google Groups.
Wordpress/Joomla Event Calendar Plugin
We have released free Wordpress & Joomla plugins for displaying an event calendar on your website. Learn more.
GraphQL API and Calendar Widget
See our GraphQL API and Calendar Widget announcement. Access the documentation here.
REST API
MotorsportReg.com provides a RESTful API. This is intended for programmers, developers and hackers with at least some technical skills who wish to access our system programmatically for integration with their own systems. This page outlines the resources are available to you, how to access them and some example code.
Authentication
Most requests require valid credentials. There are three ways to authenticate:
- OAuth 1.0 [Preferred]
- We support three-legged OAuth 1.0a
- Register your application by contacting us
- Obtain a Request Token at /rest/tokens/request
- Direct users to our authorization URL: https://www.motorsportreg.com/index.cfm/event/oauth
- Exchange Request Token for Access Token at /rest/tokens/access
- Make requests on behalf of users with their Access Token and an X-Organization-Id (for resources that require one)
- Use an existing administrative username and password
- Good for one-off tasks or in-house scripts, not for sharing with 3rd party apps or developers
- 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]
To request credentials for authentication, tell us what you're building.
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 snippets of code exactly as it appears in the html below. We may provide other sizes upon request.
MotorsportReg.com logos
Powered by MotorsportReg.com logos
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
- 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 "country" using an ISO 3166-1 ALPHA-2 code (e.g. US, CA, AU) to specify the country.
- Optionally pass URL parameter archive=true to include events in the past
- Optionally pass URL parameters "start" and "end" dates to include overlapping events, e.g. ?start=2017-01-01&end=2018-01-01 to get events which begin or end between those dates
- Optionally pass URL parameter exclude_cancelled=true to remove cancelled events from the results
- Optionally pass URL parameter types with one or more comma-delimited type_ids to filter the results, e.g. ?types=x,y,z
- GET /rest/calendars/organization/{organization_id}/type/{type_id}
- Return a calendar for a single organization/club for a single event type
- GET /rest/events/{event_id}/entrylist
- Unauthenticated request returns the same data as the public entry list. The contents of the list are controlled by the organizer and may return a limited or empty result set. For the full entry list, authenticate first and use the assignments resource.
Requires OAuth Authentication
For an example of OAuth integration in Node.js, see this post.
- POST /rest/tokens/request
- Obtain a request token to be used in directing users to our authorization URL at https://www.motorsportreg.com/index.cfm/event/oauth
- Requires signing only, no authentication
- Per RFC 5849, response is returned in body as application/x-www-form-urlencoded
- POST /rest/tokens/access
- Exchange a request token for a permanent access token by passing the token and verifier code
- Requires signing only, no authentication
- Per RFC 5849, response is returned in body as application/x-www-form-urlencoded
- GET /rest/me
- Return the profile and all organization memberships of the user whose OAuth token the request is made of
- Helps identify organizations to which the profile belongs and their IDs for use in X-Organization-Id headers
- GET /rest/me/vehicles
- Return a list of vehicles for the user whose OAuth token the request is made of
- GET /rest/me/vehicles/{vehicle_id}
- Return a single vehicle for the user whose OAuth token the request is made of
- GET /rest/me/events
- Return a list of event registrations for the user whose OAuth token the request is made of
Requires Authentication
- GET /rest/calendars
- All events from all calendars starting today or later (by default).
- 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 "country" using an ISO 3166-1 ALPHA-2 code (e.g. US, CA, AU) to specify the country.
- Optionally pass URL parameter archive=true to include events in the past
- Optionally pass URL parameters "start" and "end" dates to include overlapping events, e.g. ?start=2017-01-01&end=2018-01-01 to get events which begin or end between those dates
- Optionally pass URL parameter exclude_cancelled=true to remove cancelled events from the results
- Optionally pass URL parameter types with one or more comma-delimited type_ids to filter the results, e.g. ?types=x,y,z
- GET /rest/calendars/{event_id}
- Get details about a single event
- 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, ...)
- GET /rest/postalcodes/{postal_code}
- Return postal codes within 300 miles of the passed value. Optionally filter with URL parameter "radius" to another value.
- GET /rest/events/{event_id}/attendees
- Authenticated request returns a complete list of attendees including all statuses, order and payment totals.
- Questions may be included in partial response by passing ?fields=questions in URL
- Limit results with optional UTC-based timestamp ?registered_since=yyyy-mm-dd+10:00:00.000 or ?lastupdate_since=yyyy-mm-dd+00:00:00.000 in URL
- Enable millisecond-level timestamp precision (recommended with since filters for cursor-like behavior) by passing ?precise_timestamps=true in URL
- GET/PUT/DELETE /rest/events/{event_id}/attendees/{attendee_id}
- Read, delete, or update status, notes and metadata for a single attendee
- 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
- GET /rest/events/{event_id}/assignments/{assignment_id}
- GET /rest/events/{event_id}/attendees/{attendee_id}/assignments
- GET /rest/events/{event_id}/segments/{segment_id}/assignments
- Authenticated request returns 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 by passing ?fields=instructors in URL
- Vehicle questions may be included by passing ?fields=vehicle_questions in URL
- Vehicle modifications may be included by passing ?fields=modifications in URL
- Flagtronics ID may be included by passing ?fields=flagtronics in URL
- Contact information may be included in partial response by passing ?fields=profile in URL
- Contact information and profile question answers may be included in partial response by passing ?fields=profile_questions in URL
- GET /rest/events/{event_id}/feeds/timing [JSON only]
- Return an array of changes to timing and scoring data such as names, vehicles, transponders, classes or numbers. Use this to relay changes from Registration to T&S operators for updates.
- Filter data with optional parameters for ?segments={segment_id,segment_id,segment_id} in URL
- Limit results with optional UTC-based timestamp ?since=yyyy-mm-dd+00:00:00.000 in URL
- GET /rest/events/{event_id}/segments/{segment_id}/feeds/timing [JSON only]
- Same as above but pre-filtered to a single segment of your event. Use the since parameter to limit results.
- 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
- Member questions may be included in partial response by passing ?fields=questions in URL
- Default avatar image is 80 pixels square, request different sizes by passing ?imagesize=xx in URL
- Search for a particular profile by email by passing ?email=you@domain.com in URL
- Search for a particular profile by member number by passing ?memberId=12345 in URL
- Search for a particular profile by unique ID by passing ?uniqueId=100000 in URL
- Filter by member type by passing ?types=a,b,c in URL. Get available types via /rest/members/types.
- 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
- Default avatar image is 80 pixels square, request different sizes by passing ?imagesize=xx in URL
- PUT/DELETE /rest/members/{member_id}
- Update or delete a member - allowed fields are memberId, memberEnd and status
- Pass in an array of types to modify the member types
- Pass in an array of questions to update the club/profile question answers (file/image uploads excluded)
- GET /rest/members/types
- Return a list of possible member types (may differ by organization)
- 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
- Questions may be included in partial response by passing ?fields=questions in URL
- GET /rest/members/{member_id}/vehicles/{vehicle_id}
- Return a single vehicle for a single profile
- Questions may be included in partial response by passing ?fields=questions in URL
- GET/POST /rest/members/{member_id}/credits
- Return or create a payment credit for a member
- PUT/DELETE /rest/members/{member_id}/credits/{credit_id}
- Update or delete a payment credit for a member
- 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
- POST /rest/logbooks
- Create a new log book entry
- 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
- GET/PUT/DELETE /rest/discounts
- Return, update or delete discount codes
- Search for a particular discount by passing ?code=YOURCODE in URL
HTTP Response Codes
When making a request, you can expect to receive one of the following HTTP status codes. 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)
- 400: Bad Request (improperly formatted request or invalid values)
- 401: Unauthorized (incorrect or missing username and password)
- 403: Authorized but forbidden request
- 404: Resource Not Found
- 405: Method Not Allowed
- 408: Request Timeout
- 415: Unsupported Media Type
- 500: Application Error
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. The easiest way to specify a format is to include a file "extension" in the URL. This unsettles the REST purists but is more pragmatic:
- /rest/logbooks.json
- /rest/discounts.xml
- /rest/calendars/organization/{organization id}.rss
Most resources on api.motorsportreg.com also 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 |
Authorized Requests
All requests requiring authentication without valid credentials will be denied with a 401 Unauthorized response.
Basic Authentication
You can pass a username and password to most HTTP libraries like in this example with cURL
curl -u username: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 username: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 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.
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
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);
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, rather than .json or .xml in the URL
);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
$data = curl_exec($ch);
if (!curl_errno($ch) && curl_getinfo($ch, CURLINFO_HTTP_CODE) === 200)
{
$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';
}
}
elseif file_exists($dest_file)
{
// something went wrong, so give ourselves 30 minutes to try again and return existing cache
touch($dest_file, strtotime("+30 minutes", filemtime($dest_file)));
$data = file_get_contents($dest_file);
}
else
{
echo "Unable to initialize event feed on first run.";
$mock = array('response' => array('events' => array()));
$data = json_encode($mock);
}
curl_close($ch);
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>';
?>
To provide an Organization ID with authentication in PHP, you can add the following to your array of headers:
$headers = array(
"X-Organization-Id: {your-id-here}",
"Authorization: Basic " . base64_encode('user:pass')
);
Javascript Samples
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.11.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>
ColdFusion Samples
Here's an example using CFML:
<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>
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/{your-id-here}.html" height="300" 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)