The Web API supplies a number of HTTP endpoints that expose ways to create and modify users, groups, memberships, permissions, user activation, budgets and todos.
This documentation is written for developers who will be implementing an API connection for user provisioning with the TinQwise learning platform.
To export progress data for reporting instead, see Reporting APIs. For an overview of both, see APIs within the learning platform.
Where to start
Read the two setup articles first, then go to the endpoint you need.
Setup
Interactive documentation and test environment (below on this page)
Endpoints
Interactive documentation
To explore the available endpoints, use the interactive documentation.
It can be accessed at https://<platform name>.platform.co.nl/api/v3/public/docs/, for example https://tinqwise.platform.co.nl/api/v3/public/docs/.
This page only covers user management. The reporting endpoints have their own interactive documentation at https://<platform name>.platform.co.nl/api/v2/public/docs/, described in Reporting APIs.
Testing on QA
We recommend testing integrations on the QA environment.
You can find the API for QA at https://<platform name>.qa.platform.co.nl/api/v3/public/docs/, for example https://tinqwise.qa.platform.co.nl/api/v3/public/docs/.
đ§ Be careful
Any changes you make on QA will be reset periodically. The data on QA is refreshed on the Monday of every odd week.
Rate limits
Each API client can make 120 requests per minute to the same URL path. Query parameters are not part of the path, so /api/v3/public/users/?offset=100 and /api/v3/public/users/?employee_id=123 count toward the same limit.
When you go over the limit, the API responds with status 429 Too Many Requests and a Retry-After header with the number of seconds to wait. Wait that long and send the same request again. A request that was rate limited has not changed any data.
Syncing efficiently
Most integrations stay well within the limit if they follow these guidelines:
Reuse your access token. A token is valid for 10 hours. Request a new one only when it has expired, not before every call.
Use large pages. All list endpoints accept
limit(default 100, maximum 1000) andoffset. Listing 25,000 users takes 25 requests withlimit=1000, against 250 with the default.Look up single users with a filter, such as
?employee_id=,?email=or?saml_username=, instead of listing all users.Store the uuid of each user in your own system. You can then update a user directly with
PATCH /api/v3/public/users/<uuid>/, without looking them up first.Handle 429 responses by waiting for the number of seconds in
Retry-After, as shown in the example below.
Caveats and limitations
It is currently not possible to give users sub-admin permissions through the API. This must be done manually through Control, see Create an Admin (restricted access) group in TinQwise Control.
It is currently not possible to manage group type details through the API, such as whether a group type shows in profiles and can be selected in a report.
Creating a todo does not grant the user access to the module or journey it points to. This must be arranged separately, for example through an automation. See Todos via the API.
Example API usage with Python and the requests library
Don't forget to replace the base url, client id and client secret with the credentials for the acceptance (QA) environment you received.
import time
import requests
base_url = "https://<<your platform name>>.qa.platform.co.nl"
# Request a token once and reuse it for all calls; it is valid for 10 hours
payload = {
"grant_type": "client_credentials",
"client_id": "<<your client id>>",
"client_secret": "<<your client secret>>",
"scope": "v3:users:read v3:users:write",
}
token = requests.post(f"{base_url}/o/token/", data=payload).json()["access_token"]
headers = {"Authorization": f"Bearer {token}"}
def get(url, params=None):
while True:
response = requests.get(url, headers=headers, params=params)
if response.status_code == 429:
# Rate limited: wait as long as the API asks, then retry the same request
time.sleep(int(response.headers.get("Retry-After", 60)))
continue
response.raise_for_status()
return response.json()
# List all users, 1000 per page
users = []
url, params = f"{base_url}/api/v3/public/users/", {"limit": 1000}
while url:
page = get(url, params)
users.extend(page["results"])
url, params = page["next"], None # "next" already contains limit and offset
print("Retrieved", len(users), "users.")
# Look up a single user by employee_id instead of listing all users
page = get(f"{base_url}/api/v3/public/users/", {"employee_id": "12345"})
if page["results"]:
print(page["results"][0]["first_name"], "is on the platform")