General

The HTTP API of Kadi4Mat makes it possible to programmatically interact with most of the resources that can be managed via the graphical user interface by sending suitable HTTP requests to the different endpoints the API provides.

Tip

In parallel to the API itself, a Python wrapper library called kadi-apy is also under development, which can be used as an alternative to using the API directly.

Using the API

All API endpoints start with the /api prefix, e.g. http://kadi4mat.example.edu/api. This prefix can optionally be followed by a version, e.g. /api/v1. This way, an explicit API version to use can be specified, which may be useful to ensure that applications or scripts that make use of the API do not break in case backwards incompatible changes to the API are introduced. When omitting the explicit version, the latest (in development) version will always be used by default.

Using the API requires a suitable client that can send HTTP requests. Some examples include simple command line tools such as curl, graphical tools such as Postman or any programming language that supports sending HTTP requests, either natively or through a third-party library, such as the popular requests library for Python. For some endpoints (namely, all endpoints supporting GET requests), the normal web browser can be used as well, which is an easy way to get accustomed to the API.

While using the API via the browser simply requires being logged in, using it from another client generally requires creating a personal access token (PAT) first. Such a token can be created via the web interface in the menu found in Settings > Access tokens and will operate with the same permissions as the user who created the token. Besides specifying the name of the token, which becomes especially useful when managing multiple tokens, an expiration date can be set. This date can optionally be used to prohibit using the token beyond the specified date. If no date is given, the token will never expire. As another security feature, a token can be limited to one or multiple scopes. Scopes can restrict a token’s access to specific resources or actions, i.e. some endpoints may not be usable at all or they may only return limited information about a resource. If no scopes are selected, the token will have full access by default.

Warning

It is generally recommended to limit the lifetime and scope of access tokens as much as possible. In any case, access tokens should be treated like passwords, so make sure to keep them safe.

After the PAT has been created, it has to be included as bearer token in an Authorization header for each request that should use the token. In the end, the header should look like the following: Authorization: Bearer <token>. Without this header, including the valid PAT, all endpoints will return a 401 status code. See the later section about other common error status codes.

Common request formats

As is the case for many HTTP APIs, the JSON format is used for most requests where data needs to be sent as part of the request body. Accordingly, for most requests the Content-Type header should be set to application/json. When a file is included in a request, the multipart/form-data content type should be used instead, including the actual file data as well as any additional metadata. Note that many clients will set such headers automatically, depending on the request body being sent.

Common response formats

The JSON format is also used for all responses that return any data, except for endpoints returning actual file data. Generally, there are endpoints that return a single deserialized resource, i.e. a single JSON object, or a list of multiple resources wrapped inside an items property, which itself is an array of JSON objects. In the latter case, most endpoints return paginated data, i.e. instead of returning all resources at once, only a chunk of the resources is returned, e.g. the first 10 requested records ordered by their last modification date. In this case, the response includes a _pagination property like the following:

{
    "items": [
        // The actual data.
    ],
    "_pagination": {
        "page": 2,
        "per_page": 10,
        "total_pages": 3,
        "total_items": 25,
        "_links": {
            "prev": "https://...?page=1&...",
            "self": "https://...?page=2&...",
            "next": "https://...?page=3&...",
        }
    }
}

Two other common properties include the _links property and the _actions property. These properties consist of different endpoints that can be used to either get additional information about a resource (e.g. _links.files to get the files of a record) or to perform certain actions relating to a resource (e.g. _actions.delete to delete a record). Both properties can either be included as an additional property of a resource, or as an additional meta property, similar to the _pagination property in the example above. This is mostly for convenience, so any related endpoints can be retrieved from the data itself withouth needing to build them manually.

Whenever some error occurs, i.e. a status code greater than or equal to 400 is returned, a corresponding error object will be returned as well. This object always includes at least the status code, a message and a description about the error. The following example shows a generic error object for the status code 400:

{
    "code": 400,
    "description": "The browser (or proxy) sent a request that this server could not understand.",
    "message": "Bad Request"
}

Common error status codes

In the following, some common error status codes are listed, which can be returned by most if not all endpoints.

400 (Bad Request)

This status code is relevant for any endpoint that requires data to be sent in the HTTP request body as JSON object or form data. It will be returned whenever the body is either missing, has a syntax error or includes any invalid values or keys. For the last case, additional information about the error(s) will be included in the error response object in the errors property.

401 (Unauthorized)

This status code is relevant for every endpoint and will be returned if either no valid PAT is included in the request, it has expired or its scope is insufficient for the requested endpoint. For the last case, all scopes the endpoint requires will be included as an array in the error response object in the scopes property.

403 (Forbidden)

This status code is relevant for any endpoint that requires certain permissions to create, retrieve or update data. It will be returned if the permissions of the user of the current PAT are insufficient.

404 (Not Found)

This status code is relevant for any endpoint with dynamic URL rules. It will be returned if the requested resource, e.g. given by a certain ID, does not exist. Furthermore, the same status code will be returned for non-API endpoints or, as usual, endpoints that do not exist at all.

405 (Method Not Allowed)

This status code is relevant for every endpoint and will be returned if the HTTP method used for a request is not supported by the requested endpoint.

429 (Too Many Requests)

This status code is relevant for every endpoint and will be returned if the rate limit configured in the application has been reached, i.e. too many requests have been sent in too short a time. In addition to the usual error response, some additional HTTP headers will be returned, the most useful being Retry-After, which specifies the amount of seconds to wait until another request may be sent.