LCBO API

LCBO API Version 1

Welcome to LCBO API V1

This is the documentation for Version 1 (V1) of LCBO API. It was originally released April 2009.

Responses & Formats

The default response format for the API V1 is JSON application/json. This means that you don’t need to specify JSON in an Accept header or as an extension (.json) if that is the format you intend to request.

JSON

All responses are wrapped in a container object, in its most basic form it looks like this:

{
  "status": 200,
  "message": null,
  "result": ...
}

This allows the API to return meta information along with the data you are requesting. For example, in the case of the Stores with Product endpoint, the product object is returned with the list of stores so that your application does not have to perform an additional request to obtain the store information.

CSV

Many resources can be returned as CSV (comma separated values) or TSV (tab separated values). These results can then be easily imported into spreadsheet software such as Apple Numbers or Microsoft Excel. To return a resource in CSV or TSV format simply append the .csv or .tsv extension to the resource URI:

/products.csv?order=price_in_cents.desc

Pagination

When the API returns collections of items (stores, products, or inventories) it will paginate the results instead of returning all of them at once. You can control the number of items per page through the per_page parameter.

A typical pager object looks like this:

{
  "records_per_page": 20,
  "total_record_count": 608,
  "current_page_record_count": 20,
  "is_first_page": false,
  "is_final_page": false,
  "current_page": 5,
  "current_page_path": "/stores?page=5",
  "next_page": 6,
  "next_page_path": "/stores?page=6",
  "previous_page": 4,
  "previous_page_path": "/stores?page=4",
  "final_page": 31,
  "final_page_path": "/stores?page=31"
}

It contains all of the information you need (and more) to navigate through the pages in the result set.

Authentication

LCBO API V1 does not require authentication for access. Starting on March 8th, 2015, LCBO API V1 will require Access Keys for unlimited use. New features in LCBO API V1 such as HTTPS and CORS require authentication with an Access Key.

You can provision an unlimited number of Access Keys for free by creating an LCBO API account.

There are three different types of access keys, they have specific use-cases in mind:

Key Type Description
Web Browser Use when LCBO API is accessed from a web browser through XMLHttpRequest (Ajax/XHR) using CORS or through dynamically inserted <script> tags (JSONP). These keys are rate-limited per client IP address and are paired to a domain. For example, a Web Browser Access Key associated with the domain momsandhops.ca would fail to work if used on a page served from thebeerstore.ca.
Native Client In native mobile and desktop applications, these keys are rate-limited per client but do not support CORS or JSONP.
Private When LCBO API is accessed from a web server or private script, these keys are not rate-limited, and they do not support CORS or JSONP.

Using Access Keys

Detailed usage information is provided in the LCBO API Manager when you create access keys.

Your access key will need to be sent with every request you make to LCBO API, you can do this the following ways:

HTTP Header

This is the recommended way of adding your Access Key to requests:

Authorization: Token token="myLCBOAPIaccessKey"

Query Parameter

Aside from JSONP, you should always try to use the HTTP Header method outlined above. Add your access key to the URL like this:

http://lcboapi.com/products?access_key=myLCBOAPIaccessKey

Basic Auth

If the tool you’re using will only support setting the Authorization header by username/password, you can provide the following values to pass along your Access Key to LCBO API.

Username: x-access-key
Password: myLCBOAPIaccessKey

Errors

When an error occurs the response will look something like this:

{
  "error": "bad_query_error",
  "message": "A value supplied for the order parameter (id.desk) is not valid. It contains an invalid sort order (desk) for (id) try using: id.desc or id.asc instead.",
  "result": null,
  "status": 400
}

Error messages are always as descriptive as possible and they fall into one of the below categories:

Code Description
no_results_error The geocoder returned no geometry for the geo query.
over_limit_error The geocoder has reached its daily limit of requests.
geocoder_error The geocoder can’t geocode the query it was provided.
not_found_error A resource was not found (404)
bad_query_error One (or more) of the supplied query parameters is wrong.
jsonp_error Supplied callback is not a valid format, or JSONP is not being used correctly.
unauthorized The feature you’re trying to use requires an Access Key

Cross Origin Access

