The API is based on REST/JSON, and there are JSON Schema's of most API items (Will be expanded).
Authentication: is through the standard HTTP Authorization header, but a custom scheme called "NemTilmeld" which consists of an "api_access_id":"signature", where the signature is based on a standard SHA256 HMAC signature using a secret_key and selected headerfields and the message body.
There are separate API access ID's for different endpoints, depending on whether the request is adding organizations or accessing an existing organization. Access to endpoints should also follow the domain name of the organization, e.g. for adding organizations or testing availablity of names www.nemtilmeld.dk should be used, and for other operations the organizations domain should be used.
All API GET endpoints returning arrays of items support and enforces the following GET parameters, so in order to fetch large sets it may be required to perform multiple requests.
| Parameter | Default | Description |
|---|---|---|
| order_by | id | Which fields from the JSON to order the result by, this can be a comma separated list of names, the supported names are at each endpoint below, the internal database ID is always appended to ensure a consistent order on ties. |
| direction | asc | The order applied to the above, applies to all items can be 'asc' or 'desc' |
| limit | 250 | Maximum number of entries returned at a time, supported values are 1-1000 |
| offset | 0 | The number or record ignored after the ordering, so essentially used to page the entries |
In addition to that some endpoints support additional parameters, to only fetch items within a given timespan, which variables and whether it is supported is noted on the individual endpoints
| Parameter | Default | Description |
|---|---|---|
| timespan_variable | The JSON variable to use as argument, the supported options are listed under the specific endpoint (if supported by that endpoint). | |
| timespan | None, must be present if the timespan_variable is present | The timespan to use, this is indicated as either an ISO8601 Period or as ISO8601 NON abbreviated timestamps as START/END (END is optional) with timezone separated , e.g.
|
The actual availability of these depends on the access credentials used, i.e. a specific API user will have access to one or more of these.
| URL Format | Method | Description |
|---|---|---|
| /api/categories/ | GET | Fetch a list of categories. Returns categories_list.json
Supports ordering fields:
|
| /api/events/ | GET | Fetch a list of events (the events on the account the user has access to). Returns events_list.json
Supports ordering fields:
|
| /api/locations | GET | Lists locations. Returns locations_list.json objects
Supports ordering fields:
|
| /api/locations/{location_id} | GET | Retrieve a specific location by ID, returns location.json |
| /api/reports/events/{event_id}/registrants | GET | Get a report on the registrants for this event. Returns event_registrants_report.json. Supports selecting only items within a timespan, this allows restriction on these 2 variables:
Supports ordering fields:
Also note that last_updated_time MAY include registrants which are updated in the system, but in a manner which may not affect the record in the API. i.e. the retrieving system MUST handle the fact that records may appear here even though they end up exporting as identical except for the update timestamp. |
| /api/series/ | GET | Fetch a list of series. Returns series_list.json
Supports ordering fields:
|
The API uses 4 HTTP Headers, 3 of which are mandatory on requests, these are:
| Header | Mandatory | Description | Example |
|---|---|---|---|
| Authorization | Mandatory | Authentication and Authorization information, as specifiec in the Security section. | NemTilmeld example_api_username:8338c48a06ec19672a954b25cd7ce2553c454a5b224b3debexamplesignature |
| Date | Mandatory | Standard HTTP date field, note this must represent now, as the API will reject messages which are old or into the future. | Sun, 06 Nov 1994 08:49:37 GMT |
| Nonce | Mandatory | Nonce value. Must be an increasing integer value (larger than the last API call for the user), the API will reject any message with an old value as a replay attack, could by milliseconds or microsecond precision time. | 123456 |
| API-Version | Optional | Specifies the version of the API, as an integer. Specifying no version will give you the latest response. | 1 |
The security, authentication and tamperproofing, consists of a custom HTTP Authorization scheme. This consists of a HTTP header: Authorization containing a value of this format NemTilmeld example_api_username:SHA256HMAC_in_lower_case_hex_format
The signature is calculated based on a selected number of items separated by a newline character (ascii 10 or 0x0A, in most escape sequences in strings "\n" or in .Net use "(char)(10)"), using a standard SHA256 HMAC (rfc2104, using SHA256 as the hash algorithm). The following fields are used in this order, unused fields are empty strings when adding the newlines:
GET /api/events/?limit=10&offset=20 HTTP/1.1
Date: Wed, 12 Apr 2023 08:59:32 GMT
Nonce: 1681294879863
becomes this string
"GET\n/api/events/?limit=10&offset=20\nWed, 12 Apr 2023 10:21:19 GMT\n1681294879863\n\n"
Assuming a user with username "example_api_username" and api_key "example_key" the signature then becomes:
ddd11fd1d6e21f400e12e88923846ff266a9514334044323324a371e2fbafbd6
Which should be added as the header as:
Authorization: NemTilmeld example_api_username:ddd11fd1d6e21f400e12e88923846ff266a9514334044323324a371e2fbafbd6
Implementation of a example client implementations
A simple client implementation can be found in NemTilmeldAPIClient.class.php.
Usage example:
include 'NemTilmeldAPIClient.class.php';
$client = new NemTilmeldAPIClient('example.nemtilmeld.dk', 'example_user', 'example_secret');
$result = $client->get('/api/events/123/registrants');
if ($client->getResponseCode() !== 200) {
echo "error response";
} else {
var_dump($result);
}