Overview
Before starting, we recommend reading the Introduction to Custom Integration article
Kindly remember that custom integrations:
- Support syncing users, licenses, roles, and last used dates
- Cannot sync expenses, even if the integrated app contains expense data
- Work best for onboarding/offboarding/license optimization scenarios
To build your own integration and push user and license data into Torii you will need to follow the below 4 steps process.
Note, steps 3 & 4 require some technical knowledge.
IT - Setup/ Preparation
Technical - Use the API to upload and sync users
STEP 1 - Get Torii API Key
Prerequisite - Torii admin permission is required
- Go to Settings >> API Access
- Click on Generate API key
- In Generate API Key make sure you select the Full access option
- Make sure you store the API key somewhere safe because you will not be able to see it again after step 5. If, for some reason, you ever lose your API key, you can always generate a new one.
- Click Got it
STEP 2 - Create a new Custom Integration
- Go to the Integrations page,
- Scroll down and click the ADD CUSTOM INTEGRATION tile
- Find the App you want to integrate
- Click Add integration
- Copy the App account ID and store it somewhere safe
- Close the window
STEP 3 - Upload the data to Torii
Prerequisites - Generate a JSON file named ‘users_file.json’ in the working folder and verify it complies with the "File schema"
Click here for Torii's full API documentation
💡 Make sure you replace the placeholders in the API calls with your variables, e.g. replace API_KEY
with the API key you generated in step 1.
There are 2 techniques you can use to upload the data to Torii
- For files up to 3MB - use the Upload File (up to 3MB) API or run the following command:
curl --request POST "https://api.toriihq.com/v1.0/files/upload" \
--header "Authorization: Bearer API_KEY" \
--header "Content-Type: multipart/form-data" \
--form 'type="customIntegrationData"' \
--form 'file=@"FULL/PATH/TO/FILE"' - For files larger than 3MB, follow the process below:
- Create a one-time URL upload link
- Upload the file to S3
- Update Torii with the upload information
-
- Create a one-time, private URL upload link - use the Get parameters for uploading files API or run the following command:
curl "https://api.toriihq.com/v1.0/files/url?name=users_file.json&type=application/json" \
You should get a response that looks like this:
--header "Authorization: Bearer API_KEY"{
The url is used in step 2 and the filePath is used in step 3.
"uploadFileParameters": {
"url": "https://torii-app-test.s3.us-west-2.amazonaws.com/uploads/23/1704790932720/users_file.json?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAWVLDEIRX6X6UEP5I%2F20240109%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20240109T090212Z&X-Amz-Expires=300&X-Amz-Signature=09c8a054052a4c069a40f0ada5771742bb3f38ee12a6974e7cfbbef08ad9726c&X-Amz-SignedHeaders=host&x-amz-acl=private&x-id=PutObject",
"filePath": "1704790932720/users_file.json"
}
}
Note
- These parameters are embedded in the upload file parameters; consider it when
writing the code.
- The upload URL is valid for a short period of time, so make sure to upload the file
before it expires.
- Upload the file to S3 - use the url from the response and run the following command:
curl --request PUT S3_URL --data @'FULL/PATH/TO/FILE'
// Example
curl --data @'/Users/user/Downloads/users_file.json' -X PUT "https://torii-app-test.s3.us-west-2.amazonaws.com/uploads/23/1704790932720/users_file.json?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAWVLDEIRX6X6UEP5I%2F20240109%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20240109T090212Z&X-Amz-Expires=300&X-Amz-Signature=09c8a054052a4c069a40f0ada5771742bb3f38ee12a6974e7cfbbef08ad9726c&X-Amz-SignedHeaders=host&x-amz-acl=private&x-id=PutObject"Note
If you are pasting the URL in your terminal, make sure it doesn’t add any escape characters (e.g.
\
)
- Update Torii with the upload information - use the Store file information in DB API or run the following command:
curl "https://api.toriihq.com/v1.0/files" \
--header "Authorization: Bearer API_KEY" \
--header "Content-Type: application/json"
-data '{"path":"S3_FILE_PATH","type":"customIntegrationData"}'
You should get a result with the Torii upload ID like in the below example: Save the id value for step 4
- Create a one-time, private URL upload link - use the Get parameters for uploading files API or run the following command:
STEP 4 - Sync the uploaded file to Torii
- Use the Sync custom integration API or run the following command:
curl --request PUT "https://api.toriihq.com/v1.0/services/sync/custom" \
--header "Authorization: Bearer API_KEY"
--data '{"idFile":"FILE_ID", "idAppAccount": "APP_ACCOUNT_ID"}' - Replace the API_KEY, FILE_ID from the previous step (Upload ID)
- Replace the APP_ACCOUNT_ID you received from Torii in STEP 2 (add custom integration) like in the below example:
You should get a response indicating that the operation was successful, like in the below example:
Error Message: in case of an error, a relevant message like "Illegal file structure, Wrong file id, Wrong account", etc. will be displayed.
Last Notes:
- The syncs are NOT incremental, meaning that on each sync you must provide all the users you currently have in the systems (and not only new ones for example)
- It may take some time for the sync to complete. To confirm a successful sync, Go to Integration window (1) and make sure the hourglass (2) disappeared and a green checkmark (3) is displayed.
Q & A
Q: Can I sync absolutely any app with Torii?
A: Yes, as long as the data is structured according to the Torii file schema.
Q: How often will data be pushed into Torii & Does Torii support date synchronization with custom integrations?
A: You can decide how often you want to push the data into Torii. We recommend pushing the data regularly, so it stays up to date. When data has not been synced for more than 10 days, we show an alert in the UI.
Q: Can I perform workflow actions for a custom app?
A: Yes, through custom action configuration
Q: What happens when disconnecting custom integration?
A: The app account is revoked, and no more syncs are possible. You can always reconnect the same account. Read this article to learn what happens to your data when you disconnect an integration
Q: How do I delete and update users?
A: Each time a new file is pushed, the old data is overwritten. If users were removed from the file - they would be removed from the app in Torii. If user attributes were updated in the file - they will be updated in Torii.
File schema
The file should include the following information. Note that fields must have the exact field name as shown in the following table:
Field Name |
Description |
Type |
Required |
users |
Users using the application |
User[] (see user object below) |
Yes |
licenses |
Licenses used in your org |
License[] (see license object below) |
No |
User
Field Name |
Description |
Type & Options |
Required |
Id |
Unique identifier of a user in the application |
String |
No |
|
The user's unique email |
String |
Yes |
firstName |
The user's first name |
String |
No |
lastName |
The user's last name |
String |
No |
status |
The status of the user in Torii. Only active users are displayed as users of the application |
Enum (active/deleted) Default: active |
No |
externalStatus |
The status of the user as it appears on the application’s site |
String |
No |
roles |
Array of roles the user has in the application |
String[] |
No |
lastUsedDate |
The last date the user used the application |
Date ISO 8601 (YYYY-MM-DD) |
No |
License
Field Name |
Description |
Type & Options |
Required |
name |
Unique name |
String |
Yes |
unassignedAmount |
Number of licenses that are not assigned to users |
Number |
No |
users |
Users under this license |
licenseUser[] (see licenseUser object below) |
No |
pricePerUser |
How much does it cost per user |
Number |
No |
License User
Field Name |
Description |
Type & Options |
Required |
|
User's email |
String |
Yes |
licenseStatus |
License status. If not provided, will be defined by user status |
Enum (active/inactive/deleted) |
No |
lastUsedDate |
Last date user used the license |
Date ISO 8601 (YYYY-MM-DD) |
No |