REST API
Using the Relution REST API (Application Programming Interface)
All of Relution’s functionality is available through an extensive REST API. You can use this API to control Relution from any other application or via scripts. Documentation of the API is available via the help menu at the top right.
Create API Access Tokens
To access Relution from third-party systems or scripts, you need an API Access Token.
- Click on your username in the upper right corner of the Relution portal.
- Navigate to:
Profile → Access Token → Add Access Token
. - Name the token and copy it.
Use the token in the X-User-Access-Token
HTTP header to authenticate requests.
⚠️ The token will only be displayed once when it is created.
Example Scripts
1. Users in CSV File Format
- In the first line of the
.csv
file, insert a header line with the desired property names. - The order of the columns is not relevant.
- You can omit properties that are not needed.
- Mandatory fields:
userid,email,first name,last name,password
Passwords must follow the policy under
Settings → Password Policy
. Phone numbers must be in international format, e.g.+4912345
.
You can add up to 15 custom properties named:
custom1
– custom15
👉 Download a template via the Relution Portal:
Users → Users → Three dots menu → Import users via CSV → Download template
Example CSV:
name,email,givenName,surName,password,phone,position,country,managedAppleId,custom1,custom2
user1,user1@company.com,Heinz,Ketchup,p4ssw0rd,+49234346345,user1 position,user1 country,user1.id@company.com,43,Operations
user2,user2@company.com,Heinz,Ketchup,p4ssw0rd,+49234346345,user2 position,user2 country,user2.id@company.com,24,Marketing
user3,user3@company.com,Heinz,Ketchup,p4ssw0rd,+49234346345,user3 position,user3 country,user3.id@company.com,30,HR
user4,user4@company.com,Heinz,Ketchup,p4ssw0rd,+49234346345,user4 position,user4 country,user4.id@company.com,32,Sales
user5,user5@company.com,Heinz,Ketchup,p4ssw0rd,+49234346345,user5 position,user5 country,user5.id@company.com,45,Finance
user6,user6@company.com,Heinz,Ketchup,p4ssw0rd,+49234346345,user6 position,user6 country,user6.id@company.com,30,Purchase
2. Uploading Users via the Relution Portal
- Go to:
Users → Users → Three dots menu → Import users via CSV
- Select your CSV file and separator.
- Assign imported users to one or more groups.
- Imported users will then appear in the overview.
3. Creating Users via the Relution API
⚠️ Relution 5.34 change:
User import is now a background job with states (RUNNING / FINISHED).
Each job stores a report per line.
Legacy import was removed.
Some column names changed:
first name
→givenName
last name
→surName
managed apple id
→managedAppleId
phone number
→phone
userId
→name
Steps
- Prepare your
users.csv
file. - Copy the bash script below into a file, e.g.
uploadUserCSV.sh
. - Make it executable:
chmod +x ./uploadUserCSV.sh
- Run it:
./uploadUserCSV.sh -f 'FILEPATH' -h 'HOST' -a 'YOUR-ACCESS-TOKEN' -u 'ORGANIZATION_UUID'
Arguments
Argument | Meaning | Example | Default | Required |
---|---|---|---|---|
-f | Path to your users.csv | user.csv | ✅ | |
-h | Relution host | https://relution.io | ✅ | |
-a | API access token | xxxxxxxx | ✅ | |
-u | Organization UUID | 01995C17-6BD0-7F84-87E9-21A1498B386F | ✅ | |
-r | Roles assigned to users | Organame%20Device%20User | ❌ | |
-s | Separator for parsing | SEMICOLON | COMMA | ❌ |
-w | Overwrite existing users | true | false | ❌ |
Output Example
============
success: 1, skipped: 1, failed: 1
2: [SUCCESS] User ... successfully stored with version 1.
3: [FAILED] Number of data fields does not match number of headers.
4: [SKIPPED] User Test2 should not be overwritten.
4. Bash Script: Upload Users via CSV
#!/bin/bash
set -e
#--------------------------------------------------------------------------------
while getopts "a:h:f:u:w:r:s:" opt; do
case $opt in
a) # apikey
ACCESS_TOKEN="$OPTARG"
;;
h) # host
HOST="$OPTARG"
;;
f) # File
FILE="$OPTARG"
;;
u) # organization uuid
ORGANIZATION_UUID="$OPTARG"
;;
w) # Overwrite
OVERWRITE="$OPTARG"
;;
r) # Role
ROLE="$OPTARG"
;;
s) # Separator
SEPARATOR="$OPTARG"
;;
\?)
echo "Unknown option -$OPTARG" >&2
;;
esac
done
if [[ -z ACCESS_TOKEN ]]; then
echo "Please specify an access token (-a)"
exit 1
fi
if [[ -z $HOST ]]; then
echo "Please specify a Host URL (-h)"
exit 1
fi
if [[ ! -f $FILE ]]; then
echo "Please specify an existing csv file (-f)"
exit 1
fi
if [[ -z $ORGANIZATION_UUID ]]; then
echo "Please specify an organization uuid (-o)"
exit 1
fi
if [[ -z $SEPARATOR ]]; then
SEPARATOR="COMMA"
fi
if [[ -z $OVERWRITE ]]; then
OVERWRITE=false
fi
if [[ -z $ROLE ]]; then
ROLE=Organame%20Device%20User
fi
call() {
# Create a temporary file for the response body
tmpfile=$(mktemp) || { echo "Failed to create temp file" >&2; exit 1; }
http_code=$(curl -sw "%{http_code}" -o "$tmpfile" -H "Accept: application/json" -H "X-User-Access-Token: $ACCESS_TOKEN" "$@")
content=$(cat "$tmpfile")
rm -f "$tmpfile"
if [[ "$http_code" != "200" && "$http_code" != "201" ]]; then
echo "fail: $http_code" >&2
echo $content >&2
exit 1
fi
# Output the content for capture
printf "%s" "$content"
}
echo "Will start importing users to '${ORGANIZATION_UUID}' on server '${HOST} as '${ROLE//%20/ }'".
echo "Using '$FILE' with separator of type '$SEPARATOR'."
echo "Next step: uploading file"
upload=$(call -F "file=@$FILE;type=text/csv" "$HOST/api/management/v1/csvImport/upload/users")
file_uuid=$(echo "$upload" | jq -r '.results[0].uuid')
echo "Done uploading file: $file_uuid"
echo "============"
echo "Next step: start import job"
job=$(call -X POST "$HOST/api/v1/security/users/import/fromFile/$file_uuid?overwrite=$OVERWRITE&role=$ROLE&csvSeparator=$SEPARATOR")
job_uuid=$(echo "$job" | jq -r '.uuid')
echo "Job started: $job_uuid"
job_status=""
while [[ "$job_status" != "FINISHED" && "$job_status" != "FAILED" ]]; do
sleep 1
job=$(call -X GET "$HOST/api/management/v1/csvImport/job/$job_uuid")
job_status=$(echo "$job" | jq -r '.results[0].status')
echo "Job status: $job_status"
done
echo "============"
success_count=$(echo "$job" | jq -r '.results[0].successCount')
skipped_count=$(echo "$job" | jq -r '.results[0].skippedCount')
failure_count=$(echo "$job" | jq -r '.results[0].failureCount')
echo "success: $success_count, skipped: $skipped_count, failed: $failure_count"
if [[ "$failure_count" -ne 0 ]]; then
query='{"sortOrder":{"sortFields":[{"name":"line","ascending":true}]}}'
report=$(call -X POST -H "Content-Type: application/json" --data "$query" "$HOST/api/management/v1/csvImport/job/$job_uuid/entityStates/query")
reports=$(echo $report | jq -c '.results')
echo "$reports" | jq -c '.[]' | while read -r item; do
line=$(echo "$item" | jq -r '.line')
status=$(echo "$item" | jq -r '.status')
message=$(echo "$item" | jq -r '.message')
echo "$line: [$status] $message"
done
fi
5. Create a New Organization
#!/bin/bash
#--------------------------------------------------------------------------------
# Web service URL, change the server name as needed
SVR_URL="https://<myserver>/api/v1/security/organizations/creationWizardRequests"
# Access token of System Admin, create it by opening https://<server>/#/profile
# Open this URL in your browser while logged in as System Administrator.
# NOTE: This is not an URL you can reach through clicking through the portal!
ACCESS_TOKEN="<sysadmin_api_token>"
# HTTP Headers
ACCEPT="application/json"
ACCEPT_CHARSET="UTF-8"
# Query example
read -r -d '' JSON_BODY << 'EOF'
{
"limit": 10,
"offset": 0,
"getNonpagedCount": true,
"sortOrder": {
"sortFields": [
{
"name": "lastConnectionDate",
"ascending": false
}
]
},
"filter": {
"type": "logOp",
"operation": "AND",
"filters": [
{
"type": "stringEnum",
"fieldName": "platform",
"values": [
"ANDROID",
"ANDROID_ENTERPRISE",
"IOS"
]
},
{
"type": "stringEnum",
"fieldName": "status",
"values": [
"COMPLIANT",
"INACTIVE"
]
}
]
}
}
EOF
echo "Querying devices at $SVR_URL..."
echo
# No changes should be required beyond this line...
RESPONSE=$(curl -X POST \
${SVR_URL}${FILTER} \
-H "X-User-Access-Token: $ACCESS_TOKEN" \
-H "Accept: $ACCEPT" \
-H "Accept-Charset: $ACCEPT_CHARSET" \
-H "Content-Type: $ACCEPT" \
--write-out " HTTP_STATUS=%{http_code}" \
--silent \
-d "$JSON_BODY")
if [[ $RESPONSE =~ HTTP_STATUS=([0-9]+) ]]; then
HTTP_STATUS=${BASH_REMATCH[1]}
fi
if [[ $HTTP_STATUS -lt 200 || $HTTP_STATUS -gt 299 ]]; then
echo "HTTP status: $HTTP_STATUS"
else
echo "Done. Parsing ouput..."
echo
echo "${RESPONSE%HTTP_STATUS*}" | jq '.results[].name'
fi
6. Query Devices in an Organization
#!/bin/bash
#--------------------------------------------------------------------------------
# Web service URL, change the server name as needed
SVR_URL="https://<myserver>/api/v2/devices/baseInfo/query"
# Access token of an Orga Admin, create it by clicking on the user name in the top right corner of the portal.
# Then click "Profile", "Access tokens", "Add".
ACCESS_TOKEN="<orga_admin_access_token>"
# HTTP Headers
ACCEPT="application/json"
ACCEPT_CHARSET="UTF-8"
# Query example
read -r -d '' JSON_BODY << 'EOF'
{
"limit": 100,
"offset": 0,
"getNonpagedCount": true,
"sortOrder": {
"sortFields": [
{
"name": "lastConnectionDate",
"ascending": false
}
]
},
"filter": {
"type": "logOp",
"operation": "AND",
"filters": [
{
"type": "stringEnum",
"fieldName": "platform",
"values": [
"ANDROID",
"ANDROID_ENTERPRISE",
"IOS"
]
},
{
"type": "stringEnum",
"fieldName": "status",
"values": [
"COMPLIANT"
]
}
]
}
}
EOF
echo "Querying devices at $SVR_URL..."
echo
# No changes should be required beyond this line...
RESPONSE=$(curl -X GET \
${SVR_URL}${FILTER} \
-H "X-User-Access-Token: $ACCESS_TOKEN" \
-H "Accept: $ACCEPT" \
-H "Accept-Charset: $ACCEPT_CHARSET" \
-H "Content-Type: $ACCEPT" \
--write-out " HTTP_STATUS=%{http_code}" \
--silent \
-d "$JSON_BODY")
if [[ $RESPONSE =~ HTTP_STATUS=([0-9]+) ]]; then
HTTP_STATUS=${BASH_REMATCH[1]}
fi
if [[ $HTTP_STATUS -lt 200 || $HTTP_STATUS -gt 299 ]]; then
echo " HTTP status: $HTTP_STATUS"
else
echo "Done. Parsing ouput..."
echo ${RESPONSE%HTTP_STATUS*} | jq '.results[].name'
fi
echo