API Documentation

API Overview

The Burning Man PlayaEvents API is free for you to use and build with.

The API currently supports two formats, XML and JSON. By default it will return JSON. If you wish to consume XML, pass the API the keypair format=xml. If you want JSONP, provide the keypair callback=myclbk.

Methods

The API supports the following methods to receive and manipulate PlayaEvents data.

Events

Public API Methods using HTTP GET

  • Retrieve All Events in 2009
    playaevents.burningman.com/api/0.2/2009/event/
    jQuery Events example [source]
  • Retrieve Event with ID 1676
    playaevents.burningman.com/api/0.2/2011/event/1676/
  • Events starting after Sept 1st
    playaevents.burningman.com/api/0.2/2011/event/?start_time=2011-09-01%2018:00
  • Events before Sept 1st
    playaevents.burningman.com/api/0.2/2011/event/?end_time=2011-09-01%2018:00
  • Events between Sept 1st and Sept 2nd
    playaevents.burningman.com/api/0.2/2011/event/?end_time=2011-09-02%2018:00&start_time=2011-09-01%2018:00
  • You don't have to specify the time if you don't want to as well
    playaevents.burningman.com/api/0.2/2011/event/?end_time=2011-09-01&start_time=2011-09-02

API methods requiring authentication
These methods must be signed as explained below in the section titled "Authentication"

  • Delete an event with ID 1676
    Send an HTTP DELETE to the url:
    playaevents.burningman.com/api/0.2/2011/event/1676/
  • Create a new event
    Send an HTTP POST to the url:
    playaevents.burningman.com/api/0.2/2011/event/
    The POST should have any or all of the fields:
    • year: a 4 digit string
    • print_description: text
    • url: text
    • contact_email: text
    • other_location: text
    • slug: text (usually autocalculated, not needed)
    • moderation: U, A, or R. U=unreviewed, A=Accepted, R=Rejected
    • hosted_by_camp: the camp id, as retrieved using the camp API method
    • located_at_art: the art id, as retrieved using the art installation API method
    • check_location: boolean “TRUE” or “FALSE”
    • all_day: boolean “TRUE” or “FALSE”
    • list_online: boolean “TRUE” or “FALSE”
    • list_contact_online: boolean “TRUE” or “FALSE”
  • Edit event #1676
    Send an HTTP PUT to the url:
    playaevents.burningman.com/api/0.2/2011/event/1676/
    The PUT should have any or all of the fields listed above for the POST.

Theme Camps

Public API Methods using HTTP GET

API methods requiring authentication
These methods must be signed as explained below in the section titled "Authentication"

  • Delete the camp with ID 1676
    Send an HTTP DELETE to the url:
    playaevents.burningman.com/api/0.2/2011/camp/1676/
  • Create a new camp
    Send an HTTP POST to the url:
    playaevents.burningman.com/api/0.2/2011/camp/
    The POST should have any or all of the fields:
    • year: a 4 digit string
    • name: text
    • print_description: text
    • url: text
    • hometown: text
    • slug: text (usually autocalculated, not needed)
    • list_online: boolean “TRUE” or “FALSE”
    • circular_street: id of the street as retrieved using the Circular street API method
    • time_street: id of the street as retrieved using the Time street API method
  • Edit camp #1676
    Send an HTTP PUT to the url:
    playaevents.burningman.com/api/0.2/2011/event/1676/
    The PUT should have any or all of the fields listed above for the POST.

Art Installations

Public API Methods using HTTP GET

Circular Streets

Public API Methods using HTTP GET

Time Streets

Public API Methods using HTTP GET

Authentication

Some API methods require authentication, because they are either returning sensitive data or they are altering data. Each method that requires authentication is marked "Authentication required" above.

Authentication is done via a simple “signature"”, which is then appended to the querystring of the API url. We'll go into more detail below, but here is the basic scheme:

  1. Find the URL you want to sign. For example, let's say you want to delete event #665. The API url for the DELETE call would be
    playaevents.burningman.com/api/0.2/2011/event/665/
  2. Strip off the domain name and any query arguments, so for this example we'd have
    /api/0.2/2011/event/665/
  3. Get your API key. You must be authorized to use API functions, which you can do by using the contact page on playaevents.burningman.com, once approved, you can get the API key from your profile page at playaevents.burningman.com/accounts/profile/
  4. Make a random "seed" for signing. The easiest "seed" is to simply take the timestamp of today, expressed as seconds. Anything at all will be fine, but there are two caveats. First, the seed can't ever be reused, and second, it needs to be less than 40 characters.
  5. Add your username to the querystring. For example, if my username was "example", the url to be signed would be:
    /api/0.2/2011/event/665/?user=example
  6. Make a signature by taking an MD5 of the url, your seed, and your key, in that order. (code examples below)
  7. Add the seed and your signature to the url. For example, if your seed was "1302229284" and your MD5 signature was "5de4fce4f3135424be0a63db8f3ef20c", your final url would look like this:
    /api/0.2/2011/event/665/&user=example&seed=1302229284&sig=5de4fce4f3135424be0a63db8f3ef20c
  8. That's it. Call the url and if you are authorized, the action will be carried out. In our example, event #665 would be deleted. Note that it will only work once for that seed and signature.

