# BIS Safety Software REST API > The BIS Safety Software REST API (v.01) lets customer systems read and update users, training records, topics, forms, datasets, locations, assets, classroom events, tasks and reward points. Get a bearer token from `POST /token` with an API credential (Admin > Setup > Integration > API Credentials). Base URL: `https://www.bissafety.app/rest/v.01` Authentication: call `POST /token` with your API credential to get a bearer token, then send `Authorization: Bearer ` with every call. The Open API endpoints take `client_id` and `client_secret` request headers instead. ## Introduction Docs: https://www.bissafety.app/api-docs#introduction Organizations today are using an increasingly diverse range of online applications to meet their changing needs. As applications become more advanced for specialized functions and tasks, they provide a more efficient and intuitive workflow for organizations to share data. This diagram shows how applications in a third party system access information from another application via standardized requests called **Application Programming Interfaces** (**APIs**), specially defined for the program being called upon. ![](https://www.bissafety.app/v1/assets/img/API_WorkflowDiagram_v1.png) In the context of online applications, an API is usually defined as a set of Hypertext Transfer Protocol (**HTTP** ) request messages packaged with definitions for the response messages in Extensible Markup Language (**XML** ) or JavaScript Object Notation (**JSON**) format. ###### RESTful APIs With the number of unique APIs being implemented daily, understanding how each API works can become confusing and time consuming. Representational State Transfer (**REST** ) is a standardized way of creating HTTP APIs. APIs that conform to REST standards and architecture are called RESTful APIs and use a consistent naming scheme for their Universal Resource Locators (**URLs**), commonly known as the web address seen at the top of your browser. A **resource** is a virtual object associated with data. Every resource within an API has its own unique URL. Resources are modeled as a JSON object and are stored in code using the special identifier *key:value* pair. For example, a resource containing user information stores users' first names and last names using the identifiers, *FirstName:value* and *LastName:value*, respectively, in the code. The resources for an API are defined using different kinds of parameters. A RESTful API usually uses parameter values in the following ways: * With a URL path: **…/api/resource/parametervalue** * With a query path using name value pairs (*name=value* ): **…/api?type=user\&id=23** ###### Primary API Functions BIS Safety Software's primary API functions provide a framework for external applications to communicate directly with our servers and complete a variety of functions at any time, including: * Creating, updating, or retrieving information from user accounts * Retrieving completion statuses, completion dates, and expiry dates for all courses, training records, and forms for each user * Retrieving a list of all documents uploaded to a user’s account * Retrieving a report on all company locations and roles set up in BIS Safety Software * Retrieving a list of classroom calendar events These API functions can be executed on demand at any time by following the instructions and guidelines outlined in this document. The BIS Safety Software API can be accessed through the base URL provided below. ## Response Codes Docs: https://www.bissafety.app/api-docs#responsecode BIS uses 3-digit conventional HTTP response codes to indicate the success or failure of an API request. Generally, the first digit in the 3-digit code designates the following information: * ***2XX*** - API request is successful * ***4XX*** - the request failed because of what was sent, for example a missing required parameter, a missing or expired token, or an API credential without access to the endpoint. * ***5XX*** - the request failed because of an error on the BIS servers. Try again later, and contact BIS Support if it keeps happening. Errors return a JSON body with `error` and `error_description`, for example `{"error": "invalid_token", "error_description": "The access token is invalid"}`. | Status | error | error_description | What to do | |--------|------------------------|------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------| | 400 | invalid_request | Authorization header is missing | Send `Authorization: Bearer YOUR_BEARER_TOKEN` with every call except `POST /token` and the Open API endpoints. | | 401 | invalid_token | The access token is invalid | The token is wrong or has expired. Tokens last 3600 seconds (1 hour); request a new one from `POST /token`. | | 403 | access_denied | The access token does not have access to the requested URI | Your API credential is not allowed to call this endpoint. Grant it in Admin \> Setup \> Integration \> API Credentials. | | 400 | invalid_request | client_id, client_secret and grant_type are the required fields. | `POST /token` only. Send all three as form fields. | | 400 | unsupported_grant_type | Only supported grant_type(s) are: client_credentials | `POST /token` only. Send `grant_type=client_credentials`. | | 401 | invalid_client | Invalid client_id and/or client secret | `POST /token` only. Check the credential in Admin \> Setup \> Integration \> API Credentials. | | 400 | invalid_request | Client_ID, Client_Secret missing in request header | Open API endpoints only. Send `client_id` and `client_secret` as request headers. | | 401 | invalid_credentials | Client_ID, Client_Secret are invalid | Open API endpoints only. Check the credentials your BIS Account Manager gave you. | **Paging:** endpoints that return lists take `offset` (how many records to skip) and `recordsperpage`. The defaults differ per endpoint; see each endpoint's parameters. ## Authentication Docs: https://www.bissafety.app/api-docs#auth Endpoint: `POST /token` Applications access BIS Safety Software's APIs by first making a call to our authentication endpoint to acquire a **bearer token**. Calls to the authentication endpoint require API credentials. API keys can be generated by users with the **Client Security Admin** role within your portal. If no one in your organization has this role assigned, please contact your **BIS Account Manager** to have the **Client Security Admin** role granted to an appropriate user. 1. **Client ID**: A unique secret company identification number 2. **Client Secret**: A secret security key for BIS Safety Software authentication The bearer token is used in all following requests to call our APIs. Every call must be preceded by an authorization header containing the bearer token. Your bearer token is also required to set up a custom **single sign-on** (**SSO**) for your company, if required. Your secret API Credentials help protect your company's information and company's user information, so be sure to keep them secure and do not share them in publicly accessible environments. Parameters: - `grant_type` (string, form, required, default `client_credentials`): The only supported value is 'client_credentials'. - `client_id` (string, form, required): The secret unique Client ID given by BIS Account Managers. - `client_secret` (string, form, required): The secret BIS Safety Software Key provided by BIS Account Managers. Request: ```bash curl -X POST "https://www.bissafety.app/rest/v.01/token" \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "client_id=YOUR_CLIENT_ID" \ -d "client_secret=YOUR_CLIENT_SECRET" \ -d "grant_type=client_credentials" ``` Response: ```json { "scope": "", "access_token": "YOUR_TOKEN", "expires_in": 3600, "token_type": "bearer" } ``` ## Users Docs: https://www.bissafety.app/api-docs#users The user object is a critical element of our system. Most third party systems plan to sync users between their system and BIS Safety Software. Using the user API endpoint, you can list, add, update, and deactivate users in BIS Safety Software. Some important parameters used in this User API endpoint, as well as some other API endpoints and the SFTP Import, are discussed below. **Location** API endpoints may have location and location ID code request parameters or include location-based objects. Location refers to the name of the location in the company hierarchy in BIS Safety Software shown in the Users tab. The location ID code refers to the unique location ID code assigned to each location in the company hierarchy, which allows your system to import or move users into correct locations in BIS Safety Software. Our APIs prioritize the location ID code over the location name, such that users will be added or moved to the location in the hierarchy with the matching location ID code. If the location ID code is not found in BIS Safety Software, the API searches for a matching location name. Either neither the location ID code nor location name can be found, the user will be added to or moved to the set **default location**. The default location is set in the portal’s company settings. New locations can be created when APIs are executed using the AddLocation request parameter. **Request Parameters** AddLocation *numeric* Allows new locations to be created in the hierarchy shown in the Users tab in BIS Safety Software. By default, the value is “1”, which adds the location. If a parent location ID code is provided and found in BIS Safety Software, the new location is added under the location assigned the parent location ID code. If a parent location ID code is not provided, the new location will be added directly under the highest company location in the hierarchy. Accepted values: **1** / **0** **Company Role** Users can have company roles, which must match the roles set up in BIS Safety Software. You can assign multiple company roles by separating them using a comma. New company roles can be automatically created using the AddRole request parameter. New company roles are added automatically to the company’s training matrix if the training matrix feature is enabled, but no training is assigned to the new role. **Request Parameters** AddRole *numeric* Allows new company roles to be created, assigned to users, and added to the training matrix if enabled. The value is “1” by default, which creates and assigns the new role. A message will display “___” if the company role was successfully added and assigned. If the company role does not exist in BIS Safety Software, the user will not be assigned any role. Accepted values: **1**/ **0** **Primary Role** Users can have multiple company roles, one of which you can designate as a primary role. Using this User API endpoint, you can add both company roles and primary roles if they do not exist. **Request Parameters** AddRole *numeric* Allows a company role assigned to users to be designated as a primary. The value is “1” by default, which assigns the new primary role. If the value is "0", the API will not process or assign any new primary or company roles. Accepted values: **1**/ **0** **System User Role** Users can be assigned any system user role except the Client Admin role, which controls their permission levels to change your company’s portal and access data within it. When changing existing or assigning new system user roles, they must match user roles in BIS Safety Software. Otherwise, there will be no change to an existing user’s system user role or new users will be given the Learner role by default. (Client admin system user roles cannot be removed using API endpoint calls.) **Subcompany Name** When companies have sub companies, there will be a parent portal and sub portals. Users can be moved between the parent portal and sub portals, as well as between sub portals. The sub company name must match the company name in the sub company’s portal for users to be added to or moved successfully to their location. Data from sub portals can be included when data is retrieved using API endpoints are executed using request parameters. **Custom Fields** Your company can add custom fields with specified field names and field types to user profile accounts from the Company Setup under the Settings section in the Profile Fields subsection. BIS Safety Software creates a unique ID key for each custom field. You can find unique custom field keys by accessing the browser’s developer tool (right-click the custom field in the user profile and select Inspect). Under the Elements menu, the html coding for that custom field is highlighted. The unique ID key for the custom field can be identified in the custom field’s special name as the numerical digits following “SpecialFields_”. In the example, the developer tool shows a custom field for Rehire Date, which shows “name=’SpecialFields_291'”, where the unique ID key is “291”. Objects for custom fields are stored in the code using the identifier key:value pair using the custom field’s unique ID key. In the example, data for Rehire Date is represented as {‘291’:’YYYY-MM-DD’}. Multiple custom fields can be included by separating them with commas; for example, {‘291’:’2021-11-26’,’592’:’1 year term’,’703’:’12345’}. ![](https://www.bissafety.app/v1/assets/img/API_Custom_Field.png) ### GET /user - List Users Docs: https://www.bissafety.app/api-docs#user-list Endpoint: `GET /user` Using this API endpoint, you can list up to 1000 users in the sytem. If you have more than 1000 users, then use pagination to list all your users in the system in groups of 1000 or less. The response shows user information, including entries in custom profile fields created in the settings of the portal's Company Setup page. Note: this API endpoint will not list the primary role of users if the Primary user toggle in the Training Matrix module settings in the portal's Setup module is disabled. Each role's **primary** field is returned only when the primary role feature is turned on for your company. Parameters: - `userid` (string, query): The User ID is a unique and consistent identifier for each user in your system that is also used as a common identifier for the same users in BIS Safety Software. This identifier, typically an employee ID or a system user ID, allows users' data to be correctly exchanged between your system and BIS Safety Software. To get multiple users, you can pass User ID as comma separated list. - `bisinternaluserid` (numeric, query): System ID of a user in BIS. - `location` (string, query): The location name or location ID code of a specific location in your company hierarchy. The company hierarchy is the company structure shown in the Users tab, which structures your company's employees, contractors, clients, customers, etc. by location, sub locations, departments, or however best meets your company's needs. - `role` (string, query): The user's specific company role or job title indicated by the role name or code. - `status` (string, query, default `A`): A filter to get users with certain statuses: active, inactive, or deactivated. By default, the API returns active users "A". If you want to get deactivated users, use the parameter value "I". If you want to get both active and deactivated users, leave the parameter value blank "". **Please Note:** Account Status Active and Inactive are considered as active. The only difference is Inactive account has not yet been activated by user. Deactivated accounts are the once that we deactivated by admins and will not longer allowed to access the system. Accepted values: **A** / **I** / "" - `firstname` (string, query): Filters users by first name. - `lastname` (string, query): Filters users by last name. - `birthdate` (date, query): Filters users by their birthdate specified in the date format (YYYY-MM-DD). - `modified` (date, query): Filter users that were added or modified after a certain date time specified in ISO date format (YYYY-MM-DDTHH:MM:SSZ). - `includesubcompany` (numeric, query, default `0`): This parameter is used for the companies that have sub companies. You can include users for all sub companies by specifying "1". By default, sub companies are not included "0". Accepted values: **0** / **1** - `offset` (numeric, query, default `0`): Offset the results by a certain value. By default, the offset is zero "0". - `recordsperpage` (numeric, query, default `500`): Limit the number of users that are returned up to a maximum of 1000. - `includeqrcode` (numeric, query, default `0`): When value is 1, user QR code data is included in response. Request: ```bash curl -X GET "https://www.bissafety.app/rest/v.01/user" \ -H "Authorization: Bearer YOUR_BEARER_TOKEN" ``` Response: ```json { "recordsperpage": "1", "offset": "0", "count": 770, "users": [ { "companyrole": "Sample Role 1|Sample Role 2", "companyroles": [{ "code": "00001", "name": "Sample Role 1", "primary": "true" },{ "code": "00002", "name": "Sample Role 2", "primary": "false" }], "location": "eCommerce Users", "cellphone": "16472702345", "startdate": "", "evaluator": "", "firstname": "Aarian", "stateprov": "Alberta", "BISInternalUserID": 2145533, "birthdate": "1985-05-01", "homephone": "17803862134", "locationcode": "", "subcompanyname": "In-House BIS", "status": "A", "middlename": "A", "country": "Canada", "lastname": "Hosein", "userid": "B0001053", "username": "AHosein3", "ProfilePicApproved": 0, "workphone": "17803862134", "postalcode": "T0B 2V0", "language": "English", "emergencyContact": "Jane", "emergencyContactPhone": "", "email2": "test1@test.com", "email1": "test2@test.com", "ProfilePic": "", "employer": "", "city": "Edmonton", "address": "9999 51st Street", "sin": "678355412", "terminationdate": "", "qrcode": "C7A16E39AA2F03FBB4B47792457EB99F91643B26D6346D395DFEAE81E1C69C1846343D27855A1377", "modified": "ISO Date/Time 2023-01-01T10:10:00Z", "CUSTOM FIELD NAME 1": "VALUE", "CUSTOM FIELD NAME 2": "VALUE", "membership": { "id": "ID", "name": "Elite", "expiryDate": "YYYY-MM-DD", "dateAdded": "ISO Date/Time 2023-01-01T10:10:00Z" } } ] } ``` ### POST /user - Import Users Docs: https://www.bissafety.app/api-docs#user-import Endpoint: `POST /user` You can**add** , **update** , and **deactivate** users using this API endpoint. Returns an array of result objects in the same order as the input users array. Each result includes an error flag (0 = successfully added/updated, 1 = failed) along with status/logs. Users are matched in this order: **bisinternaluserid** , then **hrsystemid** , then **email1** (only when useEmailAsIdentifier is 1), then **userid**. Only the first identifier present in the record is used. If no account matches on hrsystemid or email1, the API falls back to userid before creating a new account. When an account is created with an **hrsystemid** , that ID is stored against the account. Sending the same hrsystemid later updates that same account and writes the **userid** (Employee ID) onto it once it is supplied, so accounts can be created before an Employee ID exists. An **hrsystemid** is added to an account, never replaced. If you send a corrected or reassigned hrsystemid for a user, the earlier value stays on that account and can still match later imports. Send a value you do not plan to change. Parameters: - `users` (json, form, required): This parameter is an array of user objects in JSON format. A maximum of 200 users can be imported into BIS Safety Software at a time. - `returnlogs` (numeric, form, default `0`): Returns additional logs of each user field updated. Accepted values: **1** /**0** Sample `users`: ```json [ { "userid": "String - Required unless hrsystemid, bisinternaluserid, or email1 (when useEmailAsIdentifier is 1) is provided - Unique identifier from your (third-party) system. Maps to the **Employee ID** field in BIS and is used to match existing accounts on import. This is NOT the internal BIS user ID (see bisinternaluserid).", "hrsystemid": "String - Optional - Persistent unique ID of the user in your HR system (for example BambooHR, SuccessFactors, ADP). Stored against the account and used to match the user on later updates when userid, name or email have changed. Recommended when accounts are created before an Employee ID exists.", "firstname": "String - Required", "preferredname": "String - Optional", "middlename": "String - Optional", "lastname": "String - Required", "location": "String - OPTIONAL - If location or locationcode is not provided then new users will be added under default location", "locationcode": "String - OPTIONAL", "parentlocation": "String - OPTIONAL", "parentlocationcode": "String - OPTIONAL", "companyrole": "String - OPTIONAL", "primaryrole": "String - OPTIONAL - Specifies the user's primary role. The value must exist within the role list (companyrole). If the specified role is not part of companyrole, it will be automatically removed or ignored during processing", "email1": "String - Recommended", "email2": "String - Optional", "address": "String - Optional", "city": "String - Optional", "country": "String - Optional - Default Portal's country", "stateprov": "String - Optional - Default Portal's state/province", "postalcode": "String - Optional", "workphone": "String - Optional", "cellphone": "String - Optional", "homephone": "String - Optional", "evaluator": "String - Optional - User's manager userid", "evaluator2": "String - Optional - User's Evaluator 2 field userid", "birthdate": "Date - Optional - Date YYYY-MM-DD format", "startdate": "Date - Optional - Date YYYY-MM-DD format", "terminationdate": "Date - Optional - Date YYYY-MM-DD format", "employer": "String - Optional", "status": "String Required - Accepted value A and I", "language": "String - Optional - Accepted value English/French/German/Español - Default English", "emergencyContactName": "String - Optional - Emergency contact name", "emergencyContactMobile": "String - Optional - Emergency contact phone", "customfields": "Struct - Optional - this is structure of all custom fields with values - Default {}", "addlocation": "Numeric - Optional - What should be done if location provide does not exists - Accepted value 0/1 - Default 1", "updatelocation": "Numeric - Optional - update location - Accepted value 0/1 - Default 0", "addParentLocation": "Numeric - Optional - add parent location if does not eixsts - Accepted value 0/1 - Default 0", "useDefaultLocation": "Numeric - Optional - What should be done if location provide does not exists and addlocation is 0 - Accepted value 0/1 - Default 1", "addrole": "Numeric - Optional - What should be done if company role provide does not exists - Accepted value 0/1 - Default 1", "proceedOnInvalidRole": "Numeric - Optional - Used only when addrole is 0. Pass 1 to still save the user when a company role passed does not exist. The missing roles are skipped, the valid roles are assigned, and the status returns 'There are invalid company roles.' With 0 the user is not saved and the status returns 'Company role does not exists.' - Accepted value 0/1 - Default 0.", "addsystemroles": "String - Optional - list of system roles that need to be added to user", "removesystemroles": "String - Optional - list of system roles that need to be removed from user", "subcompanyname": "Optional - Only needed when a company has sub companies and want to update users under sub company", "socialinsurancenumber": "String - Optional", "bisinternaluserid": "Optional - Unique ID in BIS", "onlyUpdateAPICompanyRole": "Optional - If 1 then do not remove roles added by admins, only remove roles added by API - Accepted value 0/1 - Default 0", "profilePicture": "Optional - You can pass Base64 String to update the profile picture for the user. File size is limited to 2MB.", "skipMoveUser": "Numeric - Optional - Pass 1 if you do not want users to be moved from existing location to passed/default location - Accepted value 0/1 - Default 0.", "skipaccountswithuserid": "Numeric - Optional - Pass 1 if you do not want the users with userid setuo in there account be udpated by other user account details - Accepted value 0/1 - Default 0.", "sendInvitationEmailOnCreation": "Numeric - Optional - Pass 1 if you want the users to receive account invitation email upon account creation - Accepted value 0/1 - Default 0.", "useEmailAsIdentifier": "Numeric - Optional - Pass 1 to find the user to update by email1 when bisinternaluserid and hrsystemid are not passed. userid is then not required as long as email1 is passed. If no account matches email1, the API tries userid next. If more than one account has that email1, the user is not saved - Accepted value 0/1 - Default 0.", "useNameAsIdentifier": "Numeric - Optional - Pass 1 if you want to allow API to find users to update using only the firstname and lastname, when the primary identifiers are not passed - Accepted value 0/1 - Default 0." } ] ``` Request: ```bash curl -X POST "https://www.bissafety.app/rest/v.01/user" \ -H "Authorization: Bearer YOUR_BEARER_TOKEN" \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "users=[{'userid': '123456','firstname': 'Test','lastname': 'User'}]" ``` Response: ```json [ { "userid": "123456", "status": "Updated.", "logs": ["Lastname updated to Smith."], "error": 0 }, { "userid": "4554455", "status": "Potential duplicates found.", "logs": [], "error": 1 }, { "userid": "775588", "status": "Added.", "logs": [], "error": 0 } ] ``` ### GET /user/documents - Get Documents Docs: https://www.bissafety.app/api-docs#user-documents Endpoint: `GET /user/documents` You can use this API endpoint to get the documents that are uploaded in a user's profile in BIS Safety Software. Parameters: - `userid` (string, query, required, default `-1`): The User ID is a unique and consistent identifier for each user in your system that is also used as a common identifier for the same users in BIS Safety Software. This identifier, typically an employee ID or a system user ID, allows users' data to be correctly exchanged between your system and BIS Safety Software. Request: ```bash curl -X GET "https://www.bissafety.app/rest/v.01/user/documents?userid=USER_ID" \ -H "Authorization: Bearer YOUR_BEARER_TOKEN" ``` Response: ```json { "documents": [{ "documenturl": "http://www.bissafety.app/assets/UserDriverDocument/MHR.12.07.17 R1.xlsx", "documentname": "Sachin Test" }, { "documenturl": "http://www.bissafety.app/assets/UserDriverDocument/2018-02-14_ABC.png", "documentname": "2018-02-14_0913.png" }] } ``` ### POST /user/login - Login Docs: https://www.bissafety.app/api-docs#user-login Endpoint: `POST /user/login` This API can be used to validate user's username and password and return some basic details of the user. Parameters: - `username` (string, form, required): Username used by user to login to BIS. - `password` (string, form, required): Password used by user to login to BIS. Request: ```bash curl -X POST "https://www.bissafety.app/rest/v.01/user/login" \ -H "Authorization: Bearer YOUR_BEARER_TOKEN" \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "username=USERNAME" \ -d "password=PASSWORD" ``` Response: ```json { "status": "success", "user": { "lastname": "LASTNAME", "firstname": "FIRSTNAME", "bisinternaluserid": "BIS_INTERNAL_USERID", "email": "EMAIL" } } ``` ### POST /user/siteactivity - Site Activity Docs: https://www.bissafety.app/api-docs#site-activity Endpoint: `POST /user/siteactivity` You can use this API endpoint to get last date and time the user accessed this site. The response from this API will be the exact same **records** parameter, but with two additional fields **status** and **message.** Parameters: - `records` (json, form, required): This parameter is an array of training record objects in JSON format. A maximum of 200 records can be imported into BIS Safety Software at a time. Sample `records`: ```json [ { "userid": "String - Required - Unique userid in third party system", "siteid": "String - Required - Unique siteid in third party sysytem", "activityDate": "Date in ISO format - Required - The last date and time the user accessed the site." } ] ``` Request: ```bash curl -X POST "https://www.bissafety.app/rest/v.01/user/siteactivity" \ -H "Authorization: Bearer YOUR_BEARER_TOKEN" \ -H "Content-Type: application/x-www-form-urlencoded" \ --data-urlencode 'records=[{"userid": "BIS0956e16", "siteid": "1232Test", "activityDate": "2023-08-07 04:30:00.000+05:30"}, {"userid": "BIS0956e16", "siteid": "REDTW 23123", "activityDate": "2023-09-11 19:19:00.000+05:30"}]' ``` Response: ```json { "records": [ { "message": "", "status": "success", "activityDate": "2023-08-07 04:30:00.000+05:30", "userid": "BIS0956e16", "siteid": "1232Test" }, { "message": "", "status": "success", "activityDate": "2023-09-11 19:19:00.000+05:30", "userid": "BIS0956e16", "siteid": "REDTW 23123" } ] } ``` ## Training Docs: https://www.bissafety.app/api-docs#training You can get training records for users using two API endpoints described below. ### GET /training - Completed Training Docs: https://www.bissafety.app/api-docs#training-trainings Endpoint: `GET /training` You can get users' completed training. The results will include all online courses, forms, and historical completed training records. Note: If *userid* or *bisinternaluserid* or *coursecode* or *combination of email and lastname* are not passed in and *from/to dates* are not available, the API gets the records that were completed in the past 24 hours for all users in the portal. Parameters: - `userid` (string, query): The User ID is a unique and consistent identifier for each user in your system that is also used as a common identifier for the same users in BIS Safety Software. This identifier, typically an employee ID or a system user ID, allows users' data to be correctly exchanged between your system and BIS Safety Software. - `bisinternaluserid` (numeric, query): System ID of a user in BIS. - `coursecode` (string, query): External course id of the course to get completions for a specific course. - `email` (string, query): The email address in the profile account of each user in your system. Both the email and lastname request parameters must be passed to this API endpoint to have a successful API response. - `lastname` (string, query): The last name in the profile account of each user in your system. Both the lastname and email request parameters must be passed to this API endpoint to have a successful API response. - `fromdate` (date, query): All training completed on or after the provided date in the date format (YYYY-MM-DD). If the fromdate and todate parameters are blank, then the training completed in the previous day from the time this API endpoint is called will be returned. NOTE: Total number of days between the fromdate and todate must be 30 days or less. - `todate` (date, query): All training completed on or before the provided date in the date format (YYYY-MM-DD). If the fromdate and todate parameters are blank, then the training completed in the previous day from the time this API endpoint is called will be returned. NOTE: Total number of days between the fromdate and todate must be 30 days or less. - `onlypassed` (numeric, query, default `1`): Returns the completed training that is passed and accepted by Admins by default. If the value is specified as "0", all completed training is returned, including passed, failed, and training not yet accepted. Accepted values: **1** /**0** - `status` (string, query): Leave blank to retrieve results for all course types. Accepted values: **Public** /**Private** - `type` (string, query): The completed training type: training record (TR), form (AF), or Online Course (OC). If this parameter value is left blank, records for all training types will be provided. Accepted values: **TR** / **AF** / **OC** - `deletedrecord` (numeric, query, default `0`): This parameter is used to get deleted **Training Records** only. By default, this parameter is set to 0 Accepted values: **0** / **1** - `includesubcompany` (numeric, query, default `0`): This parameter is used for the companies that have sub companies. You can include users for all sub companies by specifying "1". By default, sub companies are not included "0". Accepted values: **0** / **1** - `includeincompletecourses` (numeric, query): This parameter is used to get incomplete course completions. By default this parameter is set to 0. Accepted values: **0** / **1** - `datefilter` (string, query, default `completion`): `completion` (default): `fromdate`/`todate` filter on the completion date - the historical behavior. `modified`: incremental sync mode, pulls "what changed since my last sync". `fromdate`/`todate` filter on the record's last-modified watermark and are treated as UTC dates covering full UTC days (a time component, if supplied, is ignored; the window closes at 23:59:59 UTC of `todate`; no dates returns the last 24 hours of changes). The response field `modifiedon` carries the exact last-changed timestamp (ISO 8601, UTC) the watermark filter uses; it is `null` only for rows that were never modified, such as incomplete rows returned via `includeincompletecourses=1`. `modifieddate` keeps its historical behavior (Mountain Time date, blank when never modified). Records match on `completionid` + `completiontype` for upsert. Other response dates remain Mountain Time, day granularity. Same 30-day window cap and same filters as the default mode. Sample `datefilter`: ``` modified ``` Request: ```bash curl -X GET "https://www.bissafety.app/rest/v.01/training?userid=USER_ID" \ -H "Authorization: Bearer YOUR_BEARER_TOKEN" ``` Response: ```json { "training": [{ "results": [{ "completionid": 1342409, "permissionid": 1323433, "completionstatus" : "completed", "completiontype": "online", "certificate": "https://www.bissafety.app/index.cfm?action=trm.downloadcertificate&data=65E25EDSD6EE0148462E", "certificatefiletype": "pdf", "courseid": "", "internalcourseid": "", "coursename": "100-07 Propane Hose Inspection and Testing", "modifieddate": "", "modifiedon": "", "issuingauthority": "", "expirydate": "", "completiondate": "2024-01-18", "pass": true, "score": 80, "trainerprovstate": "Ontario", "courseinstructor": "", "internal": 0, "addeddate": "2018-01-24", "trainer": "CPA - Propane Training Institute", "deleted": 0 }, { "completionid": 1272386, "permissionid": 1323433, "completionstatus" : "completed", "completiontype": "online", "certificate": "https://www.bissafety.app/index.cfm?action=trm.downloadcertificate&data=65E25EDSD6EE0148462E", "certificatefiletype": "png", "courseid": "", "internalcourseid": "", "coursename": "Atmospheric Gas Tester.", "modifieddate": "", "modifiedon": "", "issuingauthority": "HSE Integrated", "expirydate": "2025-10-17", "completiondate": "2021-10-17", "pass": true, "score": 80, "trainerprovstate": "Alberta", "courseinstructor": "", "internal": 0, "addeddate": "2017-10-26", "trainer": "HSE Integrated Training", "deleted": 0 }], "lastname": "User", "userid": "32", "username": "tuser", "firstname": "Test", "email": "test2@test.com", "subcompanyname": "In-House BIS" }, { "results": [{ "completionid": 1983540, "permissionid": "", "completionstatus" : "completed", "completiontype": "training", "certificate": "https://www.bissafety.app/index.cfm?action=trm.downloadcertificate&data=65E25EDSD6EE0148462E", "certificatefiletype": "pdf", "courseid": "", "internalcourseid": "", "coursename": "Carte de conducteur d'embarcation de plaisance", "modifieddate": "", "modifiedon": "", "issuingauthority": "Formation Nautique Québec", "expirydate": "", "completiondate": "2022-01-19", "pass": true, "score": 80, "trainerprovstate": "Quebec", "courseinstructor": "", "internal": 0, "addeddate": "2019-01-22", "trainer": "Formation Nautique Québec", "deleted": 0 }], "lastname": "User", "userid": "1111", "username": "test", "firstname": "Test", "email": "test@test.com", "subcompanyname": "In-House BIS" }] } ``` ### GET /training/online - Online Course Result Docs: https://www.bissafety.app/api-docs#training-online Endpoint: `GET /training/online` This API endpoint returns all completed, in progress, and not started online courses with their results and progress details. Parameters: - `userid` (string, query, required): The User ID is a unique and consistent identifier for each user in your system that is also used as a common identifier for the same users in BIS Safety Software. This identifier, typically an employee ID or a system user ID, allows users' data to be correctly exchanged between your system and BIS Safety Software. - `bisinternaluserid` (numeric, query): System ID of a user in BIS. Note: If this parameter is passed then userid parameter is not required. - `courseid` (string, query): The course ID set up for the online course and specific to each company. - `includesubcompany` (numeric, query): This parameter is used for the companies that have sub companies. You can include users for all sub companies by specifying "1". By default, sub companies are not included "0". Accepted values: **0** / **1** Request: ```bash curl -X GET "https://www.bissafety.app/rest/v.01/training/online?userid=USER_ID" \ -H "Authorization: Bearer YOUR_BEARER_TOKEN" ``` Response: ```json { "training": [{ "results": [{ "datestarted": "2021-10-06 12:35:52", "Status": "In Progress Section 2/2", "score": "", "pass": "", "isrepeated": 0, "ID": 4654238, "datefinished": "" }], "dateadded": "2021-10-05 23:00:00", "type": "Regular course/exam", "Name": "royce test default completon fee 1" }, { "results": [{ "datestarted": "2021-10-08 06:50:28", "Status": "Completed with 100%", "score": 100.0, "pass": "Yes", "certificate": "", "certificatefiletype": "", "isrepeated": 0, "ID": 4660071, "datefinished": "2021-10-08 07:36:54" }], "dateadded": "2021-10-07 23:00:00", "type": "SCORM course", "Name": "Office Safety - Marcom Test Course for OCWA" }, { "results": [{ "datestarted": "", "Status": "Not Started", "score": "", "pass": "", "isrepeated": "", "ID": "", "datefinished": "" }], "dateadded": "2020-12-23 00:00:00", "type": "Regular course/exam", "Name": "04 WHMIS Worker Site Specific Update Training Information v2" }] } ``` ### POST /training - Push Training Records Docs: https://www.bissafety.app/api-docs#pushrecord Endpoint: `POST /training` This API endpoint imports training record. The response from this API will be the exact same **records** parameter, but with two additional fields **status** and **message** Parameters: - `records` (json, form, required): This parameter is an array of training record objects in JSON format. A maximum of 200 records can be imported into BIS Safety Software at a time. When **archiveOldRecords**is passed as 1, API will find records for the same course and user that were completed prior to the record being added and archive those records. If record being added has completion date prior to the one already exists in the system then API will not add the record. - `includesubcompany` (numeric, form): This parameter is used for the companies that have sub companies. You can include users for all sub companies. By default, sub companies are not included "0". Accepted values: **0** / **1** Sample `records`: ```json [ { "userid": "String - Required - Unique userid in third party system", "courseid": "String - Required - Unique customer course id", "completiondate": "Date - Required - Date YYYY-MM-DD format", "score": "Number - Optional - Accepted value 0 to 100 - Default 100", "trainingprovider": "String - OPTIONAL - Training provider for the course", "expirydate": "Date - Optional - Date YYYY-MM-DD format - Only applicable if 'Expiry Override' is enabled for the course", "archiveOldRecords" : "Number - Optional - Accepted value 1 - Default ''" } ] ``` Request: ```bash curl -X POST "https://www.bissafety.app/rest/v.01/training" \ -H "Authorization: Bearer YOUR_BEARER_TOKEN" \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "records=[{'userid': '123456','courseid': 'COURSEID','completiondate': '2021-09-25','score': '100','expiryDate': '2030-12-31'}]" ``` Response: ```json { "records": [{ "message": "", "status": "success", "score": "86", "courseid": "TTTTEEDDDTT", "userid": "123456", "completiondate": "2021-11-08" }, { "message": "Duplicate completion record", "status": "error", "score": "86", "trainingprovider": "Test", "courseid": "COURSEID", "userid": "121212", "completiondate": "2021-11-08" }] } ``` ### GET /training/contentpoolcourses - Courses in Course Pool Docs: https://www.bissafety.app/api-docs#contentpool-courses Endpoint: `GET /training/contentpoolcourses` This API endpoint gets a list of all courses in your course pool. Parameters: - `modified` (date, query): All online courses that were modified after the date(yyyy-mm-dd format) will be returned. Request: ```bash curl -X GET "https://www.bissafety.app/rest/v.01/training/contentpoolcourses" \ -H "Authorization: Bearer YOUR_BEARER_TOKEN" ``` Response: ```json { "courses": [ { "ceu": 0.3, "image": "", "description": "Description rich text content", "video": "", "courseid": "COURSE_ID_2", "internalcourseid": "INTERNAL_COURSE_ID", "contentowner": "BIS Safety Software", "type": "Internal", "priceDetails": { "membership": [ { "price": 142.5, "id": "ID", "name": "Elite" } ], "default": 150.00 }, "name": "Sample Course Name 2" } ] } ``` ### POST /training/createcoursecode - Create Course Code Docs: https://www.bissafety.app/api-docs#create-course-code Endpoint: `POST /training/createcoursecode` This API endpoint creates a course code for the passed course ID and responds with the course code. Parameters: - `courseid` (string, form, required): The Course ID you get from /contentpoolcourses needs to be passed here. - `quantity` (numeric, form, required): Number of seats to be added to the course code. - `location` (string, form, required): The location name where users will be added to when they register using the course code. - `expirydate` (date, form, required): Expiry date for the course code in YYYY-MM-DD date format. - `notes` (string, form, required): Notes about the code created. - `upgrade` (numeric, form, default `0`): Add Virtual Proctoring to the course code. By default, the upgrade is zero "0". Accepted values: **0** / **1** Request: ```bash curl -X POST "https://www.bissafety.app/rest/v.01/training/createcoursecode" \ -H "Authorization: Bearer YOUR_BEARER_TOKEN" \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "courseid=COURSEID" \ -d "quantity=QUANTITY" \ -d "location=LOCATION" \ -d "expirydate=EXPIRYDATE" \ -d "notes=NOTES" \ -d "upgrade=UPGRADE" ``` Response: ```json { "status": "success", "coursecode": "COURSECODE" } ``` ### GET /training/courses - Training Courses Docs: https://www.bissafety.app/api-docs#training-courses Endpoint: `GET /training/courses` This API endpoint gets all the training courses available in the training record management module, including classroom courses. Training courses may or may not be linked directly to online courses. The **priceDetails** , **courselink** , **policy** , **requirements** and **duration** fields are returned only when you filter with `coursetype=classroom`. Parameters: - `includesubcompany` (numeric, query): This parameter is used for the companies that have sub companies. You can include users for all sub companies. By default, sub companies are not included "0". Accepted values: **0** / **1** - `coursetype` (string, query, default `all`): Filters training courses. **all** (default) returns the full catalog with base fields. **classroom** returns only classroom calendar courses and adds `priceDetails`, `courselink`, `policy`, and `requirements`. - `modified` (date, query): All courses that was modified after the date(yyyy-mm-dd format) will be returned. Request: ```bash curl -X GET "https://www.bissafety.app/rest/v.01/training/courses" \ -H "Authorization: Bearer YOUR_BEARER_TOKEN" ``` Response: ```json { "courses": [{ "trainingprovider": "TEST PROVIDER", "courseid": "", "expiry": 0, "specificexpiryyear": "", "specificexpirymonth": "", "contentowner": "TEST OWNER", "specificexpirydate": "", "name": "TEST NAME", "subcompanyname": "In-House BIS", "status": "Inactive", "internalcourseid": 10002961, "floatingexpiryyear": "", "expirytype": "", "hourspercourse": "2", "priceDetails": { "default": 150.00, "membership": [ { "id": "1234567890", "name": "Member Tier", "price": 120.00 } ] }, "courselink": "https://www.example.com/v1/index.cfm?action=classroom.coursedetails&company={companyid}&course={courseid}", "policy": "Cancellation policy text.", "requirements": { "participant": "Participant requirement details.", "instructor": "" }, "duration": { "days": 1, "schedule": [ { "end": "12:00 PM", "start": "08:30 AM" } ] } }] } ``` ## Forms Docs: https://www.bissafety.app/api-docs#forms There are two API endpoints that can be used to get form data and completed forms. ### GET /form/response - Get Form Data Docs: https://www.bissafety.app/api-docs#forms-response Endpoint: `GET /form/response` This API endpoint returns data entered by users into specific fields for a particular form. The data also includes form completion records. Parameters: - `formid` (string, query, required, default `-1`): Data is fetched from the form with this form ID. - `fields` (string, query, default `0`): The list of fields (by field ID) in each form to include in the data returned. Field IDs are assigned in the Forms Builder, and multiple field IDs are separated by commas (e.g. TF_10,DD_11,CH_12, etc.). - `filter` (string, query, default `0`): A JSON object structure (field and and value combination) to filter results for certain user entries (e.g. {"DD_11":"VALUE1", "CH_12":"VALUE2"}). - `includeinprogress` (numeric, query, default `0`): By default, data is only returned for completed forms "0". If specified as "1", data for in progress forms is also included with data from completed forms. Accepted values: **0** / **1** - `fromdate` (date, query, default `0`): All data in the form entered by users on or after the provided date in the date format (YYYY-MM-DD). If the fromdate and todate parameters are blank, then the form data entered in the previous day from the time this API endpoint is called will be returned. - `todate` (date, query, default `0`): All data in the form entered by users on or before the provided date in the date format (YYYY-MM-DD). If the fromdate and todate parameters are blank, then the form data entered in the previous day from the time this API endpoint is called will be returned. - `offset` (numeric, query, default `1`): Offset the results by a certain value. By default, the offset is zero "0". - `recordsPerPage` (numeric, query, default `100`): Limit the form data returned by the number of different users entering data up to a maximum of 1000. - `modified` (date, query, default `0`): Filters form completions that were completed or updated after a certain date time in ISO date format (YYYY-MM-DDTHH:MM:SSZ). - `completionid` (string, query, default `0`): Use this parameter to select data for a specific completion (you can only provide one ID per request). The ID must be in the format "H_{id}" or "E_{id}" format. Sample `completionid`: ``` H_99999999 / E_99999999 ``` Request: ```bash curl -X GET "https://www.bissafety.app/rest/v.01/form/response?formid=FORM_ID" \ -H "Authorization: Bearer YOUR_BEARER_TOKEN" ``` Response: ```json { "recordsperpage": 100, "OFFSET": 1, "COUNT": 2, "formName": "Form Title", "formdata": [ { "FIELDS": [{ "fieldtype": "textfield", "label": "Test FIELD 1", "id": "TF_93", "VALUE": "aaaaaaaaaa" }, { "fieldtype": "textfield", "label": "TEXT FIELD 2", "id": "TF_95", "VALUE": 0 }], "STATUS": "Inprogress - Stage 1", "startdate": "2021-06-09", "lastname": "Asif", "userid": "testuser", "firstname": "Test", "email": "test@test.com", "completiondate": "", "completionid": "E_123456", "completiontype": "Asset", "eventID": 111222, "customformid": "TT-10001", "lastupdateddate": "2021-06-10T10:10:00Z" }, { "FIELDS": [{ "fieldtype": "attendance", "label": "Attendance FIELD", "id": "AL_7", "VALUE": [{ "NAME": "NAME (username)", "dateadded": "ISO DATE/TIME 2023-01-01T10:10:00Z", "signature": "URL https://www.bissafety.app/signature.png" },{ "NAME": "NAME (username)", "dateadded": "ISO DATE/TIME 2023-01-01T10:10:00Z", "signature": "" },{ "NAME": "NAME (username)", "dateadded": "ISO DATE/TIME 2023-01-01T10:10:00Z", "signature": "" }] }, { "fieldtype": "textfield", "label": "TEXT FIELD 2", "id": "TF_95", "VALUE": "TEXT FIELD VALUE" }, { "fieldtype": "taskassignment", "label": "Corrective Actions", "id": "TK_2", "VALUE": [{ "taskid": 145247, "taskname": "Hazards Test", "status": "completed" }] }], "STATUS": "completed", "startdate": "2021-06-15", "lastname": "Asif", "userid": "testuser", "firstname": "Test2", "email": "test2@test.com", "completiondate": "2021-06-15", "completionid": "H_985476", "completiontype": "User", "eventID": null, "customformid": "TT-10002", "lastupdateddate": "2021-06-15T10:10:00Z" } ] } ``` ### GET /form/completions - Get Completions Docs: https://www.bissafety.app/api-docs#forms-completions Endpoint: `GET /form/completions` This API endpoint gets completion records for forms. Parameters: - `formid` (string, query, default `-1`): The completion records are fetched for the form with this form ID. NOTE: Required if fromdate and todate parameters are not provided. - `filter` (string, query, default `0`): A JSON object structure (field and and value combination) to filter results for certain user entries (e.g. {"DD_11":"VALUE1", "CH_12":"VALUE2"}). - `fromdate` (date, query, default `0`): All completion records on or after the provided date in the date format (YYYY-MM-DD). If the fromdate and todate parameters are blank, then the completion records in the previous day from the time this API endpoint is called will be returned. The total number of days between the fromdate and todate must be less than 180 days. NOTE: Required if the Form ID is not provided. - `todate` (date, query, default `0`): All completion records on or before the provided date in the date format (YYYY-MM-DD). If the fromdate and todate parameters are blank, then the completion records in the previous day from the time this API endpoint is called will be returned. The total number of days between the fromdate and todate must be less than 180 days. NOTE: Required if the Form ID is not provided. - `offset` (numeric, query, default `1`): Offset the results by a certain value. By default, the offset is zero "0". - `recordsPerPage` (numeric, query, default `100`): Limit the number of form completion records up to a maximum of 1000. - `includeformpdf` (numeric, query, default `0`): If this is set to 1, then a temporary link(valid for 30 minutes) to the form PDF will be included in the API response. Accepted values: **0** /**1** - `completionid` (string, query): Use this parameter to select data for a specific completion (you can only provide one ID per request). The ID must be in the format "H_{id}" or "E_{id}" format. - `eventhistoryid` (numeric, query, default `0`): Pass the value of the Event ID you want to fetch form completions for. - `modifieddate` (date, query, default `0`): Returns only completion records whose modified timestamp falls within this UTC calendar day, in the date format (YYYY-MM-DD). This is an exact-day match, not a "changed since" cursor — a record modified on any other UTC day is excluded. Matching records include a `modifieddate` response key containing the modified timestamp of the record as an ISO 8601 datetime in UTC (empty string when no modified timestamp is stored). This parameter can be supplied on its own — when it is present, the requirement to supply either formid or (fromdate and todate) is waived. - `assetid` (string, query): Returns only completions linked to this asset. Use the asset ID returned by the `GET /asset` endpoint. For asset completions this matches the asset the form was completed on. For user completions it matches any asset selected in an asset field of that completion. If both `assetid` and `serialnumber` are supplied, `assetid` is used and `serialnumber` is ignored. An asset ID that cannot be read returns HTTP 400 (`invalid_request` / "Invalid asset ID"); an asset ID that does not belong to your company returns HTTP 404 (`not_found` / "Asset not found"). This parameter can be supplied on its own — when it is present, the requirement to supply formid, modifieddate or (fromdate and todate) is waived. - `serialnumber` (string, query): Alternative to `assetid`. Returns only completions linked to the active company asset with this exact serial number, and filters the same way `assetid` does. Ignored when `assetid` is also supplied. If no active asset matches, HTTP 404 is returned (`not_found` / "Asset not found"). If more than one active asset shares the serial number, HTTP 404 is returned with "Multiple assets found for serial number: {value}" — use `assetid` in that case. This parameter can be supplied on its own — when it resolves to an asset, the requirement to supply formid, modifieddate or (fromdate and todate) is waived. - `bisinternaluserid` (numeric, query, default `0`): Returns only completions belonging to this user. Use the value of the `BISInternalUserId` key returned in completion records. Unknown IDs are not rejected — they simply return no completions. This parameter cannot be used on its own: one of formid, modifieddate, an asset filter or (fromdate and todate) is still required. Sample `completionid`: ``` H_99999999 / E_99999999 ``` Sample `modifieddate`: ``` 2026-07-23 ``` Sample `serialnumber`: ``` SN-100234 ``` Sample `bisinternaluserid`: ```json 123456 ``` Request: ```bash curl -X GET "https://www.bissafety.app/rest/v.01/form/completions?formid=FORM_ID" \ -H "Authorization: Bearer YOUR_BEARER_TOKEN" ``` Response: ```json { "recordsperpage": 500, "offset": 0, "count": 2, "completions": [{ "startdate": "2020-10-28", "form": "Incident Report Form", "BISInternalUserId": 123456, "firstname": "Firstname", "email": "", "formid": 8980, "customformid": "TT-10001", "completiondate": "2020-10-28", "modifiedon": "2020-10-29T14:23:45Z", "userlocation": "Location 4", "assetname": "3 - Nick Testing ", "lastname": "Lastname", "userid": "0000000", "completiontype": "Asset", "completionid": "E_123456", "assetlocation": "", "stages": [ { "order": 1, "stage": "Stage 1", "submitted": "2021-02-25T10:10:00Z" }, { "order": 2, "stage": "Stage 2", "submitted": "2021-02-25T10:10:00Z" } ], "pdf": "{link_to_pdf}" }, { "startdate": "2021-05-06", "form": "Incident Report Form", "BISInternalUserId": 123456, "firstname": "Firstname", "email": "", "formid": 8980, "customformid": "TT-10002", "completiondate": "2021-05-06", "modifiedon": "2021-05-07T09:41:12Z", "userlocation": "Location 4", "assetname": "TestSr", "lastname": "Lastname", "userid": "0000000", "completiontype": "User", "completionid": "H_123456", "assetlocation": "Location 2", "stages": [ { "order": 1, "stage": "Stage 1", "submitted": "2023-12-05T10:10:00Z" } ], "pdf": "{link_to_pdf}" }] } ``` ### GET /form - Get Form Fields Docs: https://www.bissafety.app/api-docs#form-fields Endpoint: `GET /form` This API endpoints returns form fields for a given form ID. Parameters: - `formid` (string, query, required, default `-1`): The completion records are fetched for the form with this form ID. Request: ```bash curl -X GET "https://www.bissafety.app/rest/v.01/form?formid=FORM_ID" \ -H "Authorization: Bearer YOUR_BEARER_TOKEN" ``` Response: ```json { "formname": "Encryption form", "success":1, "formfields": { "encryptionKeyEnabled": true, "form": { "fields": [ { "learner": 0, "max": 0, "dbid": 972723, "layout": 1, "evaluator": 0, "pdffieldid": 0, "selectedMoveToLocationName": "", "errprMsg": "", "description": "Form/assessment description", "userMoveOption": 0, "id": "FT_1", "type": "formtitle", "subtype": "", "userReactivationOption": 0, "restrictSpace": 0, "size": 12, "required": 0, "selectedMoveToLocation": 0, "trackid": "264b09ca-6b9d-450e-b3a4-edb33c7e2aa4", "hidden": 0, "hideTitle": 0, "descriptionasTT": 0, "lockUserManagementOptions": 0, "haserror": 0, "hideSigningInstructions": 0, "min": 0, "userMoveToLocation": "", "actionrulekeys": [], "userDeactivationOption": 0, "catpoints": {}, "title": "Encryption form", "rules": {}, "inherited": 0, "readonly": 0 }, { "lengthunit": "characters", "learner": true, "max": 10, "texttype": "all", "dbid": 972726, "fieldInFT": false, "layout": 1, "evaluator": true, "pdffieldid": 0, "selectedMoveToLocationName": "", "errprMsg": "", "description": "Text field", "userMoveOption": 0, "id": "TF_4", "lengthlimitenabled": false, "type": "textfield", "subtype": "email", "userReactivationOption": 0, "restrictSpace": 0, "size": 12, "required": false, "selectedMoveToLocation": 0, "trackid": "b6daaf2e-a803-437f-8857-3b9de3b7a36f", "hidden": false, "hideTitle": false, "descriptionasTT": false, "lockUserManagementOptions": 0, "haserror": 0, "hideSigningInstructions": 0, "min": 3, "userMoveToLocation": "", "actionrulekeys": [], "userDeactivationOption": 0, "catpoints": {}, "title": "Title", "rules": {}, "inherited": 0, "readonly": false } ] }, "taskLinkedFields": [], "required": [], "actionrule": {}, "labelInFormTitle": false, "sinFields": [], "sequence": 6, "actionrulekeys": [], "validate": [ "TF_4" ], "companyId": 1, "menu": { "keys": [] }, "points": {}, "angular": true } } ``` ### GET /form/completion-pdf - Get Form PDF Link Docs: https://www.bissafety.app/api-docs#completion-pdf Endpoint: `GET /form/completion-pdf` This endpoint creates a secure, time-limited download link for PDF report of completed form submissions. The PDF can be generated using either the default layout or a specific custom layout. Parameters: - `completionid` (string, query, required): Completion identifier is available in the /form/completions or /form/response API response. - `layoutid` (string, query): Layout ID(if the form has custom layouts, then the use Get Form Fields API to get the layout ID) for custom PDF formatting. If not provided, uses default layout. Sample `completionid`: ``` H_99999999 / E_99999999 ``` Request: ```bash curl -X GET "https://www.bissafety.app/rest/v.01/form/completion-pdf?completionid=E_00000000" \ -H "Authorization: Bearer YOUR_BEARER_TOKEN" ``` Response: ```json {"linkExpiry":600,"status":1,"pdf":"{pdf link for the completion}"} ``` ## Dataset Docs: https://www.bissafety.app/api-docs#dataset Dataset APIs allow searching datasets, retrieving dataset records, and adding or updating dataset records by encrypted dataset and column identifiers. ### GET /dataset - List Datasets Docs: https://www.bissafety.app/api-docs#list-datasets Endpoint: `GET /dataset` Returns active company datasets with encrypted dataset and column identifiers that support API access. Parameters: - `searchText` (string, query): Optional search text to match dataset name or category name. Request: ```bash curl -X GET "https://www.bissafety.app/rest/v.01/dataset" \ -H "Authorization: Bearer YOUR_BEARER_TOKEN" ``` Response: ```json { "datasets": [ { "id": "_915778E00FF1C6EBE7F69EA599EFDCA", "name": "Employee Directory", "apiAccess": true, "category": { "value": "_ACF7631C827F1AB9C4CBF34C0D3223C", "label": "HR" }, "columns": [ { "id": "_5AFE7E5E459DEA7B5902F05694BF682F", "name": "employee_id", "unique": true }, { "id": "_6F993159D2A77884F1F0AD837EA6AE61", "name": "firstname", "unique": false }, { "id": "_7080EAC82B0CF785971A446766E38B934", "name": "city", "unique": false } ] } ] } ``` ### GET /dataset/records - Get Dataset Records Docs: https://www.bissafety.app/api-docs#get-dataset-records Endpoint: `GET /dataset/records` Returns dataset rows using encrypted dataset column IDs as keys. Requires dataset API access. Parameters: - `datasetId` (string, query, required): Encrypted dataset ID returned by the List Datasets endpoint. - `searchText` (string, query): Optional search text to filter records (if supported). Request: ```bash curl -X GET "https://www.bissafety.app/rest/v.01/dataset/records?datasetId=_915778E00FF1C6EBE7F69EA599EFDCA" \ -H "Authorization: Bearer YOUR_BEARER_TOKEN" ``` Response: ```json { "rows": [ { "_5AFE7E5E459DEA7B5902F05694BF682F": "1", "_6F993159D2A77884F1F0AD837EA6AE61": "Alice", "_7080EAC82B0CF785971A446766E38B934": "Toronto" }, { "_5AFE7E5E459DEA7B5902F05694BF682F": "2", "_6F993159D2A77884F1F0AD837EA6AE61": "Bob", "_7080EAC82B0CF785971A446766E38B934": "Vancouver" } ] } ``` ### POST /dataset/records - Add Dataset Records Docs: https://www.bissafety.app/api-docs#add-dataset-records Endpoint: `POST /dataset/records` Adds or updates records in an existing dataset. This enpoint requires a datasetId query parameter and a JSON body with a records array. Records are identified by a unique column value; existing records are updated, new ones are added. Returns a summary with counts of added, updated, and skipped records, plus per-record status details. Please note that the **dataset must have a Unique column** in order to use this endpoint. eg. ![Unique Field Example](https://www.bissafety.app/assets/images/apidoc/add-edit-dataset-records-uniquefield.png) Parameters: - `datasetId` (string, query, required): Dataset ID as returned by the List Datasets endpoint. - `content-body` (json, body, required): JSON array of records. Each key must be a dataset column ID as returned by List Datasets endpoint. Unique column must not have duplicate values. Sample `content-body`: ```json [ { "_5AFE7E5E459DEA7B5902F05694BF682F": "1", "_6F993159D2A77884F1F0AD837EA6AE61": "Alice", "_7080EAC82B0CF785971A446766E38B934": "Toronto" } ] ``` Request: ```bash curl -X POST "https://www.bissafety.app/rest/v.01/dataset/records?datasetId=_2ACF7631C827F1AB9C4CBF34C0D3223" \ -H "Authorization: Bearer YOUR_BEARER_TOKEN" \ -H "Content-Type: application/json" \ -d '[ { "_5AFE7E5E459DEA7B5902F05694BF682F": "1", "_6F993159D2A77884F1F0AD837EA6AE61": "Alice", "_7080EAC82B0CF785971A446766E38B934": "Toronto" }, { "_5AFE7E5E459DEA7B5902F05694BF682F": "2", "_6F993159D2A77884F1F0AD837EA6AE61": "Bob", "_7080EAC82B0CF785971A446766E38B934": "Vancouver" } ]' ``` Response: ```json { "success": 1, "summary": { "added": 2, "updated": 0, "skipped": 0 }, "results": [ { "status": "added", "message": "Record added." }, { "status": "added", "message": "Record added." } ] } ``` ### DELETE /dataset/records - Delete Dataset Records Docs: https://www.bissafety.app/api-docs#delete-dataset-records Endpoint: `DELETE /dataset/records` Deletes dataset rows whose unique-column value matches one of the supplied `uniqueValues`. Requires the dataset to have a unique column. Already-deleted or non-existent values return `notFound` in the per-value results; the call is idempotent and safe to retry. Parameters: - `datasetId` (string, query, required): Encrypted dataset ID returned by the List Datasets endpoint. - `content-body` (json, body, required): JSON object body with a `uniqueValues` array. Each entry is matched against the dataset unique column value; matched active rows are deleted. Non-matching values return `notFound` in the response. Sample `content-body`: ```json { "uniqueValues": ["1", "2"] } ``` Request: ```bash curl -X DELETE "https://www.bissafety.app/rest/v.01/dataset/records?datasetId=_2ACF7631C827F1AB9C4CBF34C0D3223" \ -H "Authorization: Bearer YOUR_BEARER_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "uniqueValues": ["1", "2"] }' ``` Response: ```json { "success": 1, "summary": { "deleted": 1, "notFound": 1, "skipped": 0 }, "results": [ { "uniqueValue": "1", "status": "deleted", "message": "Record deleted." }, { "uniqueValue": "2", "status": "notFound", "message": "No active record matched." } ] } ``` ## Location Docs: https://www.bissafety.app/api-docs#location The company hierarchy refers to the structure in which your company organizes their employees, clients, customers, contractors, etc., which can be by location, sub location, department, or whichever way best meets your company's needs. ### GET /location - List Locations Docs: https://www.bissafety.app/api-docs#location-list Endpoint: `GET /location` This API endpoint gets a list of all locations set up in company hierarchy in BIS Safety Software as shown in the Users tab and their corresponding information. Parameters: - `includesubcompany` (numeric, query): This parameter is used for the companies that have sub companies. You can include users for all sub companies. By default, sub companies are not included "0". Accepted values: **0** / **1** - `status` (string, query): A filter to get location with statuses: active, inactive. By default, the API returns active locations "A". If you want to get deactivated locations, use the parameter value "I". If you want to get both active and deactivated locations, leave the parameter value blank "". Accepted values: **A** / **I** / "" Request: ```bash curl -X GET "https://www.bissafety.app/rest/v.01/location" \ -H "Authorization: Bearer YOUR_BEARER_TOKEN" ``` Response: ```json { "locations": [{ "locationname": "Kicking Horse Canyon Construction", "locationcode": "KHCC", "status": "A", "parentlocation": "AIR EXTREME", "postalcode": "", "billto": "", "stateprov": "", "email": "", "subcompanyname": "In-House BIS", "city": "", "country": "", "maincontact": "", "address": "", "timezone": "", "website": "", "workphone": "", "custom field": "", "custom field 2": "" }] } ``` ### POST /location - Import Locations Docs: https://www.bissafety.app/api-docs#location-import Endpoint: `POST /location` You can add, update locations using this API endpoint. Parameters: - `locations` (json, form, required): This parameter is an array of location objects in JSON format. A maximum of 500 locations can be imported into BIS Safety Software at a time. Sample `locations`: ```json { "locationname": "String - Required", "locationcode": "String - Recommended", "parentlocationname": "String - Optional", "parentlocationcode": "String - Optional", "postalcode": "String - Optional", "billto": "String - Optional", "stateprov": "String - Optional", "email": "String - Optional", "subcompanyname": "In-House BIS", "city": "String - Optional", "country": "String - Optional", "maincontact": "String - Optional", "address": "String - Optional", "timezone": "String - Optional - Value should be in time offset of UTC for example MST is -07:00", "website": "String - Optional", "workphone": "String - Optional", "status": "String Optional - Accepted value A and I" } ``` Request: ```bash curl -X POST "https://www.bissafety.app/rest/v.01/location" \ -H "Authorization: Bearer YOUR_BEARER_TOKEN" \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "locations=[{'locationname': 'Location 1', 'locationcode': 'Unique Code', 'status': 'A'}]" ``` Response: ```json [ { "locationname": "Location 1", "message": "Updated.", "error": 0, "locationcode": "Unique Code" } ] ``` ### POST /location/status - Change Location Status Docs: https://www.bissafety.app/api-docs#location-status Endpoint: `POST /location/status` You can use this API endpoint will activate or deactivate a location. Parameters: - `locationname` (string, form): Name of the location. Required if locationcode is not passed. - `locationcode` (string, form): Code of the location. Required if locationname is not passed. - `action` (string, form, required): Whether to activate or deactivate a location. Accepted values: **activate** / **deactivate** Request: ```bash curl -X POST "https://www.bissafety.app/rest/v.01/location/status" \ -H "Authorization: Bearer YOUR_BEARER_TOKEN" \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "locationname=LOCATION_NAME" \ -d "locationcode=LOCATION_CODE" \ -d "action=ACTION" ``` Response: ```json { "status": "success", "message": "location was deactivated successfully" } ``` ## Training Topic Docs: https://www.bissafety.app/api-docs#training-topic Training topics are the requirements that user gets assigned by training matrix. ### GET /topic/details - Topic Details Docs: https://www.bissafety.app/api-docs#topic-details Endpoint: `GET /topic/details` This API endpoint will return all training topics and courses mapped to them. Parameters: - `topicid` (string, query): Comma separated list of topic ids. - `bisinternaltopicid` (string, query): One or more BIS topic numbers, separated by commas. This is the `bisinternaltopicid` returned by `/topic/list`. Use it for topics that have no `topicid`. Request: ```bash curl -X GET "https://www.bissafety.app/rest/v.01/topic/details?topicid=TopicID1,TopicID2" \ -H "Authorization: Bearer YOUR_BEARER_TOKEN" ``` Response: ```json { "topics": [{ "topicname": "Safety Driving", "certificateprogram": 0, "topicid": "SD-100", "bisinternaltopicid": 90095, "levels": [{ "fldlevel": 1, "levelname": 1, "itemsperlevel": 1, "hoursperlevel": "", "courses": [{ "courseid": 28506161, "coursename": "AED/CPR Awareness Course", "hourspercourse": 1.00, "autoassign": false }] }] }, { "topicname": "Certification Program", "certificateprogram": 1, "topicid": "", "bisinternaltopicid": 90211, "levels": [{ "fldlevel": 1, "levelname": "Level 1", "itemsperlevel": 1, "hoursperlevel": 1.00, "courses": [{ "courseid": 37749623, "coursename": "Test Course", "hourspercourse": 1.50, "autoassign": false }] }] }] } ``` ### GET /topic/assigned - Topic Assigned Docs: https://www.bissafety.app/api-docs#topic-assigned Endpoint: `GET /topic/assigned` This API endpoint will return all users and their assigned topics. Parameters: - `userid` (string, query): The User ID is a unique and consistent identifier for each user in your system that is also used as a common identifier for the same users in BIS Safety Software. This identifier, typically an employee ID or a system user ID, allows users' data to be correctly exchanged between your system and BIS Safety Software. - `bisinternaluserid` (numeric, query): System ID of a user in BIS. - `topicid` (string, query): The unique topic ID for the training topic. - `bisinternaltopicid` (string, query): One or more BIS topic numbers, separated by commas. This is the `bisinternaltopicid` returned by `/topic/list`. Use it for topics that have no `topicid`. Request: ```bash curl -X GET "https://www.bissafety.app/rest/v.01/topic/assigned" \ -H "Authorization: Bearer YOUR_BEARER_TOKEN" ``` Response: ```json { "records": [{ "topics": [ { "topictype": "R", "topicid": "CSE-101", "bisinternaltopicid": 90095, "topic": "Confined Space Entry" },{ "topictype": "O", "topicid": "", "bisinternaltopicid": 90211, "topic": "Working at Heights" } ], "employeeid": "1111", "lastname": "Doe", "firstname": "Jane", "bisinternaluserid": 123456 }] } ``` ### GET /topic/status - Topic Status Docs: https://www.bissafety.app/api-docs#topic-status Endpoint: `GET /topic/status` Returns the training topics each user is required to complete, with their completion status. The response is a list of users, each with a list of topics. Topics an administrator has removed from one user are not returned. The same rules the user sees on their Training Matrix are applied: topic exceptions, location and role exceptions, the department setting, and the orientation and reactivation windows. A topic assigned directly to a named user is always returned, because an instruction about one person is more specific than a rule about a role. `topictype` is `R` for required or `O` for optional. A user who holds the same topic as both gets two records, one of each, with the same completion status. `bisinternaltopicid` is the number BIS gives every topic and is always filled in; `topicid` is the ID your administrators type and can be empty. Only current requirements are returned, so this endpoint cannot tell you that a topic stopped being required. `/topic/status/delta` reports that as a change, and returns only what changed since your last run. **assigneddate** and **duedate** are returned only when you pass `includeduedate=1`, and are blank for certification programs. **bisinternaluserid** is returned only when you pass `bisinternaluserid` or `includeuserwithoutuserid=1`. Parameters: - `userid` (string, query): The User ID is a unique and consistent identifier for each user in your system that is also used as a common identifier for the same users in BIS Safety Software. This identifier, typically an employee ID or a system user ID, allows users' data to be correctly exchanged between your system and BIS Safety Software. - `bisinternaluserid` (numeric, query): System ID of a user in BIS. - `topicid` (string, query): The topic ID your administrators type on the topic. Comma separated for more than one. It narrows the response to the topics you name; it does not change which topics qualify, so a topic removed by a topic exception is not returned either way. - `offset` (numeric, query, default `0`): Offset the results by a certain value. By default, the offset is zero "0". - `recordsperpage` (numeric, query, default `500`): Limit the number of user and topic combinations returned up to a maximum of 500. - `includeuserwithoutuserid` (numeric, query, default `0`): Controls whether to include users without UserID set in the system. By Default, 0 = exclude users without UserIDs (default), 1 = include all users - `includeduedate` (numeric, query, default `0`): Controls whether to include topic assigned date and due date in response. This is only applicable for regular topics. Certification program type type does not support this functionality yet. By default the value is "0". - `bisinternaltopicid` (string, query): One or more BIS topic numbers, separated by commas. This is the `bisinternaltopicid` returned by `/topic/list`. Use it for topics that have no `topicid`. Request: ```bash curl -X GET "https://www.bissafety.app/rest/v.01/topic/status" \ -H "Authorization: Bearer YOUR_BEARER_TOKEN" ``` Response: ```json { "records": [{ "topics": [{ "status": "complete", "topictype": "R", "certificateprogram": 1, "topicid": "", "bisinternaltopicid": 90211, "topic": "Working at Heights", "completiondate": "YYYY-MM-DD", "expirydate": "YYYY-MM-DD", "assigneddate": "", "duedate": "" }, { "status": "incomplete", "topictype": "R", "certificateprogram": 0, "topicid": "CSE-101", "bisinternaltopicid": 90095, "topic": "Confined Space Entry", "completiondate": "YYYY-MM-DD", "expirydate": "YYYY-MM-DD", "assigneddate": "YYYY-MM-DD", "duedate": "YYYY-MM-DD" }], "employeeid": "1111", "bisinternaluserid": 123456, "lastname": "Doe", "firstname": "Jane" }] } ``` ### GET /topic/reset - Topic Reset Docs: https://www.bissafety.app/api-docs#topic-reset Endpoint: `GET /topic/reset` This API endpoint find all the completions that satisfies the topic for a user and archive those completions. Parameters: - `userid` (string, query, required): The User ID is a unique and consistent identifier for each user in your system that is also used as a common identifier for the same users in BIS Safety Software. This identifier, typically an employee ID or a system user ID, allows users' data to be correctly exchanged between your system and BIS Safety Software. - `topicid` (string, query): The topic ID your administrators type on the topic. Send either `topicid` or `bisinternaltopicid`. - `bisinternaltopicid` (numeric, query): The BIS topic number, the `bisinternaltopicid` returned by `/topic/list`. Send either `topicid` or `bisinternaltopicid`. When both are sent, `bisinternaltopicid` is used. Request: ```bash curl -X GET "https://www.bissafety.app/rest/v.01/topic/reset?userid=USER_ID&topicid=TOPIC_ID" \ -H "Authorization: Bearer YOUR_BEARER_TOKEN" ``` Response: ```json { "status": "success", "message": "Topic was reset successfully" } ``` ### GET /topic/list - Topic List Docs: https://www.bissafety.app/api-docs#topic-list Endpoint: `GET /topic/list` Returns every training topic in your company with its IDs, without the courses and levels that `/topic/details` returns. `bisinternaltopicid` is the number BIS gives every topic. It is always filled in and never repeats, so use it to refer to a topic in other calls. `topicid` is the ID your administrators type on the topic. It can be empty, and the same value can be typed on more than one topic. Topics are returned in `bisinternaltopicid` order. `count` is the total number of topics. When `offset` plus `recordsperpage` is less than `count`, call again with a larger `offset` to get the next page. Parameters: - `offset` (numeric, query, default `0`): Skip this many topics before the page starts. By default, the offset is zero "0". - `recordsperpage` (numeric, query, default `500`): How many topics one page returns. The default is 500 and the maximum is 10000. Request: ```bash curl -X GET "https://www.bissafety.app/rest/v.01/topic/list?offset=0&recordsperpage=500" \ -H "Authorization: Bearer YOUR_BEARER_TOKEN" ``` Response: ```json { "count": 2, "offset": 0, "recordsperpage": 500, "topics": [ { "bisinternaltopicid": 90095, "topicid": "CSE-101", "topicname": "Confined Space Entry", "certificateprogram": 0 }, { "bisinternaltopicid": 90211, "topicid": "", "topicname": "Working at Heights", "certificateprogram": 1 } ] } ``` ### GET /topic/status/delta - Topic Status Delta Docs: https://www.bissafety.app/api-docs#topic-status-delta Endpoint: `GET /topic/status/delta` Returns each user's training topics with the date each record last changed, so a scheduled job can ask for only what changed since its last run instead of reading every user and topic each time. Leave `lastupdateddate` out and you get every topic each user holds now or held before. Send it and you get only the records that changed at or after that time, including topics that were taken away. A topic never assigned to a user is never returned. `assignmentstatus` is `assigned` or `unassigned`. An `unassigned` record carries `unassigneddate`, has no `topictype`, and is your signal to drop the requirement; `status`, `completiondate` and `expirydate` are still filled in. One user and topic always produce one record, so a topic held as both required and optional is returned once, as `R`. `asof` is the time this answer covers. Store it and send it back as the next `lastupdateddate`, exactly as received. It is set fifteen minutes before the call so that records saved a little late are not skipped, which means a change made in the last fifteen minutes arrives on the next run. Pages are read with `cursor`, not `offset`. Send `nextcursor` back until it comes back empty; every page of one run carries the same `asof`. Match records on `bisinternaluserid` and `bisinternaltopicid`, and apply each record by replacing what you hold, because the same record can arrive more than once. Expiry, deleted topics and deactivated users are not sent as changes. Treat a record whose `expirydate` has passed as expired, and take a full copy from time to time to drop anything that no longer appears in it. Parameters: - `lastupdateddate` (string, query): Returns only the records that changed at or after this date and time, in ISO format (YYYY-MM-DDTHH:MM:SSZ). Times are UTC. Send back the `asof` value from your previous run. Leave it blank to get every record. - `cursor` (string, query): Pagination token. Leave it blank on the first call, then send back the `nextcursor` value from the previous response until it comes back empty. A blank value starts from the beginning. - `userid` (string, query): The User ID is a unique and consistent identifier for each user in your system that is also used as a common identifier for the same users in BIS Safety Software. To get multiple users, you can pass User ID as comma separated list. - `bisinternaluserid` (numeric, query): System ID of a user in BIS. Comma separated for more than one. - `topicid` (string, query): The topic ID your administrators type on the topic. Comma separated for more than one. It can be empty and the same value can be used by more than one topic, so identify topics by `bisinternaltopicid` in the response. - `bisinternaltopicid` (numeric, query): The number BIS gives every topic, returned as `bisinternaltopicid` and also available from `/topic/list`. Comma separated for more than one. Unlike `topicid` it is always filled in, so use it to ask about a particular topic. - `includeoptional` (numeric, query, default `1`): Set to 0 to leave out topics a user holds only as optional. A topic is required when any one of the user's assignments makes it required. Topics the user no longer holds are always returned. Accepted values: **1** / 0 - `includeuserwithoutuserid` (numeric, query, default `0`): Controls whether to include users without UserID set in the system. Ignored when the request filters by `bisinternaluserid`. Accepted values: **0** / 1 - `includecount` (numeric, query, default `0`): Set to 1 to include `count`, the total number of records in this run. It is worked out only on the first call and is ignored when `cursor` is supplied. Accepted values: **0** / 1 - `recordsperpage` (numeric, query, default `500`): Limit the number of user and topic records that are returned up to a maximum of 10000. Sample `lastupdateddate`: ``` 2026-07-30T00:00:00Z ``` Sample `cursor`: ``` 38893_90095_1785456251 ``` Request: ```bash curl -X GET "https://www.bissafety.app/rest/v.01/topic/status/delta?lastupdateddate=2026-07-30T00:00:00Z&recordsperpage=500&includecount=1" \ -H "Authorization: Bearer YOUR_BEARER_TOKEN" ``` Response: ```json { "mode": "delta", "recordsperpage": 500, "count": 1284, "nextcursor": "38893_90095_1785456251", "asof": "2026-07-31T09:24:11Z", "records": [ { "employeeid": "E10432", "bisinternaluserid": 38893, "firstname": "Jane", "lastname": "Doe", "topics": [ { "topic": "Confined Space Entry", "topicid": "CSE-101", "bisinternaltopicid": 90095, "status": "complete", "completiondate": "2026-03-14", "expirydate": "2027-03-14", "topictype": "R", "certificateprogram": 0, "assignmentstatus": "assigned", "unassigneddate": "", "modifiedon": "2026-07-29T18:04:11Z" }, { "topic": "Working at Heights", "topicid": "WAH-200", "bisinternaltopicid": 90211, "status": "incomplete", "completiondate": "", "expirydate": "", "certificateprogram": 0, "assignmentstatus": "unassigned", "unassigneddate": "2026-07-29", "modifiedon": "2026-07-29T18:04:11Z" } ] } ] } ``` ## Roles Docs: https://www.bissafety.app/api-docs#role Endpoint: `GET /role` This API endpoint gets company roles. Parameters: - `includesubcompany` (numeric, query): This parameter is used for the companies that have sub companies. You can include users for all sub companies. By default, sub companies are not included "0". Accepted values: **0** / **1** Request: ```bash curl -X GET "https://www.bissafety.app/rest/v.01/role" \ -H "Authorization: Bearer YOUR_BEARER_TOKEN" ``` Response: ```json { "roles": [{ "role": "Test a role", "rolecode": "0023", "company": "In-House BIS" }, { "role": "Company Sanctioned Driver", "rolecode": "", "company": "In-House BIS" }] } ``` ## Task Docs: https://www.bissafety.app/api-docs#task Users can be assigned tasks from the task module and from within Task Assignment field in digital forms. ### GET /task - Get Tasks Docs: https://www.bissafety.app/api-docs#get-task Endpoint: `GET /task` This endpoint can be used to fetch all tasks in the system. Parameters: - `taskstatus` (string, query, default `pending`): Returns all tasks with specified task status. If no task status is provided, then all pending tasks are returned. Accepted values: **Pending** /**Overdue** /**Completed** /**All** - `location` (string, query): Returns all tasks that are associated with the provided location. If no location is provided, then all tasks are returned. - `includearchived` (numeric, query, default `0`): If this is set to 1, then all tasks that were assigned by archived forms will also be included in the response. Accepted values: **0** /**1** - `fromdate` (date, query): All tasks that were added from the provided date in the date format (YYYY-MM-DD) are returned. If the fromdate and todate parameters are left blank, all tasks are returned. - `todate` (date, query): All tasks that were added until the provided date in the date format (YYYY-MM-DD) are returned. If the fromdate and todate parameters are left blank, all tasks are returned. - `taskid` (numeric, query): Returns the task with this task ID. When this parameter is provided, the taskstatus and includearchived parameters are ignored, so a completed task, or a task from an archived form, is still returned. Inactive tasks are never returned. An ID that is not a positive whole number returns the error "Invalid Task ID Provided". - `completionid` (string, query): Returns all tasks created by this form completion. Use the completionid returned by the Get Form Data and Get Completions endpoints, in the format "H_{id}" or "E_{id}" (you can only provide one ID per request). When this parameter is provided, the taskstatus and includearchived parameters are ignored, so completed tasks are included. Inactive tasks, and follow-up forms assigned from a task field, are not returned. An ID in any other format returns the error "Invalid Completion ID Provided". Sample `taskid`: ```json 145247 ``` Sample `completionid`: ``` H_99999999 / E_99999999 ``` Request: ```bash curl -X GET "https://www.bissafety.app/rest/v.01/task" \ -H "Authorization: Bearer YOUR_BEARER_TOKEN" ``` Response: ```json { "tasks": [ { "location": "Corporate Head Office (BIS)", "dateadded": "2023-10-25", "datecompleted": "2023-10-25", "eventId": "", "formID": 30411, "formTitle": "*Hazard Assessment", "taskname": "Hazards Test", "taskProof": "/assets/TaskVisualProof/1/Signature_136594CE-B0DC-8CAB-10E1539C32F667asd.jpg", "taskid": 145247, "equipmentID": "", "completionid": "H_985476", "status": "completed", "TaskComment": "Task completed", "description": "Please test the all hazards", "archive": 0, "requireVisualProof": 0, "taskLocation": "", "userid": "B0001285", "username": "Austin Gonzales (AGonzales86 - Corporate Head Office (BIS))", "addedbyusername": "Austin Gonzales", "duedate": "2023-10-25", "overdue": "" }, { "location": "Corporate Head Office (BIS)", "dateadded": "2019-12-03", "datecompleted": "2021-09-24", "eventId": "", "formID": 3641, "formTitle": "Task Lock Date Test", "taskname": "Complete Inspection", "taskProof": "", "taskid": 4487, "equipmentID": 898, "completionid": "E_123456", "status": "completed", "TaskComment": "This task has been closed.", "description": "", "archive": 0, "requireVisualProof": 0, "taskLocation": "", "userid": "1111", "username": "Aswathy S (as1 - Corporate Head Office (BIS))", "addedbyusername": "Aswathy S", "duedate": "2019-12-03", "overdue": "" } ], "totalTasks": 2 } ``` ## E-Commerce Docs: https://www.bissafety.app/api-docs#ecommerce-header API endpoints related to company's E-commerce store. ### GET /products - Get Available Products Docs: https://www.bissafety.app/api-docs#ecommerce Endpoint: `GET /products` This API gets the courses and products in the company's e-commerce store. **launchcode** is not returned by default. Contact your account manager to have it included. Parameters: - `types` (string, query): The type of content in the e-Commerce store. The data returned from this API will show either online courses only "Online" or online courses, classroom courses, and physical products "All". Accepted values: **Online** / **All** Request: ```bash curl -X GET "https://www.bissafety.app/rest/v.01/products" \ -H "Authorization: Bearer YOUR_BEARER_TOKEN" ``` Response: ```json { "itemCount": 1422, "redirectUrl": "", "items": [{ "price": 79.95, "video": "Video_Link", "ratingcount": 22, "portrait": "Image_Link", "expanded": "", "productID": "12-steps-to-establishing-leadership-presence-fuel-navigate-drive", "name": "12 Steps to Establishing Leadership Presence", "short": "SHORT DESCRIPTION", "thumnail": "Image_Link", "rating": 4.4, "large": "Image_Link", "altname": "", "type": 9, "long": "LONG DESCRIPTION", "launchcode": "LAUNCH CODE for SSO" }, { "price": 249.95, "video": "Video_Link", "ratingcount": "", "portrait": "Image_Link", "expanded": "", "productID": "5-minute-fundamentals-dvd", "name": "5 Minute Fundamentals DVD", "short": "SHORT DESCRIPTION", "thumnail": "Image_Link", "rating": "", "large": "Image_Link", "altname": "", "type": 8, "long": "LONG DESCRIPTION", "launchcode": "LAUNCH CODE for SSO" }] } ``` ## Asset Docs: https://www.bissafety.app/api-docs#asset Asset API endpoints let API clients read category metadata, list/create/update assets, and manage asset documents and required documents. All calls require a valid Bearer token. ### GET /asset/categories - Get Asset Categories Docs: https://www.bissafety.app/api-docs#get-asset-categories Endpoint: `GET /asset/categories` Returns asset categories configured for the authenticated company, including type/status options, enabled fields, custom fields, and required-document settings used by the Asset UI and integrations. Request: ```bash curl -X GET "https://www.bissafety.app/rest/v.01/asset/categories" \ -H "Authorization: Bearer YOUR_BEARER_TOKEN" ``` Response: ```json { "assetTypes": [ { "categoryID": "CATEGORY_ID", "name": "Location", "displayName": "Location", "isLocation": true, "isDisabled": false, "types": [ { "id": "TYPE_ID", "name": "Forklift", "colorCode": "#f1f1f1", "active": true }, { "id": "TYPE_ID", "name": "Crane", "colorCode": "#00ff90", "active": true } ], "statuses": [ { "id": "STATUS_ID", "name": "In Service", "colorCode": "#d31717", "active": true }, { "id": "STATUS_ID", "name": "Out of Service", "colorCode": "#b34242", "active": true } ], "enabledFields": [ { "id": "FIELD_ID", "field": "type", "name": "Type", "active": true }, { "id": "FIELD_ID", "field": "serialNumber", "name": "Serial Number", "active": true } ], "customFields": [ { "id": "FIELD_ID", "name": "test", "type": "textfield", "active": true, "defaultChoice": 0 } ], "requiredDocumentSettings": { "enabled": true, "complianceTarget": 99.99, "documentTypes": [ { "documentTypeId": "REQUIRED_DOCUMENT_TYPE_ID", "name": "MR TEST", "hasExpiry": false, "needApproval": false }, { "documentTypeId": "REQUIRED_DOCUMENT_TYPE_ID", "name": "MR test10", "hasExpiry": true, "needApproval": true } ] } }, { "categoryID": "CATEGORY_ID", "name": "Assets", "displayName": "Equipment", "isLocation": false, "isDisabled": false, "types": [], "statuses": [], "enabledFields": [], "customFields": [], "requiredDocumentSettings": { "enabled": false, "complianceTarget": 0, "documentTypes": [] } } ] } ``` ### GET /asset - List Assets Docs: https://www.bissafety.app/api-docs#list-assets Endpoint: `GET /asset` Returns paginated assets for the authenticated company with optional filters (asset/category/status/type/location/serial/search), active-state filtering, and sorting. Parameters: - `assetid` (string, query): Asset id. When provided, response is limited to that asset. - `serialnumber` (string, query): Exact serial number filter (active company assets only). - `categoryid` (string, query): Asset category id filter. - `statusid` (string, query): Status id filter. Empty/0 means no status filtering. - `typeid` (string, query): Type id filter. Empty/0 means no type filtering. - `locationid` (string, query): Location id filter. Empty/0 means no location filtering. - `search` (string, query): Case-insensitive text search across name, serial number, manufacturer, model, description, and current site. - `active` (string, query, default `A`): Asset state filter: `A` (active, default) or `I` (inactive). Any value other than `I` is treated as active. - `offset` (numeric, query, default `0`): Pagination offset (0-based). - `recordsperpage` (numeric, query, default `50`): Page size. Values are clamped to 1..500 on the server. Default is 50. - `orderby` (string, query): Sort column key: `name`, `location`, `serialNumber`, or `description`. Any other value defaults to `name`. - `sortdirection` (string, query): Sort direction: `ASC` or `DESC`. Any non-`DESC` value defaults to `ASC`. Sample `active`: ``` A ``` Sample `offset`: ```json 0 ``` Sample `recordsperpage`: ```json 50 ``` Sample `sortdirection`: ``` ASC ``` Request: ```bash curl -X GET "https://www.bissafety.app/rest/v.01/asset?categoryid=CATEGORY_ID&search=&active=A&offset=0&recordsperpage=50" \ -H "Authorization: Bearer YOUR_BEARER_TOKEN" ``` Response: ```json { "assets": [ { "active": true, "assetId": "ASSET_ID", "categoryId": "CATEGORY_ID", "currentSite": "", "description": "", "hours": "5", "locationId": "LOCATION_ID", "locationName": "corporate Head office (BIS)", "manufacturer": "", "mileage": "10", "model": "", "name": "12544 test asset", "serialNumber": "", "statusId": null, "statusName": "", "typeId": null, "typeName": "" } ], "offset": 0, "recordsPerPage": 50, "totalCount": 8 } ``` ### POST /asset - Save Asset Docs: https://www.bissafety.app/api-docs#save-asset Endpoint: `POST /asset` Creates or updates an asset using JSON body data. Update flow uses `assetid` or `serialnumber`; create flow uses `categoryid`. Returns `assetId` on create or `success=true` on update. Returns 400 for invalid payload/inputs and 404 when serialnumber lookup does not resolve to a single active asset. When you pass only `categoryid`, a new asset is created and the response is `{"assetId": "ASSET_ID"}`. When you pass `assetid` or `serialnumber`, that asset is updated and the response is `{"success": true}`. Parameters: - `assetid` (string, query): Asset ID of the asset to update (from GET /asset endpoint). If present and valid, API updates that asset. - `serialnumber` (string, query): Serial number lookup for update flow. Must resolve to exactly one active asset in the company. - `categoryid` (string, query): Category id for create flow. - `content-body` (json, body, required): Required JSON object body. For create, `name` is required by service validation. Common fields: `name`, `serialNumber`, `description`, `locationId`, `statusId`, `typeId`, `manufacturer`, `model`, `currentSite`, `hours`, `mileage`. **Custom fields:** category-specific custom field values are supplied in an optional `customFields` object within this same body. Each **key** is the encrypted custom field `id` returned by `GET /asset/categories` (the matching category's `customFields[].id`). The **value** format depends on that field's `type`: * `textfield` – a plain text string. * `datefield` – a date string; stored as `YYYY-MM-DD`. Values that are not valid dates are ignored. * `multiplechoice` – the encrypted `optionId` of the selected option, taken from that field's `options[].optionId` in `GET /asset/categories`. * `multiselect` – an array of the selected options' `optionText` values (a single text string is also accepted). Call `GET /asset/categories` to discover a category's custom fields, their `type`, and the available option ids/text. Options that cannot be matched are skipped and reported back in the response `message` array. Sample `content-body`: ```json { "name": "Test Asset", "serialNumber": "SN-0011", "description": "Description for Test Asset", "locationId": "LOCATION_ID", "customFields": { "TEXT_CUSTOM_FIELD_ID": "Sample text value", "DATE_CUSTOM_FIELD_ID": "2026-12-31", "MULTIPLE_CHOICE_CUSTOM_FIELD_ID": "OPTION_ID", "MULTISELECT_CUSTOM_FIELD_ID": ["OPTION_A_ID", "OPTION_B_ID"] } } ``` Request: ```bash curl -X POST "https://www.bissafety.app/rest/v.01/asset?categoryid=CATEGORY_ID" \ -H "Authorization: Bearer YOUR_BEARER_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "Test Asset", "locationId": "LOCATION_ID", "serialNumber": "SN-0011", "description": "Description for Test Asset", "customFields": { "TEXT_CUSTOM_FIELD_ID": "Sample text value", "DATE_CUSTOM_FIELD_ID": "2026-12-31", "MULTIPLE_CHOICE_CUSTOM_FIELD_ID": "OPTION_ID", "MULTISELECT_CUSTOM_FIELD_ID": ["OPTION_A_ID", "OPTION_B_ID"] } }' ``` Response: ```json { "assetId": "ASSET_ID" } ``` ### GET /asset/requiredDocuments - Get Asset Required Documents Docs: https://www.bissafety.app/api-docs#get-asset-required-documents Endpoint: `GET /asset/requiredDocuments` Returns required-document uploads for a resolved asset (`assetid` or `serialnumber`) with controls for archive and expired-document visibility. Includes approval status, expiry, download link, and computed document status. Parameters: - `assetid` (string, query): Asset ID of the asset whose required documents you want to retrieve. Either `assetid` or `serialnumber` is required. - `serialnumber` (string, query): Serial number of the asset whose required documents you want to retrieve. Either `assetid` or `serialnumber` is required. - `includearchived` (numeric, query): Archive toggle: `0` active-only (default), `1` include archived. - `includeexpireddocuments` (numeric, query): Expiry toggle: `0` exclude expired (default), `1` include expired. Sample `includearchived`: ```json 0 ``` Sample `includeexpireddocuments`: ```json 0 ``` Request: ```bash curl -X GET "https://www.bissafety.app/rest/v.01/asset/requiredDocuments?assetid=ASSET_ID&includearchived=1&includeexpireddocuments=1" \ -H "Authorization: Bearer YOUR_BEARER_TOKEN" ``` Response: ```json { "requiredDocuments": [ { "documentId": "REQUIRED_DOCUMENT_ID", "title": "License", "documentName": "Operator License", "uploadedBy": "API", "uploadDate": "2026-01-10 12:00:00", "approvalStatus": "Approved", "expiryDate": "2026-12-31", "docPath": "https://example.com/v1/index.cfm?action=learner.downloadFilePublic&type=_asset_required_document_token&id=REQUIRED_DOCUMENT_ID", "documentStatus": "active" }, { "documentId": "REQUIRED_DOCUMENT_ID", "title": "Inspection", "documentName": "Quarterly Inspection", "uploadedBy": "Jane Doe", "uploadDate": "2026-03-01 09:20:00", "approvalStatus": "Pending", "expiryDate": "", "docPath": "https://example.com/v1/index.cfm?action=learner.downloadFilePublic&type=_asset_required_document_token&id=REQUIRED_DOCUMENT_ID", "documentStatus": "active" } ] } ``` ### POST /asset/requiredDocument - Add Asset Required Document Docs: https://www.bissafety.app/api-docs#add-asset-required-document Endpoint: `POST /asset/requiredDocument` Uploads a required-document file for an asset using `documenttypeid`. Existing active Pending/Denied records of the same required-document type are archived before insert; new API upload is stored as Approved. Parameters: - `assetid` (string, form): Asset ID of the asset to which the required document will be uploaded. Either `assetid` or `serialnumber` is required. - `serialnumber` (string, form): Serial number of the asset to which the required document will be uploaded. Either `assetid` or `serialnumber` is required. - `documenttypeid` (string, form, required): Required-document type id. Mandatory for upload. - `documentname` (string, form): Optional display name for uploaded required document. - `expirydate` (string, form): Optional expiry date. If provided, use `YYYY-MM-DD`. - `file` (file, file, required): Required upload file. Allowed types: jpeg, jpg, png, pdf, xlsx, xls, docx, doc. Sample `documentname`: ``` Operator License ``` Sample `expirydate`: ``` 2026-12-31 ``` Request: ```bash curl -X POST "https://www.bissafety.app/rest/v.01/asset/requiredDocument" \ -H "Authorization: Bearer YOUR_BEARER_TOKEN" \ -F "assetid=ASSET_ID" \ -F "serialnumber=SN-123" \ -F "documenttypeid=REQUIRED_DOCUMENT_TYPE_ID" \ -F "documentname=Operator License" \ -F "expirydate=2026-12-31" \ -F "file=@/path/to/document.pdf" ``` Response: ```json { "documentId": "REQUIRED_DOCUMENT_ID", "message": "Required document Operator License added" } ``` ### DELETE /asset/requiredDocument - Delete Required Document Docs: https://www.bissafety.app/api-docs#delete-required-document Endpoint: `DELETE /asset/requiredDocument` Archives an active required-document record by `requiredDocumentId` and returns `success=true` with a status message. This endpoint uses HTTP DELETE and expects `requiredDocumentId` in the query string. Parameters: - `requiredDocumentId` (string, query, required): Required-document id to archive. Sent in the query string. Request: ```bash curl -X DELETE "https://www.bissafety.app/rest/v.01/asset/requiredDocument?requiredDocumentId=REQUIRED_DOCUMENT_ID" \ -H "Authorization: Bearer YOUR_BEARER_TOKEN" ``` Response: ```json { "success": true, "message": "Document Operator License archived." } ``` ### GET /asset/documents - Get Asset Documents Docs: https://www.bissafety.app/api-docs#get-asset-documents Endpoint: `GET /asset/documents` Returns uploaded asset documents for a resolved asset (`assetid` or `serialnumber`), with archive inclusion, search, and sorting. Returns 400 when asset reference is missing and 404 when the target asset cannot be resolved. Parameters: - `assetid` (string, query): Asset ID of the asset whose documents you want to retrieve. Either `assetid` or `serialnumber` is required. - `serialnumber` (string, query): Serial number of the asset whose documents you want to retrieve. Either `assetid` or `serialnumber` is required. - `includearchived` (numeric, query, default `0`): Archive toggle: `0` active-only (default), `1` include archived. - `search` (string, query): Free-text match against document name and uploader full name. - `sortcolumn` (string, query, default `docname`): Sort key: `docname` or `addeddate`. Any other value defaults to `docname`. - `sortdirection` (string, query, default `ASC`): Sort direction: `ASC` or `DESC`. Empty defaults to `ASC`; any non-`ASC` value is treated as `DESC`. Sample `includearchived`: ```json 0 ``` Sample `sortcolumn`: ``` docname ``` Sample `sortdirection`: ``` ASC ``` Request: ```bash curl -X GET "https://www.bissafety.app/rest/v.01/asset/documents?assetid=ASSET_ID&includearchived=0&sortcolumn=docname&sortdirection=ASC" \ -H "Authorization: Bearer YOUR_BEARER_TOKEN" ``` Response: ```json { "documents": [ { "documentId": "DOCUMENT_ID", "docName": "Inspection Form.pdf", "docType": "pdf", "docPath": "https://example.com/v1/index.cfm?action=learner.downloadFilePublic&type=_asset_document_token&id=DOCUMENT_ID", "addedDate": "2026-01-10 12:00:00", "expiryDate": "2026-12-31", "active": true, "uploadedBy": "API" }, { "documentId": "DOCUMENT_ID", "docName": "Service Log.xlsx", "docType": "xlsx", "docPath": "https://example.com/v1/index.cfm?action=learner.downloadFilePublic&type=_asset_document_token&id=DOCUMENT_ID", "addedDate": "2026-02-22 10:30:45", "expiryDate": "", "active": true, "uploadedBy": "John Smith" } ] } ``` ### POST /asset/documents - Add Asset Document Docs: https://www.bissafety.app/api-docs#add-asset-document Endpoint: `POST /asset/documents` Uploads a document file and links it to an asset (`assetid` or `serialnumber`). File is required and allowed file types are jpeg/jpg/png/pdf/xlsx/xls/docx/doc. Duplicate active names are auto-adjusted to a unique name. Parameters: - `assetid` (string, form): Asset ID of the asset to which the document will be uploaded. Either `assetid` or `serialnumber` is required. - `serialnumber` (string, form): Serial number of the asset to which the document will be uploaded. Either `assetid` or `serialnumber` is required. - `documentname` (string, form, required): Display name for saved document. Server appends uploaded extension and auto-deduplicates active names if needed. - `expirydate` (string, form): Optional expiry date. If provided, use `YYYY-MM-DD`. - `file` (file, file, required): Required upload file. Allowed types: jpeg, jpg, png, pdf, xlsx, xls, docx, doc. Sample `documentname`: ``` Test Document ``` Sample `expirydate`: ``` 2026-12-31 ``` Request: ```bash curl -X POST "https://www.bissafety.app/rest/v.01/asset/documents" \ -H "Authorization: Bearer YOUR_BEARER_TOKEN" \ -F "assetid=ASSET_ID" \ -F "serialnumber=SN-123" \ -F "documentname=Test Document" \ -F "expirydate=2026-12-31" \ -F "file=@/path/to/document.pdf" ``` Response: ```json { "added": 1, "message": "Document added: Test Document.pdf" } ``` ### POST /asset/documents/update - Update Asset Document Docs: https://www.bissafety.app/api-docs#update-asset-document Endpoint: `POST /asset/documents/update` Updates existing asset document metadata (name and/or expiry date). Returns `success=true` on success. Returns 400 if the encrypted document id is invalid or the document cannot be updated. Parameters: - `documentid` (string, form, required): Document id to modify. - `documentname` (string, form): Optional new document title. - `expirydate` (string, form): Optional new expiry date in `YYYY-MM-DD` format. Sample `documentname`: ``` Updated Title ``` Sample `expirydate`: ``` 2027-01-15 ``` Request: ```bash curl -X POST "https://www.bissafety.app/rest/v.01/asset/documents/update" \ -H "Authorization: Bearer YOUR_BEARER_TOKEN" \ -F "documentid=DOCUMENT_ID" \ -F "documentname=Updated Title" \ -F "expirydate=2027-01-15" ``` Response: ```json { "success": true } ``` ### DELETE /asset/documents - Delete Asset Document Docs: https://www.bissafety.app/api-docs#delete-asset-document Endpoint: `DELETE /asset/documents` Soft-archives an asset document by `documentid` and returns `success=true`. This endpoint uses HTTP DELETE and expects `documentid` in the query string. Parameters: - `documentid` (string, query, required): Document id to archive (soft delete). Sent in the query string. Request: ```bash curl -X DELETE "https://www.bissafety.app/rest/v.01/asset/documents?documentid=DOCUMENT_ID" \ -H "Authorization: Bearer YOUR_BEARER_TOKEN" ``` Response: ```json { "success": true } ``` ## Classroom Event Docs: https://www.bissafety.app/api-docs#event There are three API endpoints to get and update classroom events. ### GET /event - List Events Docs: https://www.bissafety.app/api-docs#list-events Endpoint: `GET /event` This API endpoint gets all classroom calendar events. Parameters: - `fromdate` (date, query): All events in the classroom calendar scheduled on or after the provided date in the date format (YYYY-MM-DD). If the fromdate and todate parameters are left blank, all classroom events are returned. - `todate` (date, query): All events in the classroom calendar scheduled on or before the provided date in the date format (YYYY-MM-DD). If the fromdate and todate parameters are left blank, all classroom events are returned. - `status` (string, query): A filter to active events. By default, the API returns all active/deactivated events. If you want only active events, the parameter value "A". If you want to get both active and deactivated events, leave the parameter value empty or exclude the parameter. Accepted values: **A** / "" - `courseid` (string, query): The course ID for the calendar event. - `modified` (date, query): All events in the classroom calendar that was modified after the date(yyyy-mm-dd format) will be returned. Request: ```bash curl -X GET "https://www.bissafety.app/rest/v.01/event" \ -H "Authorization: Bearer YOUR_BEARER_TOKEN" ``` Response: ```json { "events": [{ "location": "CITY", "starttime": "08:00AM", "startdate": "YYYY-MM-DD", "eventid": "EVENT_ID", "courseid": "COURSE_ID", "course": "COURSE_NAME", "courselink": "LINK_TO_THE_EVENT_REGISTER_PAGE", "priceDetails": { "default": 150.00, "membership": [ { "id": "1234567890", "name": "Member Tier", "price": 120.00 } ] }, "policy": "Cancellation policy text.", "internalcourseid": "COURSE_ID", "capacity": 20, "requirements": { "participant": "Participant requirement details.", "instructor": "" }, "duration": { "days": 1, "schedule": [ { "date": "2016-07-21", "end": "12:00 PM", "start": "08:30 AM" } ] } }] } ``` ### GET /event/participants - Get Event Participants Docs: https://www.bissafety.app/api-docs#event-participants Endpoint: `GET /event/participants` This API endpoint gets all classroom event participants. Parameters: - `fromdate` (date, query): All event participants in the classroom calendar scheduled on or after the provided date in the date format (YYYY-MM-DD). If the fromdate and todate parameters are left blank, all classroom event participants are returned. - `todate` (date, query): All event participants in the classroom calendar scheduled on or before the provided date in the date format (YYYY-MM-DD). If the fromdate and todate parameters are left blank, all events participants are returned. - `onlynotapproved` (numeric, query): All event participants that have not been approved yet. If notonlyapproved is left blank, then all participants are returned. Accepted values: **0** / **1** - `courseid` (string, query): The course ID set up for the online course and specific to each company. - `coursename` (string, query): The course ID for the calendar event. - `eventid` (numeric, query): System event ID where new participants will be created. - `includeallparticipants` (numeric, query): This parameter is used to include all participants including inactive participants in the response. Accepted values: **0** / **1** Request: ```bash curl -X GET "https://www.bissafety.app/rest/v.01/event/participants" \ -H "Authorization: Bearer YOUR_BEARER_TOKEN" ``` Response: ```json { "success": true, "participants": [ { "initials": "AD", "startdate": "2022-09-14", "firstname": "Aaron", "courseid": 37913732, "coursename": "First Aid", "eventid": 72783, "birthdate": "1999-05-18", "locationcode": 10, "enddate": "2022-10-2002", "locationname": "Classroom Registrants", "status": "Failed", "participantid": 621781, "lastname": "Duclos", "userid": "B0001232", "gender": "Female", "sin": "678355411", "participantlastupdated": "2022-09-21", "registrationstatus": "Active" }, { "initials": "AD", "startdate": "2022-09-14", "firstname": "Adam", "courseid": 37913732, "coursename": "First Aid", "eventid": 72783, "birthdate": "", "locationcode": 10487, "enddate": "2022-10-2002", "locationname": "Classroom Registrants", "status": "NotStarted", "participantid": 324205, "lastname": "Doe", "userid": "BIS0001645", "gender": "Male", "sin": "678355412", "participantlastupdated": "2022-09-21", "registrationstatus": "Inactive" } ] } ``` ### PATCH /event/participants - Patch Event Participants Docs: https://www.bissafety.app/api-docs#patch-participants Endpoint: `PATCH /event/participants` This API endpoint can be used to patch event participants. Parameters: - `content-body` (json, body, required): A JSON object structure (field and and value combination) to update the participants' statuses. * **participantid** - A unique id to identify participants for classroom calendar events. participantid is required in JSON. If it is not provided, the response will return error for this participant and then move to the next element in the array. * **status** - Status indicates if the participant passed or failed the course. It is also required. If it is not provided, the response will return error for this participant and then move to the next element in the array. The system only accepts the following values for status: * Pass * Fail * Absent * **expiry** *-* Expiry is the expiry date for the record created for the participant. If expiry is not provided, the system takes the course expiry as expiry date. * **approved**- Approved indicates whether the participant was approved or not. If it is not provided, the participant is automatically approved if the status was pass. Otherwise, the participant is not approved. Accepted values are (1/0) 1 = Approved\| 0 = Not approved. * **mark** - Mark indicates what marks participant recieved for the event. If it is not provided and the participant passed the course, the mark is automatically set to 100 for the participant. Otherwise, it is 0. Accepted values are between 0 and 100. Sample `content-body`: ```json [ { "participantid": "String - Required - Unique participantid to identify participant", "status": "String - Required - Accepted value pass/fail/absent", "expiry": "Date - Optional - Date YYYY-MM-DD format", "approved": "Numeric - Optional - Accepted value 0/1", "mark": "Numeric - Optional - Accepted value between 0 and 100" } ] ``` Request: ```bash curl -X PATCH "https://www.bissafety.app/rest/v.01/event/participants" \ -H "Authorization: Bearer YOUR_BEARER_TOKEN" \ -H "Content-Type: application/json" \ -d '[ { "participantid": 621781, "status": "pass", "expiry": "2024-06-27", "approved": 1, "mark": 80 }, { "participantid": 621782, "status": "fail" } ]' ``` Response: ```json { "success": 1, "participantData": [ { "success": 1, "id": 621781 }, { "success": 1, "id": 621782 } ] } ``` ### POST /event/participants - Add Event Participants Docs: https://www.bissafety.app/api-docs#post-participants Endpoint: `POST /event/participants` This API endpoint can be used to add new event participants. Parameters: - `eventid` (string, form, required): System event ID where new participants will be created. Event ID can encrypted or decrypted. - `allowmultireg` (numeric, form): Allow participants to be added to be registered for multiple events for the same course. Accepted values: **0** / **1** Request: ```bash curl -X POST "https://www.bissafety.app/rest/v.01/event/participants" \ -H "Authorization: Bearer YOUR_BEARER_TOKEN" \ -H "Content-Type: application/x-www-form-urlencoded" \ -d 'eventid=137142' \ -d 'participants=[ { "userid": 621781 }, { "userid": 621782 } ]' ``` Response: ```json { "success": 1, "eventid": "137142", "participants": [ { "success": 1, "userid": "BIS0001605" }, { "success": 0, "userid": "BIS0001367", "error": "event_full", "error_description": "Classroom event is full" } ] } ``` ## Webhooks Docs: https://www.bissafety.app/api-docs#webhooks Webhook functionality that allows external systems to receive real-time notifications about specific events within the BIS Safety Software platform. ### POST https://your-endpoint - Course Completion Event Hook Docs: https://www.bissafety.app/api-docs#ccpush Endpoint: `POST https://your-endpoint` In addition to APIs, BIS also uses **event hooks**, which are outgoing calls from BIS Safety Software that trigger processes in your system's software. The event hook will push course completions from BIS Safety Software to your system with a POST request. Contact your account manager to register for this event hook. To set up an event hook, you need to implement an API endpoint in your system that is external to BIS Safety Software and accepts our server's POST request whenever one or more courses are completed by users in your BIS Safety Software portal. BIS requires a long term bearer token from you, which is implemented in BIS Safety Software and used in an Authorization header so your system can verify our POST requests. You can get course completion pushes by selecting specific courses or all courses completed by your users in BIS Safety Software. The selected courses should have course codes set up and users should have user IDs set up in BIS Safety Software in order for the event hook to push course completions. The POST request sends the form fields listed below. Your API must handle multiple POST requests for the same course completion ID. If your system already saved the completion ID, then your system must update that completion ID with updated scores, results, and completiondates from any following requests as our system may send multiple calls for the same course completion. Parameters: - `completionid` (numeric, form, required): The course completion ID. BIS may send the same completion more than once; update the record you already saved. - `userid` (string, form, required): The user ID (employee ID) of the user who completed the course. - `bisinternaluserid` (numeric, form, required): The user's ID in BIS Safety Software. - `bisinternalcourseid` (numeric, form, required): The course's ID in BIS Safety Software. - `coursecode` (string, form, required): Your course code for the course. Empty when the course has no course code. - `score` (string, form, required): The final course mark, with two decimal places. - `result` (numeric, form, required): 1 = pass, 0 = fail. - `completiondate` (string, form, required): When the course was completed, as YYYY-MM-DD HH:MM:SS. - `expirydate` (string, form, required): When the completion expires. Empty when it does not expire. Request: ```bash curl -X POST "https://your-endpoint" \ -H "Authorization: Bearer PROVIDED_BEARER_TOKEN" \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "completionid=COMPLETION_ID" \ -d "userid=USERID" \ -d "bisinternaluserid=BIS_USER_ID" \ -d "bisinternalcourseid=BIS_COURSE_ID" \ -d "coursecode=COURSE_CODE" \ -d "score=SCORE" \ -d "result=1" \ -d "completiondate=YYYY-MM-DD HH:MM:SS" \ -d "expirydate=EXPIRY_DATE" ``` ## Single Sign-On (SSO) Docs: https://www.bissafety.app/api-docs#sso **SSO** is a user/session authentication service that allows a user to use one set of login credentials to access multiple applications. BIS Safety Software allows for SSO access from any web-based system that can authenticate the user via a username or email and the password. This may include a legacy Learning Management System, a payroll system, or a company intranet portal that requires users to log in. The SSO link can be embedded within any button the user clicks to access their company portal. The SSO link bypasses the BIS Safety Software login screen and takes users straight to their homepage. ###### SSO Functionality There are several features built into the SSO service: * **Creation of a new account**: New accounts are created for any new users as soon as they click the SSO link. * **Access to existing accounts**: If users already exist in the system, and they are confirmed by a unique identifier, the system redirects the users to their existing accounts. * **Adding courses**: The SSO service can automatically add courses to existing or new accounts by providing "Course ID" with SSO requests. * **Automatic user provisioning**: User accounts are automatically added, updated, and deactivated based on changes in your Azure active directory. ### SAML 2.0 SSO Docs: https://www.bissafety.app/api-docs#sso-saml We support **Security Assertion Markup Language** (**SAML** ) 2.0 single sign-on. Our system can act as an application service provider (**SP**) and use your organization's identity provider to authorize and allow user access to our system. If you are using Microsoft Azure, you can use the tutorial at to set up your SSO. **Client admins can download SP metadata file** from your Portal Settings page -\> Integrations -\> SSO Section. Use this file to complete setting up the Azure SSO App. After the Azure app is setup, upload the **Federation(Identity Provider) metadata XML file** to Portal Settings page -\> Integrations -\> SSO Section to complete integration. ### User Provisioning Docs: https://www.bissafety.app/api-docs#user-provisioning Our SSO allows for automatic user provisioning with Microsoft Entra ID (formerly known as Microsoft Azure AD). Our system will use your organization’s Entra ID to create, update, and deactivate user accounts as the roles of users change in your organization. You must have access to an Entra ID tenant and have the permissions to configure provisioning in your Entra ID. You can use this tutorial at to set up automatic user provisioning. Please contact us to get your credentials for authorization. ### POST /user/token - Custom SSO Docs: https://www.bissafety.app/api-docs#sso-custom Endpoint: `POST /user/token` BIS provides a custom SSO for companies who do not support SAML 2.0 SSO. Setting up a custom SSO requires a bit of coding to set up. You can follow the guidelines below to help you. 1. Follow the instructions in the Authentication section above to obtain a bearer token using the secret BIS Safety Software API credentials provided by BIS Account Managers. 2. The API accepts user parameters as JSON objects. 3. Upon successfully validating the user, the API will return a JSON Web Token (**JWT**) token that must be used within 30 seconds. 4. Use the JWT token to redirect the user to the URL: `https://www.bissafety.app/sso/redirect/?token={JWT_TOKEN}` **Note:** If you are using the system's CUSTOM URL feature, then please replace `www.bissafety.app` with your custom domain. Parameters: - `user` (json, form, required): This parameter is an array of user objects in JSON format. A maximum number of 200 users can be imported at a time. Sample `user`: ```json { "userid": "String - Required - Unique userid in third party system", "givenName": "String - Required", "middlename": "String - Optional", "surname": "String - Required", "location": "String - OPTIONAL - If location is not provided then new users will be added under default location", "parentlocation": "String - OPTIONAL - if location provided does not exists and new location is being created, the new location will be created under provided parent location", "role": "String - OPTIONAL", "emailAddress": "String - Recommended", "address": "String - Optional", "city": "String - Optional", "country": "String - Optional", "province": "String - Optional", "postalcode": "String - Optional", "manager": "String - Optional - Unique userid in third party system", "managerEmail": "String - manager's email", "language": "String - Optional - Default English", "startDate": "Date - Optional - YYYY-MM-DD Date format", "SubCompanyName": "String - Optional - Only needed when a company has sub companies and want user to login to sub company", "CourseCode": "String - Optional - Course to auto-add and launch on login. Accepts either your registered course code (see Create Course Code) OR the encrypted 'courseid' returned by GET /training/contentpoolcourses. Launch requires the user's company to have the course via its course pool or eCommerce catalog." } ``` Request: ```bash curl -X POST "https://www.bissafety.app/rest/v.01/user/token" \ -H "Authorization: Bearer YOUR_BEARER_TOKEN" \ -H "Content-Type: application/x-www-form-urlencoded" \ --data-urlencode 'user={"userid": "123456", "givenName": "Test", "surname": "User", "emailAddress": "test.user@example.com"}' ``` ## SFTP Import Docs: https://www.bissafety.app/api-docs#sftp ###### Automated Bulk User Upload In addition to the on-demand functions listed above, automated bulk updates can be set up to run at scheduled intervals to perform the following functions: * Create user accounts * Update user information * Deactivate user accounts To accomplish this, an automated process is set up to transfer data files containing account modification requests via a **Secure File Transfer Protocol** (**SFTP**). SFTP is a method of sending and receiving encrypted files to provide higher levels of security. Please fill out our [SFTP User Data Import Form](https://www.bissafety.app/assets/sftp-import/BIStrainer%20SFTP%20User%20Data%20Import%202022-12-27.pdf) to set up this automated method of file transfer for your company. ***File Type*** We recommend **Excel files** . Comma Separated Value (CSV) spreadsheet files, plain text (TXT) files, and Excel files are commonly used for bulk updates. Download a sample excel file [here](https://www.bissafety.app/v1/assets/User%20Import%20Sample%20File.xlsx). ***Update Type*** We highly recommend that user information is updated using the **delta file** instead of doing a complete update each time. The delta file contains only new user information or changed user information and allows for a "Modification" method. This method avoids concerns about losing user data during automated updates when clients manually add users. ***Frequency*** We recommend scheduling a nightly update for a specific time. More frequent updates can be scheduled, but we do not recommend more than four in any given day. ***Dataset*** The dataset for bulk automated user uploads follow the same protocols as those for the User API endpoint. Refer to the Users section above for details regarding locations, company roles, system user roles, sub companies, and custom fields. The dataset includes, but is not limited to, the following fields: * User ID (required\*) * Last Name (required\*) * First Name (required\*) * Middle Name (optional) * Address (optional) * City (optional) * Province (required\*) * Country (required\*) * Postal Code (optional) * SIN/SSN (not recommended) * Birthdate (not recommended) * Language (required\*) * Work Phone (optional) * Cellphone (recommended) * Home Phone (optional) * Location ID Code (optional) * Location Name (optional) * Parent Location ID Code (optional) * Adding/Removing System User Role (optional) * Adding/Removing Company Role (optional) * Email (optional) * Evaluator (optional) * Start Date (optional) * Termination Date (optional) * Employee Status (A-Active/I-Deactivated) (required\*) * Company (optional) * Other custom fields ###### User ID It’s very important that user accounts use the company’s internal employee ID when the User ID dataset is required. The User ID must be a unique identifier to help link the accounts. Using internal employee IDs allows data to flow more effectively across systems and causes fewer issues when connecting to other systems in the future. NOTE: In situations where an employee account is needed in the system before an internal employee ID is available, an employee account can be created without a User ID. Our system can search for orphan accounts that don’t have User IDs, cross verify the last name, first three letters of the first name, and one piece of account information (e.g. address, phone, email, etc.). If there is a match, the system adds the User ID to the existing orphaned user account, preventing duplicate or unlinked accounts. ###### Location ID Code The location ID code is a unique identifier that can be entered into each location under the Users tab. This allows companies to have a user-friendly name (e.g. Leduc Office) and a unique ID code from the system for each location. When setting up the Users tab, it’s important to enter these codes into each location so that the system can properly import users into the correct locations. During the automated bulk update process, if a location in the imported data doesn’t exist in the system, the new location will be added and shown on the update log, which is received automatically after each import. ###### Custom Roles If you are using the Training Matrix, it’s efficient to include the user’s company role during a user import so that the system can automatically map out all the user’s training requirements. ## BambooHR Integration Docs: https://www.bissafety.app/api-docs#bamboohr We support Single Sign-On (SSO) integration and automatic user provisioning through the BambooHR platform. Our system functions as a Service Provider (SP) and uses BambooHR to authenticate and authorize user access via OpenID Connect. OpenID Connect operates on protocols within the OAuth 2.0 framework to verify user identity, enabling seamless SSO capabilities. Once SSO is configured, users can bypass the BIS Safety Software login screen and access their homepage directly after logging into BambooHR. For more information on OpenID, please refer to their tutorial *[How OpenID Connect Works - OpenID Foundation](https://openid.net/developers/how-connect-works/)*. ## Open API Docs: https://www.bissafety.app/api-docs#open-api Calls to these endpoints require a set of **different** API Credentials, which can be provided by your BIS Account Manager. A sample API call shows how to use client_id and client_secret as request header to call this API end point. ### GET /training/verification - Training Verification Docs: https://www.bissafety.app/api-docs#training-verification Endpoint: `GET /training/verification` This API can be used to verify a training that is completed in BIS Safety Software by using the ID (Completion ID) and last name of the user. The status of training verification can have one of the following values: * valid * invalid - *did not find the matching training* * expired - *training expired* * unverified - *if the training was virtually proctored, then 'unverified' means the training was not verified* Parameters: - `id` (string, query, required): The ID of the certificate that needed to be verified. - `lastname` (string, query, required): Last name of the user who completed the training. Request: ```bash curl -X GET "https://www.bissafety.app/rest/v.01/training/verification?id=ID&lastname=LASTNAME" \ -H "client_id: CLIENT_ID" \ -H "client_secret: CLIENT_SECRET" ``` Response: ```json { "status": "valid", "coursename": "COURSE_NAME", "expirydate": "YYYY-MM-DD", "completiondate": "YYYY-MM-DD" } ``` ### GET /training/networkpartners - Network Partners Docs: https://www.bissafety.app/api-docs#network-parteners Endpoint: `GET /training/networkpartners` This API can be used to fetch public network partners from BIS Safety Software. Request: ```bash curl -X GET "https://www.bissafety.app/rest/v.01/training/networkpartners" \ -H "client_id: CLIENT_ID" \ -H "client_secret: CLIENT_SECRET" ``` Response: ```json { "status": "success", "networkparteners": [ "Network Partner 1", "Network Partner 2", "Network Partner 3", "Network Partner 4", "Network Partner 5" ] } ``` ## Rewards Docs: https://www.bissafety.app/api-docs#rewards Rewards APIs allow an external system to read a user's current reward point balance and set it to a new total. The Rewards module must be enabled for the company, and each endpoint must be granted to the API credential before it can be called. ### GET /reward/points - Get Reward Points Docs: https://www.bissafety.app/api-docs#get-reward-points Endpoint: `GET /reward/points` Returns each user's first name, last name, location, username, User ID, email and current reward point total. Filter by userid, bisinternaluserid, username or email, or call it with no filter to page through all users. When more records remain past the returned page, the response status is 202 instead of 200. Parameters: - `userid` (string, query): The User ID is a unique and consistent identifier for each user in your system. Accepts a comma separated list to return several users at once. - `bisinternaluserid` (numeric, query): System ID of a user in BIS. - `username` (string, query): The username of the user's BIS account. - `email` (string, query): The email address in the profile account of the user. - `status` (string, query, default `A`): A filter to get users with a certain status. By default, the API returns active users only "A". Use "I" to get inactive users. Accepted values: **A** / **I** - `includesubcompany` (numeric, query, default `0`): This parameter is used for the companies that have sub companies. You can include users for all sub companies by specifying "1". By default, sub companies are not included "0". A sub company that does not have the Rewards module enabled is skipped. Accepted values: **0** / **1** - `offset` (numeric, query, default `0`): Offset the results by a certain value. By default, the offset is zero "0". - `recordsperpage` (numeric, query, default `500`): Limit the number of users that are returned up to a maximum of 500. A larger value is trimmed to 500. Request: ```bash curl -X GET "https://www.bissafety.app/rest/v.01/reward/points?userid=USER_ID" \ -H "Authorization: Bearer YOUR_BEARER_TOKEN" ``` Response: ```json { "count": 1, "offset": 0, "recordsperpage": 500, "users": [ { "userid": "EMP1042", "bisinternaluserid": 123456, "firstname": "Alice", "lastname": "Smith", "username": "alice.smith", "email": "alice.smith@example.com", "location": "Calgary", "points": 300 } ] } ``` ### POST /reward/points - Update Reward Points Docs: https://www.bissafety.app/api-docs#update-reward-points Endpoint: `POST /reward/points` Sets a user's reward point total to the value passed. The value is the new total, not a delta: if the user has 300 points and 50 is passed, the new total is 50. The difference is recorded as one adjustment in the user's point history. Supply exactly one of userid, bisinternaluserid, username or email; the identifier must match exactly one user, and both active and inactive users are matched. The request body must be form encoded (application/x-www-form-urlencoded); a JSON body is not supported. If another update for the same user is already in progress, the response status is 409. Parameters: - `points` (numeric, form, required): The new point total for the user, a whole number of zero or more. The user's total is set to this value; it is not added to the current total. - `userid` (string, form): The User ID of the user in your system. Supply exactly one of userid, bisinternaluserid, username or email. - `bisinternaluserid` (numeric, form): System ID of a user in BIS. Supply exactly one of userid, bisinternaluserid, username or email. - `username` (string, form): The username of the user's BIS account. Supply exactly one of userid, bisinternaluserid, username or email. - `email` (string, form): The email address in the profile account of the user. Supply exactly one of userid, bisinternaluserid, username or email. - `reason` (string, form, default `Reward point total updated through API`): Text stored with the point adjustment and shown in the user's point history and the notification email. - `notify` (numeric, form, default `0`): Send the reward notification email to the user when the total changes by specifying "1". By default no email is sent "0". Accepted values: **0** / **1** - `includesubcompany` (numeric, form, default `0`): Search sub companies for the user as well by specifying "1". By default, only your own company is searched "0". A sub company that does not have the Rewards module enabled is skipped. Accepted values: **0** / **1** Request: ```bash curl -X POST "https://www.bissafety.app/rest/v.01/reward/points" \ -H "Authorization: Bearer YOUR_BEARER_TOKEN" \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "userid=USER_ID&points=50" ``` Response: ```json { "userid": "EMP1042", "bisinternaluserid": 123456, "previouspoints": 300, "points": 50, "adjustment": -250 } ```