Query

Many get() methods (such as Users.get()) accept a query parameter.

Example:
"query": {
    "fields": [
        "id", "loginName", "fullName", "description"
    ],
    "conditions": [
        {
            "fieldName":"QUICKSEARCH",
            "comparator":"Like",
            "value":"doe"
        }
    ],
    "combining":'And',
    "orderBy": [
        {
            "columnName":"loginName",
            "direction":"Asc"
        }
    ],
    "start":0,
    "limit":2
}

Fields

Fields restrict members (also called columns or fields) of returned objects, e.g. they return only basic information about the user, but not the group membership, quota usage etc.

You can find a list of supported fields for appropriate structure in Method and Data Reference

Some methods (see method descriptions) support a special value of "QUICKSEARCH" which searches the most important columns (e.g. loginName, fullName and description).

The values of comparator are predefined, e.g. “Eq” (equality) or “Like” (substring match).

Conditions

Only objects matching the conditions will be returned.

Combining

Combining expresses how the conditions are combined: "Or" (at least 1 condition must match), "And" (all conditions must match).

orderBy

Set of columns to order by, with ascending ("Asc") or descending ("Desc") ordering.

start

How many entries to skip, e.g. start = 50 and limit = 10 means return 51st to 60th user, with given conditions and in the given ordering.

limit

Maximum number of entries to return. It is not an error if there are fewer entries available. Special value of –1 means no limit.

Id

Some objects, such as users, domains and groups, contain "id ". It is a unique, permanent identifier of an object. Treat it as opaque.

You may store "id" in a third-party application and use it later.

Error handling

Principles

Errors during request processing are carefully reported. The error information returned to the client contains both machine-readable and human-readable details. Each method description contains a list of errors that can be returned besides the common errors like “Request parse error”.

Simple errors

In case of simple methods like Users.get() or Users.create(), server aborts the requested operation, e.g. a user is not created at all, rather than creating a semi-finished account, and "error" object is returned (instead of "result"), with "code", "message" and "data" members:

"error": {
    "code": 1001,
    "message": "User %1 (%2) already exists .",
    "data": {
        "messageParameters": {
            "positionalParameters": ["jdoe", "Jane Doe"],
            "plurality": 1
        }
    }
}

Placeholders and translation

Let’s look at "error.data" object. It has one member, "messageParameters" object, with its two members:

  1. "positionalParameters" array contains string replacements for "message" placeholders: "jdoe" for %1, "Jane Doe" for %2.
  2. “plurality" describes grammatical number. Some messages do not need a plural form (like the example above), but some do, e.g. "If you want to add more than %1 [user|users], contact your Kerio Connect administrator."

Before unfolding the placeholders, the client needs to choose the correct form of the message based on "plurality" (number of items the message talks about) and language. English rules are simple (singular for 1 item, plural for 0 and 2 or more), while another languages have different rules (e.g. singular for 0 or 1 item) or even more options (e.g. singular for 1, dual – yet another form – for 2-4, and plural for 0 or 5+ items).

Please do not confuse plurality with %1, e.g. "You are removing [the only distributed domain|all remaining distributed domains]" does not even contain %1 at all but plurality is still important.

Note: In other programming languages, you may initially opt to display imperfect messages with placeholders not unfolded or even not to display detail messages at all.

Partial success

Let’s start with an example. We called Users.remove() and passed 20 users in. The response is:

{
    "jsonrpc": "2.0",
    "id": "9",
    "result": {
        "errors": [{
            "inputIndex": 3,
            "code": 1002,
            "message": "Failed to delete %1, user was not found.",
            "messageParameters": {
                "positionalParameters": ["jdou"],
                "plurality": 1
            }
        }]
    }
}

The response says that the operation went quite well, but one user wasn’t deleted.

Some methods like Users.set() or Users.remove() operate on multiple items. It’s natural that the operation may fail on some of the items. Server then continues in proceeding of the remaining items, and reports the problematic items in response.

Even these methods may totally fail, e.g. due to broken encoding of parameters (“Parse error”), and return "error" object in response, as described above in Simple errors. If the server understands the call but the method fails on each argument (none of users can be removed), it is still considered a partial success by definition . It is up to the client application to eventually handle the problems of both kinds, and the client always receives all the information it needs.

In case of partial success, the response contains "result" object with output arguments of the method, not an "error" object. All these methods are defined to have "errors" (note plural “-s”) array as one of the output arguments (actually there are no other output arguments for Users.remove() method). Each element of the "errors" array contains "code", "message" and "messageParameters" with the meaning described in Simple errors and Placeholders and translation, along with the "inputIndex" integer, which is a zero-based index to the input array, e.g. 3 means that it was 4th user which could not have been deleted.

