Restaurant Reservations.Learn More
Developers
Introduction
The Sexbyfood API exposes Sexbyfood restaurant content through an easy-to-use web service interface that, when combined with the Sexbyfood Associates Program, is a simple way for website developers to make money.
You may use the Sexbyfood API as long as it is used primarily to drive more honored Internet reservations to restaurants listed on Sexbyfood. Access to the Sexbyfood API is free.
Highlights
Easily incorporate rich Sexbyfood restaurant content into your own site including:
- Real-time table availability searching
- Restaurant profiles, information, images, menu's and special offers
- Customer reviews and more
Receive 12.5% in referral fees on honored Internet reservations placed on your website through the Sexbyfood API.
Get Started
Get Started
- API Protocol
- Authentication
- Reading Resources
- Creating Resources
- Updating Resources
- Deleting Resources
- Content Negotiation
- Content Encoding
- Error Handling
- AJAX And Cross-Domain Requests
- Earning Referral Fees
- API Terms
API Protocol
The Sexbyfood API at http://www.sexbyfood.com/api/ enables access to specific Sexbyfood resources, each of which can be referred to by a uniform resource identifier or URI. Sexbyfood resources can be manipulated over HTTP using the verbs GET, POST, PUT and DELETE. Resources can be exchanged as either JSON or XML representations. In other words, the Sexbyfood API is based on REST.
Authentication
When you use the Sexbyfood API you have access to everything that your Sexbyfood account has access to. Please sign in to view your Sexbyfood API authentication credentials.
The Sexbyfood API authenticates using HTTP Basic Authentication. You must include an Authorization header in every request to the Sexbyfood API. This consists of your API ID, a UTC timestamp and a hex MD5 hash of the UTC timestamp and your Authentication Token:
$utc_timestamp = gmmktime(); //generated within an hour of each request
$credentials = $api_id . ':' . $utc_timestamp . md5($utc_timestamp . $authentication_token);
$authorization_header = 'Authorization: Basic ' . base64_encode($credentials);
Anyone who has your Sexbyfood API ID and Authentication Token can see and change everything you have access to. If your Authentication Token may have been compromised, please change your Sexbyfood password to regenerate your Authentication Token.
Reading Resources
To read a resource, perform a GET on the resource URI.
The response to a successful resource read is the requested resource represented in your requested format and an HTTP status code header of '200 OK'.
Creating Resources
To create a resource, perform a POST on the URI of the resource to be created and include the new resource in the body of your request.
The response to a successful resource creation is the created resource represented in your requested format and an HTTP status code header of '201 CREATED'.
Updating Resources
To update a resource, perform a PUT on the URI of the resource you want to update and include the updated resource in the body of your request. To perform a PUT on a resource URI, perform a POST on the resource URI and set the method override header as 'X-HTTP-Method-Override: PUT'.
The response to a successful resource update is the updated resource represented in your requested format and an HTTP status code header of '200 OK'.
Deleting Resources
To delete a resource, perform a DELETE on the URI of the resource you want to delete. To perform a DELETE on a resource URI, perform a POST on the resource URI and set the method override header as 'X-HTTP-Method-Override: DELETE'.
The response to a successful resource delete is an HTTP status code header of '200 OK'.
Content Negotiation
The Sexbyfood API uses content negotation to exchange resources as either JSON or XML representations. To indicate which representation you wish to exchange, specify an 'Accept' HTTP header for GET requests and a 'Content-Type' HTTP header for POST and PUT requests. The relevant MIME media-type to include in your header is 'application/json' for JSON or 'application/xml' for XML.
Content Encoding
The Sexbyfood API expects data to be UTF-8 encoded. Checks are made for valid UTF-8 sequences. If an invalid sequence is found, the data is presumed to be ISO-8859-1 and is converted accordingly to UTF-8.
Error Handling
The response to a failed resource request is an HTTP status code header of either: 400 Bad Request, 401 Unauthorized, 404 Not Found, 405 Method Not Allowed, 415 Unsupported Media Type or 500 Internal Server Error.
A '400 Bad Request' response is accompanied with a custom 'X-Error-Message' header to indicate errors in the request. The 'X-Error-Message' header is designed to be end-user friendly. A '500 Internal Server Error' response indicates an error internal to Sexbyfood. Please contact us at info@sexbyfood.com should such an error persist or should you wish to receive error messages in Cantonese.
AJAX And Cross-Domain Requests
The Sexbyfood API is designed to be AJAX friendly. We recommend that you use the excellent cross-browser Prototype Javascript library when making AJAX calls to the Sexbyfood API. Prototype provides helpers for AJAX requests, JSON and custom headers.
We further recommend that you use our Javascript serialize method when serializing your HTML forms to JSON as it has support for nested HTML form elements.
For security reasons, AJAX requests can only be made to URLs of the same protocol, host and port as the page containing the AJAX request. To access the Sexbyfood API through AJAX you need to install a proxy on your web server.
A proxy can be a single line in your Apache .htaccess file or a server-side script. Instead of making your AJAX request to the Sexbyfood API, make your AJAX request to your proxy. Your proxy passes the request onto the Sexbyfood API and then returns the response to your client application. Because the connection is made to your server, and the data comes back from your server, the browser has nothing to complain about.
Earning Referral Fees
To earn referral fees for referring honored Internet reservations, find out more about the Sexbyfood Associates Program. You will receive a Sexbyfood Associate ID to identify you. Include your Sexbyfood Associate ID in each Sexbyfood API request where applicable to receive referral fees for honored Internet reservations referred by you.
API Terms
Use of the Sexbyfood API is governed by the Sexbyfood API Terms. Before starting, make sure you have read and agree to the Sexbyfood API Terms.
API Resources
GET listings
Returns a collection of restaurant listings.
Response:
<listings>
<listing>
...
</listing>
</listings>
GET listings/{id}
Returns a restaurant listing.
Response:
<listing>
<id>62</id>
<restaurant>
<name>The Showroom</name>
<clean>the-showroom</clean>
<metaphone>0ZZZ XRMZ</metaphone>
</restaurant>
<street>10 Hospital Street</street>
<suburb>
<id>2</id>
<name>Green Point</name>
<clean>green-point</clean>
</suburb>
<area>
<id>1</id>
<name>Atlantic Seaboard</name>
<clean>atlantic-seaboard</clean>
</area>
<city>
<id>2</id>
<name>Cape Town</name>
<clean>cape-town</clean>
</city>
<state>
<id>9</id>
<name>Western Cape</name>
<clean>western-cape</clean>
</state>
<country>
<id>1</id>
<name>South Africa</name>
<clean>south-africa</clean>
</country>
<zip>8051</zip>
<geocode>
<lattitude>-33.9148</lattitude>
<longitude>18.4207</longitude>
</geocode>
<time>
<local>1201440976</local>
<utc-offset>2</utc-offset>
</time>
<tel>27 21 421 4682</tel>
<fax>27 21 421 3858</fax>
<email>info@theshowroomrestaurant.co.za</email>
<website>http://www.theshowroomrestaurant.co.za</website>
<since>2007-07-04</since>
<status>public</status>
<about>A great restaurant is not only about the food...</about>
<directions></directions>
<price>190</price>
<currency>
<id>1</id>
<name>ZAR</name>
<symbol>R</symbol>
<exchange>1</exchange>
<status>local</status>
</currency>
<cuisines>
<cuisine>
<id>29</id>
<name>Fine Dining</name>
<clean>fine-dining</clean>
<metaphone>FNZZ TNNK</metaphone>
</cuisine>
<cuisine>
<id>31</id>
<name>Fusion</name>
<clean>fusion</clean>
<metaphone>FXNZ</metaphone>
</cuisine>
</cuisines>
<occasions>
<occasion>
<id>2</id>
<name>Al Fresco</name>
<clean>al-fresco</clean>
<metaphone>ALZZ FRSK</metaphone>
</occasion>
<occasion>
<id>22</id>
<name>Fashionable</name>
<clean>fashionable</clean>
<metaphone>FXNBL</metaphone>
</occasion>
<occasion>
<id>46</id>
<name>Sophisticated</name>
<clean>sophisticated</clean>
<metaphone>SFSTKTT</metaphone>
</occasion>
</occasions>
<payment-methods>
<payment-method>
<id>1</id>
<name>American Express</name>
</payment-method>
<payment-method>
<id>2</id>
<name>Diners Club</name>
</payment-method>
<payment-method>
<id>3</id>
<name>Mastercard</name>
</payment-method>
<payment-method>
<id>4</id>
<name>Visa</name>
</payment-method>
</payment-methods>
<rating>
<food>4.75000</food>
<service>4.25000</service>
<vibe>4.50000</vibe>
<value>4.25000</value>
<average>4.45000</average>
</rating>
</listing>
POST listings
Creates a new restaurant listing accessible by an existing user-id.
Request:
<listing>
<restaurant>
<name>The Showroom</name>
</restaurant>
<user-id>1</user-id>
</listing>
Response:
<listing>
<id>62</id>
<restaurant>
<name>The Showroom</name>
<clean>the-showroom</clean>
<metaphone>0ZZZ XRMZ</metaphone>
</restaurant>
...
</listing>
GET listings/images
Returns a collection of restaurant images.
Response:
<images>
<image>
...
</image>
</images>
GET listings/{listing-id}/images
Returns a collection of images for a specific restaurant.
Response:
<images>
<image>
...
</image>
</images>
GET listings/{listing-id}/images/{id}
Returns a restaurant image.
Response:
<image>
<id>3</id>
<listing-id>73</listing-id>
<type>photo</type>
<uri>http://static0.sexbyfood.com/listings/73/images/3/</uri>
</image>
GET listings/reviews
Returns a collection of restaurant customer reviews.
Response:
<reviews>
<review>
...
</review>
</reviews>
GET listings/{listing-id}/reviews
Returns a collection of customer reviews for a specific restaurant.
Response:
<reviews>
<review>
...
</review>
</reviews>
GET listings/{listing-id}/reviews/{id}
Returns a restaurant customer review.
Response:
<review>
<id>7</id>
<listing-id>62</listing-id>
<user-id>10</user-id>
<name>Robby Zimmerman</name>
<website>http://www.highway61revisited.com</website>
<date>2008-03-11</date>
<title>Imagine</title>
<body>Bruce Robertson displays imagination...</body>
<rating>
<food>4.5</food>
<service>4.0</service>
<vibe>5.0</vibe>
<value>4.5</value>
<average>4.5</average>
</rating>
<votes>
<positive>11</positive>
<negative>2</negative>
<inappropriate>0</inappropriate>
</votes>
<status>public</status>
</review>
POST listings/{listing-id}/reviews
Creates a new customer review for a restaurant listing.
Request:
<review>
<name>Paul Hewson</name>
<website>http://www.hewson.com</website>
<title>The Fast Car</title>
<body>The Showroom is the fast car...</body>
<rating>
<food>5.0</food>
<service>5.0</service>
<vibe>5.0</vibe>
<value>5.0</value>
</rating>
</review>
Response:
<review>
<id>6</id>
<listing-id>62</listing-id>
<user-id>1</user-id>
<name>Paul Hewson</name>
<website>http://www.hewson.com</website>
<date>2007-09-02</date>
<title>The Fast Car</title>
<body>The Showroom is the fast car...</body>
<rating>
<food>5.0</food>
<service>5.0</service>
<vibe>5.0</vibe>
<value>5.0</value>
<average>5.0</average>
</rating>
<votes>
<positive>0</positive>
<negative>0</negative>
<inappropriate>0</inappropriate>
</votes>
<status>private</status>
</review>
POST users
Creates a new user account.
Request:
<user>
<name>Lucien Ginzburg</name>
<email>serge@melodynelson.com</email>
<password>bonnieandclyde</password>
</user>
Response:
<user>
<id>11</id>
<name>Lucien Ginzburg</name>
<email>serge@melodynelson.com</email>
<password>bb491b0128aa723e7321e15ce40b417065754fa5f32f7706d</password>
<since>2007-07-07</since>
</user>
GET world
Returns a collection of countries, states, cities, areas and suburbs.
Response:
<world>
<countries>
<country>
...
</country>
</countries>
<states>
<state>
...
</state>
</states>
<cities>
<city>
...
</city>
</cities>
<areas>
<area>
...
</area>
</areas>
<suburbs>
<suburb>
...
</suburb>
</suburbs>
</world>
GET world/countries
Returns a collection of countries.
Response:
<countries>
<country>
...
</country>
</countries>
GET world/countries/{id}
Returns a country.
Response:
<country>
<id>12</id>
<parent-id>2</parent-id>
<name>United States</name>
<clean>united-states</clean>
<approved>yes</approved>
</country>
POST world/countries
Creates a new country.
Request:
<country>
<parent-id>2</parent-id>
<name>United States</name>
</country>
Response:
<country>
<id>12</id>
<parent-id>2</parent-id>
<name>United States</name>
<clean>united-states</clean>
<approved>no</approved>
</country>
GET world/states
Returns a collection of states.
Response:
<states>
<state>
...
</state>
</states>
GET world/states/{id}
Returns a state.
Response:
<state>
<id>37</id>
<parent-id>12</parent-id>
<name>California</name>
<clean>california</clean>
<approved>yes</approved>
</state>
POST world/states
Creates a new state.
Request:
<state>
<parent-id>12</parent-id>
<name>California</name>
</state>
Response:
<state>
<id>37</id>
<parent-id>12</parent-id>
<name>California</name>
<clean>california</clean>
<approved>no</approved>
</state>
GET world/cities
Returns a collection of cities.
Response:
<cities>
<city>
...
</city>
</cities>
GET world/cities/{id}
Returns a city.
Response:
<city>
<id>31</id>
<parent-id>37</parent-id>
<name>Los Angeles</name>
<clean>los-angeles</clean>
<approved>yes</approved>
</city>
POST world/cities
Creates a new city.
Request:
<city>
<parent-id>37</parent-id>
<name>Los Angeles</name>
</city>
Response:
<city>
<id>31</id>
<parent-id>37</parent-id>
<name>Los Angeles</name>
<clean>los-angeles</clean>
<approved>no</approved>
</city>
GET world/areas
Returns a collection of areas.
Response:
<areas>
<area>
...
</area>
</areas>
GET world/areas/{id}
Returns an area.
Response:
<area>
<id>17</id>
<parent-id>31</parent-id>
<name>Hollywood</name>
<clean>hollywood</clean>
<approved>yes</approved>
</area>
POST world/areas
Creates a new area.
Request:
<area>
<parent-id>31</parent-id>
<name>Hollywood</name>
</area>
Response:
<area>
<id>17</id>
<parent-id>31</parent-id>
<name>Hollywood</name>
<clean>hollywood</clean>
<approved>no</approved>
</area>
GET world/suburbs
Returns a collection of suburbs.
Response:
<suburbs>
<suburb>
...
</suburb>
</suburbs>
GET world/suburbs/{id}
Returns a suburb.
Response:
<suburb>
<id>12</id>
<parent-id>17</parent-id>
<name>Laurel Canyon</name>
<clean>laurel-canyon</clean>
<approved>yes</approved>
</suburb>
POST world/suburbs
Creates a new suburb.
Request:
<suburb>
<parent-id>17</parent-id>
<name>Laurel Canyon</name>
</suburb>
Response:
<suburb>
<id>12</id>
<parent-id>17</parent-id>
<name>Laurel Canyon</name>
<clean>laurel-canyon</clean>
<approved>no</approved>
</suburb>
GET categories/cuisines
Returns a collection of cuisines.
Response:
<cuisines>
<cuisine>
...
</cuisine>
</cuisine>
GET categories/cuisines/{id}
Returns a cuisine.
Response:
<cuisine>
<id>31</id>
<name>Fusion</name>
<clean>fusion</clean>
<metaphone>FXNZ</metaphone>
</cuisine>
GET categories/occasions
Returns a collection of occasions.
Response:
<occasions>
<occasion>
...
</occasion>
</occasion>
GET categories/occasions/{id}
Returns an occasion.
Response:
<occasion>
<id>5</id>
<name>Birthday Drinks</name>
<clean>birthday-drinks</clean>
<metaphone>BR0T TRNKS</metaphone>
</occasion>
GET currencies
Returns a collection of currencies.
Response:
<currencies>
<currency>
...
</currency>
</currencies>
GET currencies/{id}
Returns a currency.
Response:
<currency>
<id>2</id>
<name>USD</name>
<symbol>$</symbol>
<exchange>7.30429</exchange>
<status>default</status>
</currency>
GET greetings
Returns a collection of foreign language greetings ordered at random.
Response:
<greetings>
<greeting>Mhoroi</greeting>
<greeting>Ni hao</greeting>
<greeting>G'day</greeting>
<greeting>Guten Tag</greeting>
<greeting>Sawubona</greeting>
<greeting>Shalom</greeting>
<greeting>Giorno</greeting>
<greeting>Halla</greeting>
<greeting>Salut</greeting>
<greeting>Mambo</greeting>
<greeting>Bonjour</greeting>
<greeting>Dzien dobry</greeting>
...
</greetings>
API Sandbox
HTTP Request

