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
(see the next section for possible version values). 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.
Tip
For some endpoints (namely, all endpoints supporting GET
requests), the normal
web browser can be used as well by simply typing the corresponding URL in the
browser’s address bar. This is an easy way to get accustomed to the API, however,
please note that this requires being logged in.
Generally, using the API requires a suitable access token for authorization. Each token
will operate with the same permissions as the user it belongs to. The currently
available token types are explained in the following sub-sections. Independent of token
type, the actual token value has to be included as bearer token in an
Authorization
HTTP header for each request that should use the token. In the end,
the header should look like the following:
Authorization: Bearer <token>
Note that the <token>
placeholder has to be substituted with an actual access token.
Without including this header, all endpoints will return a 401
status code. See the
later section about other common error status codes.
Personal Access Tokens
Personal access tokens (PATs) can directly be created via the web interface of Kadi4Mat in the menu found in Settings > Access tokens. When creating the token, an expiration date can optionally be set, which will prohibit using the token beyond the specified date. If no date is given, the token will never expire. As another security measure, 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 return limited information about a resource. If no scopes are selected, full access is granted to the token.
Warning
It is generally recommended to limit the lifetime and scope of PATs as much as possible for the specific need of the token. In any case, PATs should be treated like passwords, so make sure to keep them safe.
OAuth2 Tokens
OAuth2 tokens can be created by first registering an application capable of performing
the OAuth2 authorization flow via the web interface of Kadi4Mat in the menu found in
Settings > Applications. When creating an application, one or more scopes can be
selected. Similarly to PATs, if no scopes are selected, full access will be granted to
the access token. The selected scopes will be used automatically whenever requesting a
new access token, i.e. scopes requested via the scope
parameter will currently
always be ignored.
Warning
It is generally recommended to limit the scope of applications as much as possible for the specific need of the application.
After creating the application, a randomly generated Client ID and Client Secret will be issued, which are required to perform the OAuth2 authorization flow using different grant types. Currently, only two grant types are supported: the Authorization Code and the Refresh Token grant type. This means that an application needs to ensure that it can keep the issued client secret confidential. The following endpoints can be used to perform the OAuth2 authorization flow:
- GET /oauth/authorize
Ask a user to grant access to your registered application, based on its scopes. The user may need to log in to Kadi4Mat first. If granted, a new authorization code for use in the authorization code grant type will be returned in the redirect using the
code
query parameter. Optionally, the query parameters will also include thestate
value.Query parameters
response_type - Must be set to
code
.client_id - The client ID that was generated when registering the application.
redirect_uri - One of the redirect URIs that was specified when registering the application.
state - (optional) A randomly generated string that the server will return unaltered after the user authorizes the application, which the application should verify. Mainly used to prevent CSRF attacks.
code_challenge - (optional) The code challenge value when using PKCE. Must be derived from a randomly generated code verifier. Mainly used to prevent authorization code interception attacks.
code_challenge_method - (optional) The method used for deriving the code challenge from the code verifier. One of
S256
orplain
.
- POST /oauth/token
Exchange an authorization code for an access token (when using the
authorization_code
grant type) or request a new access token using a refresh token (when using therefresh_token
grant type). In both cases, the response will always include a new refresh token, which must be used for the next refresh request. Before that, refresh tokens do not currently expire. Note that scope information is only included if at least one scope was selected when creating the application.Request form data (Encoding:
application/x-www-form-urlencoded
)grant_type - One of
authorization_code
orrefresh_token
.client_id - The client ID that was generated when registering the application.
client_secret - The client secret that was generated when registering the application.
code - (for grant type
authorization_code
) The authorization code that was received in the previous step.redirect_uri - (for grant type
authorization_code
) The same redirect URI that was sent in the previous step.code_verifier - (optional, for grant type
authorization_code
) The derived code verifier when using PKCE.refresh_token - (for grant type
refresh_token
) The refresh token that was received previously.
It is also possible to revoke existing OAuth2 tokens using the corresponding revocation endpoint:
- POST /oauth/revoke
Revoke an existing access/refresh token pair.
Request form data (Encoding:
application/x-www-form-urlencoded
)token - The token that should be revoked. May either be an access token or refresh token. Note that the entire access/refresh token pair will be removed, independent of the given token type.
client_id - The client ID that was generated when registering the application.
client_secret - The client secret that was generated when registering the application.
token_type_hint - (optional) A hint about the token type submitted for revocation. One of
access_token
orrefresh_token
.
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 errors 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 access token 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. The status code may also be returned if the user associated with an access token is currently not authorized to use the API at all, e.g. if the corresponding account is inactive.- 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 associated with an access token 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.