Skip to Content

Making requests to the TwentyThree API

Requests

The API is based on HTTP, and any request is made to the workspace's api base url, for example https://videos.examples.com/api/2, followed by the API endpoint such as /user/create or /tag/related).

Both GET and POST requests are allowed, but note that the GET-style query string parameters (i.e. /api/tag/related?tag=mytag) are not used on POST requests.

For example, using the tags list method a request could look like this:

https://video.example.com/api/2/tag/list?size=2

And return something like this:

{
    "status": "ok",
    "permission_level": "anonymous",
    "cached": true,
    "p": 1,
    "size": 20,
    "total_count": 6,
    "cache_time": 1712310006,
    "data": [
        {
            "tag": "drones",
            "count": 2,
            "url": "/tag/drones"
        },
        {
            "tag": "open",
            "count": 1,
            "url": "/tag/open"
        }
    ]
}

 

The API expects UTF-8 formatted input and will return in UTF-8 as well.

Responses

All responses from the platform come in the form of JSON and will always have a status attribute detailing if the request was ok or error. Success and failure responses will also be reflected in HTTP status codes, for example 200 for successful requests.

Success

{
    "status": "ok",
    "permission_level": "admin",
    "cached": false,
    "message": "The user has been created",
    "data": {
        "user_id": 96584427,
        "email": "somebody@twentythree.com",
        "username": "somebody",
        "full_name": "Somebody Cool",
        "site_admin": 0,
        "timezone": "Etc/UTC"
    }
}

Failure

Whenever a request to the API fails, a response detailing the exception is returned. The response includes an error_code and a detailed error description:

{
    "status": "error",
    "message": "User already exists",
    "code": "user_already_exists",
    "permission_level": "admin"
}


JSON-P style responses

Responses are also available as a JSONP-style callback using the callback parameter. Requesting the same data with https://videos.example.com/api/2/tag/list?size=2&callback=listTags gets you:

/* */
listTags({
  "status": "ok",
  "permission_level": "anonymous",
  "cached": true,
  "p": 1,
  "size": 2,
  "total_count": 37,
  "cache_time": 1712310327,
  "data": [
    {
      "tag": 2016,
      "count": 1,
      "url": "\/tag\/2016"
    },
    {
      "tag": "adventures",
      "count": 4,
      "url": "\/tag\/adventures"
    }
  ]
});

This is valuable for reading publicly available data across domains in a browser:

<script>  
  function listTags(o) {
    for (i in o.data) {
      console.log(o.data[i].tag);
    }  
  }
</script>
<script src="https://videos.example.com/api/2/tag/list?size=2&callback=listTags"></script> 

Pagination

A number of API methods (including for example /photo/list, /user/list and /tag/list) returns a list of objects. These lists will often only return a subset of the data, and the programmer will need to handle pagination explicitly. This is done using p and size:

  • size: Number of items to return with each request. Where nothing else is stated, the default value for size is 20 and the maximum value is 100.
  • p: The page number to return. The default value is 1 and given a size of 20, p=2 will return items 21 through 40, and p=5 will yield items 81 through 100.

Any request offering pagination will include the p and size parameters in their responses, and in addition a third property is included:

  • total_count: The total number of object available through the request.

For example, you might query https://videos.example.com/api/2/album/list?size=2:

{
    "status": "ok",
    "permission_level": "anonymous",
    "cached": true,
    "p": 1,
    "size": 2,
    "total_count": 6,
    "cache_time": 1712310527,
    "data": [
        {
            "album_id": 62945245,
            "title": "First Category",
            ...
        },
        {
            "album_id": 62915571,
            "title": "Second Category",
            ...
        }
    ]
}

Based on the response, we know that there are 6 categories distributed along 3 pages. Armed with this information we can make a few additional requests ending with https://videos.example.com/api/2/album/list?size=2&p=3:

{
    "status": "ok",
    "permission_level": "anonymous",
    "cached": true,
    "p": 3,
    "size": 2,
    "total_count": 6,
    "cache_time": 1712310600,
    "data": [
        {
            "album_id": 86246876,
            "title": "Fifth Category",
            ...
        },
        {
            "album_id": 61550144,
            "title": "Sixth Category",
            ...
        }
    ]
}