Skip to content


Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?

Latest commit


Git stats


Failed to load latest commit information.
Latest commit message
Commit time

This is a simple Python Bottle web app demonstrating basic usage of the Sonlet API. A live instance of this app is available here.

Running locally

To run this app locally, grab the code and set up a python environment:

$ git clone
$ cd str-api-demo-web
$ virtualenv env
$ env/bin/pip install -r requirements.txt
$ REDIRECT_URI=http://localhost.localdomain:8888/cb \
    STR_URL= \

If you don't have a client ID and secret, you'll need to send an email to to get an app set up for yourself on the beta site.

You should now be able to browse to http://localhost:8888 to view the app.

Important stuff

The code here is quite small, but it's still useful to call out some of the more salient bits. In all of the examples below I'll be using the URLs from the beta site, even though those can be overridden to point at your local setup.

Also remember that this is proof of concept code. You should not carry over any of the following patterns to your app:

  • Putting the access token in the URL. That's just plain lazy and not secure at all. It's like embedding the user's password in the URL. Instead, the user's access token (and refresh token) should be persisted somewhere secure (i.e. not on the client's device) and associated with the user's account in your app.

Getting the token

To get the token, we send the user to the following web page:<client_id>&state=random_state_string&redirect_uri=

If the user clicks "authorize" on that page, they will be redirected to the redirect_uri with a code in the query string, which we can extract in bottle like so:


Note that for a mobile app this redirect URI would be using a custom schema handled by your app, as described here.

Once we have the code, we can get an access token by doing a POST to with the following arguments:

  "grant_type": "authorization_code",
  "code": <code>,
  "redirect_uri": "",
  "client_id": <client_id>,
  "client_secret": <client_secret>,

Note that the reason we can use client_secret here is because this is a server-side application where the code is presumably secret. In a mobile app, for example, you wouldn't be able to use client_secret since the code can be extracted by the user (thereby compromising your secret). TODO: flesh out details for mobile.

The return value will be a JSON object of the format:

  "access_token": <token>

The access token obtained can now be used to make STR API calls.

Using the token

Now that we have an access token we can make authorized requests to the STR API by adding an HTTP header to our requests. It should look like:

Authorization: Bearer <token>

See for our implementation. So a GET request would look like this:

Authorization: Bearer <token>

The result is a JSON object. It includes paging in order to reduce load on the STR servers. For example:

  "count": 579,
  "next": "http://localhost.localdomain:8000/api/v2/items/?page=2",
  "previous": null,
  "results": [
      "pk": 11466409,
      "style": "Carly",
      "size": "3XL",
      "listingLink": null

To traverse the paging results, just use the URLs returned in the next or previous properties. Just make sure you include the Authorization header when making requests to the next and previous URLs as well.

Refreshing the token

See the str-api-docs.

Sneaky shimming to work around CORS

You'll notice that we're actually "shimming" the API here. Our front-end (javascript) code isn't actually making remote API calls to the STR API. Instead, it's calling our own backend code which is, in turn, making a remote API call to STR. The reason for this is to get around CORS protection on the browser (since our server-side code isn't subject to the same security policies as a web browser). This should eventually be fixed on the STR side so that it can be called directly.

This shouldn't be a problem for mobile apps.