List of Error Codes

error.code error.message Meaning HTTP Status
(not sent) (not sent) Success, response is sent. 200
-32700 Parse error. Request wasn't valid JSON. 500
-32603 Internal error.   500
-32602 Invalid params.   500
-32601 Method not found. The requested method doesn't exist. 404
-32600 Invalid request.
(Too many files uploaded. etc.)
Request wasn't valid JSON-RPC v2 (e.g. method is missing). 400
-32099..-32000 Server error. (Reserved for Kerio-defined server errors.) 500
-32002 Request timeout. No response from the server. Timeout is controlled by the client. N/A
-32001 Session expired. Re-login is needed. 500
0   (Must not be used) (None)
1 to 999   (Reserved) 1 to 999
413 Request entity too large. The client tried to upload a file bigger than the limit. 413
1000 to 1999   (Reserved for Kerio-common errors) 200
1000 Operation failed. The command was accepted, the operation was run and returned an error. (E.g. Cannot delete the user.)

This is a generic code used when no specific code is defined.

200
1001 Already exists. Cannot create the item as it already exists.

E.g. User "john" already exists.

200
1002 No such entity.
(Domain %1 does not exist. etc.)
User / message / folder / etc. does not exist. 200
1003 Not permitted. Server refused to proceed.

E.g. Cannot delete the primary domain. E.g. You cannot delete yourself.

200
1004 Access denied. Insufficient privileges for the required operation. (E.g. deleting Ben by Amy.)

The application is not obliged to report such a specific code, a generic error is also permitted.

200
2000 to 8999   (Reserved for Kerio applications) 200

File upload and download

Download

To provide maximum compatibility with JSON frameworks, file download is done in two simple steps:

  1. Plain method call. It returns information about the file ready to download: fileDownload object with members url, name and length.

    Request:
    {
        "jsonrpc": "2.0",
        "id": 1,
        "method": "Users.exportToCsv",
        "params": {
            "query": {
                "fields": [
                    "loginName"
                ],
                "start": 0,
                "limit": "-1",
                "orderBy": [{
                    "columnName": "loginName",
                    "direction": "Asc"
                }]
            },
            "domainId": "keriodb://domain/4baa0a76-1a8c-4887-b56e-6fe4ff1f4f53",
            "filename": ""
        }
    }
    
    Response:
    {
        "jsonrpc": "2.0",
        "id": 1,
        "result": {
            "fileDownload": {
                "url": "http://localhost:4040/admin/api/jsonrpc/download/admin@localhost/4203959aad/users_localhost_2010-09-27.csv",
                "name": "users_localhost_2010-09-27.csv",
                "length": 1487
            }
        }
    }
    

  2. Plain file download. The URL from the previous response is used.
    GET /admin/api/jsonrpc/download/admin@localhost/4203959aad/users_localhost_2010-09-27.csv HTTP/1.0
    Accept: */*
    

Upload

Post Upload Request

If you post (send HTTP POST request) a new file to the Connect server, you should obtain a response with the file id. This id can be used for further work.

Content-Type: multipart/form-data; boundary=---------------------------1655174106359
Content-Length: 1712 -----------------------------1655174106359

Content-Disposition: form-data; name="csvFile"; filename="users.csv"
Content-Type: application/vnd.ms-excel 

Name;FullName;Description;Enable;DataSource;Authentication;Role;Groups;MailAddress;EmailForwarding;ItemLimit;...

Post Upload Response

{
    "jsonrpc": "2.0",
    "id": "1",
    "result": {
        "fileUpload": {
            "id": "73af7c5b28",
            "length": 1487,
            "name": "users.csv"
        }
    }
}

FileId

Several methods (like Users.parseFromCsv) accept a parameter fileId. Instead of the client data, they work with a file previously uploaded on server.

Example
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "Users.parseFromCsv",
    "params": {
        "fileId": "73af7c5b28",
        "domainToImport": "keriodb://domain/4baa0a76-1a8c-4887-b56e-6fe4ff1f4f53"
    }
}

Cleanup

Uploaded files are removed regularly. There is a 60-minute timeout after which a file can be deleted unless it is accessed.

Tools

You can use any tool of your choice. During our development of the public API, we found the following tools to be useful:

If you want to perform a certain API action, you can get inpired by web administration.