HTTP Response
API Code
- Javascript: Apache .Htaccess Proxy
- Javascript: Authorization Header
- Javascript: Request Wrapper
- Javascript: Serialize Method
- PHP: Request Wrapper
Javascript: Apache .Htaccess Proxy
To access the Sexbyfood API using Javascript, you need to install a proxy to enable cross-domain AJAX requests. This is clean and simple if your website runs on Apache. Just include the following lines in your Apache .htaccess file:
RewriteEngine on
RewriteRule ^/sexbyfood/api/(.*)$ http://www.sexbyfood.com/api/$1 [P]
Javascript: Authorization Header
Your authorization header expires an hour after it is generated. Include the following script tag at the top of each HTML page that initiates a request. This enables you to generate the authorization header dynamically and make it available as a global Javascript variable to your external Javascript files:
<script type="text/javascript">
var AUTHORIZATION = 'Basic: <?php $gmt_timestamp = gmmktime(); echo base64_encode($api_id . ':' . $gmt_timestamp . md5($gmt_timestamp . $authentication_token)); ?>';
</script>
Javascript: Request Wrapper
We recommend that you use the following request wrapper (requires Prototype Version 6) to make your AJAX requests. Simply paste the wrapper wherever you need to make a request, modify as required by the request method, and use the onSuccess and onFailure functions to act on the response accordingly:
new Ajax.Request(
'http://www.your-domain-name.com/sexbyfood/api/listings', {
method : 'GET', //'GET', 'POST', 'PUT' or 'DELETE'
requestHeaders : {
'Authorization' : AUTHORIZATION, //Note comma between key : value pairs
'Accept' : 'application/json' //Use only for GET requests
//'X-HTTP-Method-Override' : 'PUT' //Use only for PUT requests
//'X-HTTP-Method-Override' : 'DELETE' //Use only for DELETE requests
},
//contentType : 'application/json' //Use only for POST and PUT requests
//postBody : Object.toJSON($('id-of-form-to-serialize').serialize(true)),
//Use only for POST and PUT requests, insert 'id-of-form-to-serialize'
onSuccess : function(ajax) {
var listings = ajax.responseJSON.listings;
alert('The first listing has id: ' + listings[0].listing.id);
},
onFailure : function(ajax) {
alert(ajax.getHeader('X-Error-Message'));
}
}
);
Javascript: Serialize Method
We recommend that you use the following Javascript serialize method when serializing your HTML forms to JSON as it has support for nested HTML form elements. Nested form elements are necessary to produce resource representations that adhere to the relevant schema. This method is designed to replace Prototype's native serialize method (line 3374 in Prototype Version 6) which does not support nested form elements.
The method serializes form data to an object hash where keys are form element names and values are data. If a form name is provided, this is used as the object hash root. Only elements with a name attribute are serialized. Disabled form elements and submit inputs are not serialized (as per the W3C HTML recommendation). File inputs are skipped as they cannot be serialized by Javascript. See the Javascript request wrapper above for usage.
serialize: function(form, options) {
var serialization = {}, root = ($(form).attributes['name'] ? $(form).attributes['name'].value : '');
if (root) eval('serialization["' + root + '"] = {};');
$(form).getElements().each(function(element) {
if (!element.disabled && element.name) {
if ($F(element) != null && element.type != 'submit') {
var keys = $w(element.name.gsub(/\[\]/, '[-]').gsub(/\[/, ' ').gsub(/\]/, ''));
var variable = 'serialization';
if (root) variable = 'serialization["' + root + '"]';
keys.each(function(key, index) {
if (key == '-') key = eval(variable + '.length;');
variable += '["' + key + '"]';
if (index < keys.length - 1) {
if (!eval(variable)) {
if (keys[index + 1] * 1 >= 0 || keys[index + 1] == '-') {
eval(variable + '= [];');
} else {
eval(variable + '= {};');
}
}
} else {
if (eval(variable)) {
eval(variable + ' = $A(' + variable + ');');
eval(variable + '.push($F(element));');
} else {
eval(variable + ' = $F(element)');
}
}
});
}
}
});
return serialization;
}
PHP: Request Wrapper
If you use PHP, the following PHP wrapper simplifies access to the Sexbyfood API. Pass in your method, resource and representation (as a PHP array). The wrapper returns the response HTTP status code. Where applicable the wrapper also returns an error message, and a representation (as a PHP array).
function sexbyfood($method, $resource, $representation = '') {
//authorization credentials
$api_id = '';
$authentication_token = '';
require_once('xml.php');
$xml = new xml();
if ($representation) $representation = $xml->encode($representation);
$gmt_timestamp = gmmktime();
$credentials = $api_id;
$credentials .= ':' . $gmt_timestamp;
$credentials .= md5($gmt_timestamp . $authentication_token);
$headers[] = 'Authorization: Basic: ' . base64_encode($credentials);
switch(strtoupper($method)) {
case 'GET':
$method = 'GET';
$headers[] = 'Accept: application/xml';
break;
case 'POST':
$method = 'POST';
$headers[] = 'Content-Type: application/xml';
break;
case 'PUT':
$method = 'POST';
$headers[] = 'Content-Type: application/xml';
$headers[] = 'X-HTTP-Method-Override: PUT';
break;
case 'DELETE':
$method = 'POST';
$headers[] = 'X-HTTP-Method-Override: DELETE';
break;
}
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, 'http://www.sexbyfood.com/api/' . $resource);
if ($method == 'POST') {
curl_setopt($curl, CURLOPT_POST, TRUE);
if ($representation) curl_setopt($curl, CURLOPT_POSTFIELDS, $representation);
}
curl_setopt($curl, CURLOPT_HEADER, TRUE);
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
$response = explode("\n\r\n", curl_exec($curl), 2);
$status = curl_getinfo($curl, CURLINFO_HTTP_CODE);
$error = NULL;
preg_match("/X-Error-Message:\s([^\n]*)/s", $response[0], $matches);
if (isset($matches[1])) $error = $matches[1];
$representation = NULL;
if (isset($response[1])) $representation = $xml->decode($response[1]);
curl_close($curl);
return array(
'status' => $status,
'error' => $error,
'representation' => $representation
);
}
$result = sexbyfood('GET', 'listings/62');
print_r($result);
API Terms
Associates, developers, restaurants and users may access Sexbyfood data via the Sexbyfood API (Application Program Interface). Any use of the API, including use of the API through a third-party product that accesses Sexbyfood, is bound by the Sexbyfood terms of service plus the following specific terms:
- You expressly understand and agree that Sexbyfood shall not be liable for any direct, indirect, incidental, special, consequential or exemplary damages, including but not limited to, damages for loss of profits, goodwill, use, data or other intangible losses (even if Sexbyfood has been advised of the possibility of such damages), resulting from your use of the API or third-party products that access data via the API.
- Abuse or excessively frequent requests to Sexbyfood via the API may result in the temporary or permanent suspension of your account's access to the API. Sexbyfood, in its sole discretion, will determine abuse or excessive usage of the API. Sexbyfood will make a reasonable attempt via email to warn the account owner prior to suspension.
- Sexbyfood reserves the right at any time to modify or discontinue, temporarily or permanently, your access to the API (or any part thereof) with or without notice.