API v3 is the preferred and full-featured API for user management. However, you may still need to use API v1 if you need to isolate access to user provisioning per sub-company or data source.
Status of API v1
The bulk user import in API v1 is deprecated
It has been replaced by the API v3 User Management API
If you can use API v3, you should: Link to API v3 docs
When API v1 is still useful
API v3 allows read access to all users on a platform. If your setup includes multiple user sources (like in a reseller model) and you want to avoid exposing users across sub-companies, API v1 can still be useful.
Why: API v1 is write-only, ideal when you need to provision users without reading platform-wide user data (write-only).
Base URL and authentication
Base URL
Use your platform domain:
https://your-name.platform.co.nl/
Authentication
Use an OAuth2 token with the write.users scope.
Token endpoint:
POST /o/token/
To request credentials (client ID, secret, and scopes), contact service@tinqwise.com.
How to import users
Endpoint
POST /api/accounts/user/bulk_import/
Required scope
write.users
JSON body structure
{
"users": [
{
"user_identifier": "EMP-123",
"first_name": "Alex",
"last_name": "Nguyen",
"email": "alex@example.com",
"groups": [
{"group_identifier": "manager", "group_type": "jobtitle"},
{"group_identifier": "amsterdam", "group_type": "city"}
],
"contract_start_at": "2026-01-01",
"contract_end_at": "2026-12-31",
"country": "NL",
"manager_identifier": "EMP-001",
"language": "en",
"uses_single_signon": false,
"status": "active"
}
]
}
Field references
users(required): Array of user objects.user_identifier(required): Unique user key (max 150 chars). Used to update existing users.first_name(optional, max 30 chars)last_name(optional, max 150 chars)email(required)groups(optional): Array of{group_identifier, group_type}contract_start_at(optional):YYYY-MM-DDcontract_end_at(optional):YYYY-MM-DDcountry(optional, max 30 chars): deprecatedmanager_identifier(optional):user_identifierof the managerlanguage(optional):en,nl, or another language code. Defaults to the platform default language.uses_single_signon(optional): Boolean (defaultfalse). Whentrue, no “set password” email is sent.status(optional):active(default) ordelete.deletesuspends the user.
Response
{ "success": true }
💡 Tip:
To verify success, go to Users > Integrations > User importer in the Control environment.
How to assign users to groups
Users can be assigned to groups via the groups field in each user object (see the request body example above).
Each group entry has two fields:
group_identifier: the group’s unique keygroup_type: the category the group belongs to (for examplejobtitleorcity)
Optionally, groups can be nested using parent fields:
parent_identifier(optional): the parent group’s identifierparent_type(optional): the parent group’s type
Notes:
Best practice: create one root “sorting” group per type, and place all groups of that type under it. For example, create
jobtitleswithgroup_type: "sorting"and set allgroup_type: "jobtitle"groups to haveparent_identifier: "jobtitles"andparent_type: "sorting"(see the Python example, step 2).Group identifiers are matched exactly. If the group does not exist yet, create it first using the groups bulk import endpoint (see the Python example below, step 2).
A user can be in multiple groups (for example one job title and one city).
🧪 Example usage (Python)
import requests
base_url = "https://yourname.platform.co.nl"
client_id = "put your client id here"
client_secret = "put your secret here"
Step 1. Authenticate
token_payload = {
"grant_type": "client_credentials",
"client_id": client_id,
"client_secret": client_secret,
"scope": "write.users write.groups",
}
token_response = requests.post(f"{base_url}/o/token/", data=token_payload).json()
token = token_response["access_token"]
headers = {"Authorization": f"Bearer {token}"}
Step 2. Create or update groups
groups_payload = {
"groups": [
{
"group_identifier": "jobtitles",
"group_type": "sorting",
"name": "Job Titles"
},
{
"group_identifier": "cities",
"group_type": "sorting",
"name": "Cities"
},
{
"group_identifier": "manager",
"group_type": "jobtitle",
"name": "Manager",
"parent_identifier": "jobtitles",
"parent_type": "sorting"
},
{
"group_identifier": "sales_associate",
"group_type": "jobtitle",
"name": "Sales Associate",
"parent_identifier": "jobtitles",
"parent_type": "sorting"
},
{
"group_identifier": "amsterdam",
"group_type": "city",
"name": "Amsterdam",
"parent_identifier": "cities",
"parent_type": "sorting"
}
]
}
groups_response = requests.post(
f"{base_url}/api/groups/tree-group/bulk_import/",
json=groups_payload,
headers=headers,
).json()Step 3. Import users
# Note: The manager (EMP-001) must be listed before users that reference them
users_payload = {
"users": [
{
"user_identifier": "EMP-001",
"first_name": "Sarah",
"last_name": "Johnson",
"email": "sarah.johnson@example.com",
"groups": [
{"group_identifier": "manager", "group_type": "jobtitle"},
{"group_identifier": "amsterdam", "group_type": "city"}
],
"country": "NL",
"language": "en",
"status": "active"
},
{
"user_identifier": "EMP-123",
"first_name": "Alex",
"last_name": "Nguyen",
"email": "alex@example.com",
"groups": [
{"group_identifier": "sales_associate", "group_type": "jobtitle"},
{"group_identifier": "amsterdam", "group_type": "city"}
],
"contract_start_at": "2026-01-01",
"contract_end_at": "2026-12-31",
"country": "NL",
"manager_identifier": "EMP-001",
"language": "en",
"uses_single_signon": False,
"status": "active"
}
]
}
users_response = requests.post(
f"{base_url}/api/accounts/user/bulk_import/",
json=users_payload,
headers=headers,
).json()