Authentication Code Examples

Python

Python example code:


    import hashlib
    import time
    import types
    import urllib
    import urlparse

    def _add_query_param(query, param, val):
        """Add a querystring parameter to the url"""

        last = '%s=%s' % (param, urllib.quote_plus(val))
        if query:
            return "%s&%s" % (query, last)
        else:
            return last

    def _remove_query_param(query, param):
        """Removes a query param, leaving the querystring in order"""
        parts = query.split('&')
        look = "%s=" % param
        for ix in range(len(parts)-1, -1, -1):
            if parts[ix].startswith(look):
                del parts[ix]

        return '&'.join(parts)

    def _replace_query_param(query, param, val):
        """Replaces a query param, leaving the querystring in order"""
        parts = query.split('&')
        look = "%s=" % param
        for ix in range(0, len(parts)):
            if parts[ix].startswith(look):
                parts[ix] = "%s=%s" % (param, urllib.quote_plus(val))
                break
        return '&'.join(parts)

    def sign_url(url, key, user=None, seed=None):
        """Sign an url.

        Args:
            url: An url to sign.  It can have query parameters which will be preserved.
                 If there is no "seed" provided as a keyword arg, it will look in the
                 query params for it before finally simply giving up and using the
                 current timestamp as the seed.

            key: a key to sign with

        Kwargs:
            user: a user to sign with
            seed: An explicit seed string to use for signing.

        Returns:
            The same url, with its signature added to the querystring.
        """
        origurl = url
        parsed = urlparse.urlsplit(url)
        query = parsed.query
        qs = parse_qs(query)


        if not seed:
            # first look at query
            if 'seed' in qs:
                seed = qs['seed']
                query = _remove_query_param(query,'seed')
            else:
                timestamp = datetime.datetime.now()
                timestamp = time.mktime(timestamp.timetuple())
                seed = str(int(timestamp))
                log.debug('sign_url: no seed, using timestamp %s', seed)

        if user is not None:
            if 'user' in qs:
                username = qs['user']
                if type(username) is types.ListType:
                    username = username[0]
                if username != user.username:
                    query = _replace_query_param(query, 'user', self.user.username)
        else:
            if 'user' in qs:
                query = _remove_query_param(query, 'user')

        url = urlparse.urlunsplit((parsed.scheme, parsed.netloc, parsed.path, query, parsed.fragment))

        processor = hashlib.md5(work)
        processor.update(seed)
        processor.update(key)
        sig = processor.hexdigest()
        query = _add_query_param(query, 'seed', seed)
        query = _add_query_param(query, 'sig', sig)

        url = urlparse.urlunsplit((parsed.scheme, parsed.netloc, parsed.path, query, parsed.fragment))
        return url

PHP

PHP Example code:


    /**
     * Sign an url for use by the Events API
     *
     * @param string $apiurl the url fragment to sign, it should not contain the scheme or server
     * @param string $key the user key
     * @param string $user the user name for the key
     * @param array $apiatts array of options with key=value
     * @param array $urlinfo the url of the originial gallery link as parsed by parse_url
     * @return string url
     */
    function gallery_sign_url($apiurl, $key, $user, &$apiatts, $urlinfo) {

      $apiurl = str_replace('//', '/', $apiurl);
      if (!empty($key) && !empty($user)) {
        $apiatts[] = 'user=' . $user;
        $apiurl .= '?' . implode('&',$apiatts);
        $seed = time();
        $n = rand(10e16, 10e20);
        $seed .= base_convert($n, 10, 36);
        $sig = md5($apiurl . $seed . $key);
        $apiurl .= "&seed=$seed&sig=$sig";
      }
      elseif (count($apiatts) > 0) {
        $apiurl .= '?' . implode('&',$apiatts);
      }
      $signed = $urlinfo['scheme'] . '://' . $urlinfo['host'];
      if (!empty($urlinfo['port']) && $urlinfo['port'] <> 80) {
        $signed .= ':' . $urlinfo['port'];
      }
      $signed .= $apiurl;
      return $signed;
    }

Legal

© 2009-2011 Black Rock City LLC, all rights reserved. Use of all event information and data restricted to free use. These materials are not to be used or distributed in any form which may be sold for profit.
 
`