LCBO API provides support for cross-origin requests so that it can be used from a web page. In the past, due to the Single Origin Policy implemented in all web browsers, there were only two ways to do this. Either by proxying all requests through the origin server, or by using a technique called JSONP. Today, all modern browsers implement Cross Origin Resource Sharing (CORS). LCBO API supports all of these techniques.

HTTP Proxy

In a proxy setup, the API consumer implements an endpoint on their web server that proxies all requests to and responses from LCBO API. For example, the following endpoint on your web server:

mysite.com/lcboapi/*

Would then proxy anything after lcboapi/ to lcboapi.com, as if it were a part of your site, even though those requests are actually being delegated to lcboapi.com. So a request to your server like this:

mysite.com/lcboapi/products

Would actually request this page on LCBO API:

lcboapi.com/products

And your site would then return the result of that LCBO API response.

This approach is not bad, the browser doesn’t care because all of the requests are to the same domain, and given the performance of modern web servers like Nginx and Apache the overhead is quite low. The downside is that it requires infrastructure and configuration to work properly and ultimately becomes another thing to maintain. This leads us to the first way to truly request 3rd party data from a web page: JSONP.

JSONP

JSONP stands for JSON with Padding and works by dynamically attaching <script> elements to a web page, that call a previously defined function in order to load data.

To use JSONP with LCBO API, simply add a callback parameter to LCBO API URLs. When using JSONP LCBO API also sets the response Content-Type to application/javascript since the response is now executable JavaScript, and not just data (JSON) anymore.

Here’s how the whole process works, say you have a globally defined function named loadStore on your page, like this:

<!DOCTYPE html>
<html>
  <head>
    <title>LCBO Learnin'</title>
    <script>
      function loadStore(response) {
        var el = document.getElementById('store_name');
        el.innerHTML = response.result.name;
      }
    </script>
  </head>
  <body>
    <h1 id="store_name"></h1>
  </body>
</html>

And you dynamically insert a <script> tag on the page using a function like this:

function loadStore(id) {
  var script = document.createElement('script');

  script.src = 'http://lcboapi.com/stores/'+id+'?callback=loadStore';
  script.async = true;

  document.head.appendChild(script);
}

loadStore(511);

LCBO API retuns a JavaScript file that looks like this:

loadStore({
  status: 200,
  message: null,
  result: {
    "id": 511,
    "name": "King & Spadina",
    ...
  }
});

Which effectively calls our prevously defined loadStore function with the response data as its sole argument, so our <h1> tag is filled with the name of the store.

It’s important to note that most popular JavaScript libraries have built-in support for JSONP. For example, the following jQuery can be used to perform a JSONP request against LCBO API:

$.ajax({
  url: 'http://lcboapi.com/products/371906',
  dataType: 'jsonp'
}).then(function(data) {
  console.log(data);
});

I highly recommend using a library like jQuery to manage JSONP orchistration.

CORS

Cross Origin Resource Sharing (CORS) is a robust W3C specification for allowing browsers to access resources from different domains. LCBO API uses it to give access to web browser JavaScript applications.

If you need to support outdated bowsers, specifically IE 6 and 7, you’ll either have to use a proxy or JSONP. Hilariously, with the advent of async script tags <script async> JSONP can be about as effective in modern browsers as using XMLHttpRequest with CORS. If you have to support older browsers that don’t understand CORS, there is no shame in using JSONP.

If you don’t have to support IE 6 and 7, welcome to the future! To use CORS with LCBO API you need to provide a Web Browser Access Key with your requests. You’ll need an LCBO API account to create Access Keys, sign up for one and get started. You can also read more about LCBO API authentication.

Once you have a Web Browser Access Key, using LCBO API with CORS from jQuery is as simple as:

$.ajax({
  url: 'http://lcboapi.com/products/346197',
  headers: {
    Authorization: 'Token YOUR_ACCESS_KEY'
  }
}).then(function(data) {
  console.log(data);
});

HTTPS

LCBO API now supports secured connections over HTTPS, this is particularly useful when you want to request data over JSONP or CORS on a webpage that was served over HTTPS.

To use HTTPS you must provide an Access Key. Sign Up for an LCBO API account to create one.