Developers

Fiix CMMS API Developer's Guide


What is the Fiix CMMS API
Getting Started
Who this guide is for
Developer Sandbox
Getting API Keys
How to use the API
Using your API Keys in your App
Important Concepts
Code Examples


What is the Fiix CMMS API anyway?


The Fiix CMMS API offers a range of information and functionality that developers and Fiix CMMS product users can use to further extend their business and software. The Fiix CMMS API, as its name suggests, offers developers a way to access CMMS instance-specific data and functionality. In other words, if you want to leverage data from your Fiix CMMS instance in other tools or systems you use, this is the key to doing so.



Getting Started


Getting started with the Fiix CMMS API is fast and simple. Following the instructions in this guide, you should be up and running within minutes. The documentation for the API is subdivided into two main sections. This guide, is aimed to be an introduction to the principles and setup needed to work with the API. The other section is the API Reference, which is a comprehensive listing of the objects and functions all accessible via the API. Best of all, both sections are packed with code examples, tutorials and example data responses.



Who this guide is for


This guide is aimed at users who have a basic understanding of the Fiix CMMS product. If you are building against the Fiix API it is highly recommended that you have experience in the programming language of your choice, as well as a solid understanding of HTTP and JSON. Experience building against other APIs will help as well.



Developer Sandbox


To help you get started, we have a sandbox environment setup that allows you to work against a real Fiix CMMS instance. By creating a "free" instance in the Sandbox CMMS, it will be pre-configured to have a functional environment for you to test out your Fiix CMMS API calls. Please contact your Fiix representative to have a sandbox created for you. After your sandbox instance is created, you can use the instance as if it were a true Fiix CMMS instance, create Assets, WorkOrders, and even import data as necessary. To begin testing against the instance, see the Getting your API Access Keys section below.



Getting your API Access Keys


Either using your sandbox instance or actual CMMS instance, login as an administrator and obtain your API Access keys using the following steps (For OAuth2 applications, follow the OAuth2 steps below the following section):
  1. Visit your sandbox environment (If you are setting up your API keys in your production environment, please access your production CMMS instance).
  2. Login as an administrator and go to Settings > Connect Management > MA Connect API Application Settings page.
  3. Register a new API Application by pressing the New Api Application button.

  4. Enter the description of the app and leave the other fields empty.
  5. Click the OK button and then you should be presented with the Application Key (1), Access Key (2) and Secret Key (3). You'll be able to insert these values into your Fiix CMMS Client for accessing the API. Keep the secret in a safe place, as you will not be able to retrieve this value at a later time.


Once you have obtained your API keys, use it together with one of the API Client SDKs.

Important: You'll notice that the API Keys are associated with a particular account. This means any access via the API using that particular key will be through that account; whatever the account sees, or has permission to, will be as such. It is recommended to customize the permissions of this account, allowing your app to access the API with access rules that are fine-tuned to how you'd like your app to interact with the CMMS. (i.e. you can reassign this user to "technicians" user group instead of "administrators" to reduce the privileges of the account)


OAuth2 Setup
  1. Follow the same process as above for registering a new API Application, but be sure to provide a redirect URL that the OAuth login page will redirect to after the user authorizes your app via login.
  2. After being presented with your Application Key, Access Key and Secret, store this information in a secure spot as the secret will not be available to you at a later time.
  3. When building your OAuth2 application, be sure to point your application to
    <Your sandbox tenant URL>/api/auth?app-key=<Your Application key here>&redirect-url=<Your Redirect URL here>.

How to use the API


Using the Java or JavaScript SDK

Fiix provides API Software Development Kits for use in both Java and JavaScript formats. The Java client is available as a Maven artifact while the JavaScript client is published as an NPM module. To know more about the usage visit our API reference welcome section.

Using the API Without an SDK

The Fiix CMMS API can also be used without an SDK. This is explained in detail here.

Hooking up your API Access Keys


OK, so you've got your SDK set up and you've generated a set of API Access keys for yourself using the steps above. For your API projects, you'll need to identify your apps using those API Access keys. Be sure to point the URIs to your instances instead of the example ones listed here. In javascript, configuring your app is as follows:
var fiixCmmsClient = new FiixCmmsClient();
fiixCmmsClient.setBaseUri( '<Your sandbox tenant URL>/api/' );
fiixCmmsClient.setAppKey('Your Application Key');
fiixCmmsClient.setAuthToken('Your Access Key');
fiixCmmsClient.setPKey('Your API Secret');



Configuring in Java is just as easy:
BasicCredentials credentials = new BasicCredentials("APPLICATION KEY HERE","API KEY HERE", "API SECRET HERE");
fiixCmmsClient client = new FiixCmmsClient(credentials, "<Your sandbox tenant URL>/api/");

Concepts


CRUD calls

CRUD calls, or Create,Read, Update and Delete for short, are the basic calls you can do with Fiix CMMS API. These calls will be made to request Objects from the CMMS instance you are working against. For the objects available to the API, you are able to add new objects, update existing ones or even delete, as desired. For a list of all objects and methods available via the API, see the API Reference documentation.

RPC calls

The Fiix CMMS API also allows for Remote Procedure Calls from the client side. For example, a call to getDaysOfMonth with the required parameters will return a summary of upcoming events for the specified user. For a list of all RPC calls available via the API, see the API Reference documentation.

Responses from the API

When performing any kind of all to the API, the response from the CMMS will be in a particular format. Ensuring your application handles and parses these responses properly is key to the success of programming against the API. The API delivers responses in a consistent format (depending on your flavour of Fiix CMMS API client), and can contain object and objects for single and multi results of the API calls, respectively. In addition, errors from the server-side will be communicated via the error field of the response object. The errors returned will give you a code to quickly identify the type of error, as well as a brief explanation of what the error was or was caused by. In the case with Batch Requests (see below), responses are batched together, just as they are batched together when sending out the request(s).

Batching Requests

In addition to performing single API calls, the Fiix CMMS API allows for multiple requests to be executed together in a single request to the server. This can optimize the number of network requests needed, as well as client-side programming flows (could reduce complexity of request chaining). See the Batch Request Example section below to learn more.

Timeout

Socket timeout values can be applied to the client object to control API call timeout. Below is an example in JavaScript:

fiixCmmsClient.setTimeoutMs(2000);
            

Below is an example in Java, to specify value for timeout, the ConnectionParams interface needs to be implemented such that the timeout value(s) and the baseUri can be returned in respective implementation methods. An object of the implementation class is then used to create an instance of the FiixCmmsClient.

 //IMPLEMENTING ConnectionParams
import com.ma.cmms.api.client.ConnectionParams;

public class MyConnectionParams implements ConnectionParams
{
	@Override public String getBaseUri()
	{
		return "https://mysubdomain.macmms.com/api";
	}

	@Override public Integer getConnectionTimeout()
	{
		return 2000;
	}

	@Override public Integer getSoTimeout()
	{
		return 4000;
	}
}

//CREATING CLIENT
FiixCmmsClient fiixCmmsClient = new FiixCmmsClient(getCredentials(), new MyConnectionParams());
            


Proxy Server Information

Proxy server information can be specified for API requests via an implementation of the ProxyCredentials interface. The Basic or the NTLM Authentication scheme can also be used. To specify proxy information, the ProxyCredentials interface needs to be implemented such that it can provide proxyHost, proxyPort, authScheme (BASIC or NTLM), proxyUser, proxyPassword, srcHost and/or domain in respective implementation methods. An object of the implementation class is then used to create an instance of the FiixCmmsClient.

 //IMPLEMENTING ProxyCredentials

import com.ma.cmms.api.client.ProxyCredentials;

public class MyProxyCredentials implements ProxyCredentials
{
	String proxyHost = "localhost";

	int proxyPort = 8888;

	String proxyUser;

	String proxyPassword;

	@Override public String getProxyHost()
	{
		return proxyHost;
	}

	@Override public int getProxyPort()
	{
		return proxyPort;
	}

	@Override public AuthScheme getAuthScheme()
	{
		return null;
	}

	@Override public String getProxyUser()
	{
		return proxyUser;
	}

	@Override public String getProxyPassword()
	{
		return proxyPassword;
	}

	@Override public String getSrcHost()
	{
		return null;
	}

	@Override public String getDomain()
	{
		return null;
	}
}


//CREATING CLIENT
                String API_ENDPOINT = "https://mysubdomain.macmms.com/api";
FiixCmmsClient fiixCmmsClient = new FiixCmmsClient(getCredentials(),
				API_ENDPOINT, new MyProxyCredentials());

            

Examples


Java Examples

Find Java examples on  GitHub

JavaScript Examples

Pinging

We are going to start with a very simple example : we are going to ping the API. The API provides two kinds of methods : the RPC method and CRUD methods (change, add, remove, find). For doing a simple ping, we are going to use the RPC method and use the RPC object called "Ping". For more details about this RPC object, check out the reference documentation.
// RPC call to Ping
fiixCmmsClient.rpc({
  "name": "Ping",
});
Great, now the call is apparently being made, but we would like to make sure everything works fine. Let's add a callback :
// RPC call to Ping with simple callback
fiixCmmsClient.rpc({
  "name": "Ping",
  "callback": function(ret) {
    if (!ret.error) {
      output("You have successfully made your first call to the API.");
    } else output(ret.error);
  }
});

Listing assets

Fiix CMMS is all about managing assets, so one of the first things you might be interested in doing with the Fiix CMMS API is listing assets. To list assets, we are going to use the find method on the Asset object :
// find with callback
fiixCmmsClient.find({
  "className": "Asset",
  "fields": "id, strName, strDescription",
  "filters": [{"ql": "intAssetLocationID = ?", "parameters": [408608]}],
  "callback": function(ret) {
    if (!ret.error) {
      output(ret.objects);
    } else output(ret.error);
  }
});

Here we use a filter to only list the assets at a specific location. Notice how we had to specify what fields we wanted to be returned in the fields parameter. For the complete list of fields available, check out the reference documentation.

This example was useful for listing all our assets. Now let's say we are interested in just one asset. We can then use the method findById to retrieve it :

// findById with callback
fiixCmmsClient.findById({
  "className": "Asset",
  "id": 408677,
  "fields": "id, strName, strDescription, intAssetLocationID, intCategoryID",
  "callback": function(ret) {
    if (!ret.error) {
      output(ret.object);
    } else output(ret.error);
  }
});

Notice how the response object contains integer values for all the relations of the assets (for example intAssetLocationID or intCategoryID). Now, what if we want to build a complete object ready for being rendered ? We need to get the objects corresponding to these IDs. Let's do some more findById requests then.

// Build a complete object
var obj = {};

// Get the asset
var ret = fiixCmmsClient.findById({
  "className": "Asset",
  "id": 408677,
  "fields": "strName"
});

if (!ret.error) {
  obj.asset = ret.object;
}

// Get the associated location factory
var ret = fiixCmmsClient.findById({
  "className": "Asset",
  "id": 408608,
  "fields": "strName"
});

if (!ret.error) {
  obj.factory = ret.object;
}

// Get the associated category
var ret = fiixCmmsClient.findById({
  "className": "AssetCategory",
  "id": 26195,
  "fields": "strName"
});

if (!ret.error) {
  obj.category = ret.object;
}

output(obj);

Now we get a full object with everything we need inside. But notice how we had to make 3 different calls to the API and how we had to do everything in a synchronous way. There is a way to do all this in one request to the API, which we will explain in the next section.

Batching

The Fiix CMMS API provides the possibility of executing several requests as a single batch request. Using batch requests offers several advantages :

We are going to use the same example as in the section above, but we are going to do a batch request :

// Perform a batch request

// Prepare the request for getting the asset
var req1 = fiixCmmsClient.prepareFindById({
  "className": "Asset",
  "id": 408677,
  "fields": "strName"
});

// Prepare the request for getting the associated location factory
var req2 = fiixCmmsClient.prepareFindById({
  "className": "Asset",
  "id": 408608,
  "fields": "strName"
});

// Prepare the request for getting the associated category
var req3 = fiixCmmsClient.prepareFindById({
  "className": "AssetCategory",
  "id": 26195,
  "fields": "subdomain"
});

// Execute the batch
fiixCmmsClient.batch({
  "requests": [req1, req2, req3],
  "callback": function(ret) {
    if (!ret.error) {
      var obj = {
        "asset": ret.responses[0].object,
        "factory": ret.responses[1].object,
        "category": ret.responses[2].object
      };
      output(obj);
    } else output(ret.error);
  }
});

Display values

We have seen above how to retrieve associated objects, which is a good thing. But most of the time, we won't need the full associated object, we just want a display value for it. The API provides a mechanism for that : most of the objects have some extra fields prefixed with dv_ that provide display values for their associated objects. Here is an example :

// Get an asset with display values
fiixCmmsClient.findById({
  "className": "Asset",
  "id": 408677,
  "fields": "strName, dv_intAssetLocationID, dv_intCategoryID",
  "callback": function(ret) {
    if (!ret.error) {
      output(ret.object);
    } else output(ret.error);
  }
});

Notice how the values for the extra fields are enclosed in the extraFields property in the response object.

Adding assets

Now that we have seen how to retrieve content from the CMMS with find and findById, it's time to add our own content. Let's try to add an asset. For this we are going to use a method simply called add :

// Add request
fiixCmmsClient.add({
  "className" : "Asset",
  "fields": "id, strName, strSerialNumber",
  "object" : {
    "strCity" : "Toronto",
    "strNotes" : "Newly created asset via the API",
    "strProvince" : "ON",
    "strName" : "New asset",
    "strInventoryCode" : "AAAX1",
    "qtyStockCount" : 1,
    "strDescription" : "Our new asset",
    "strModel" : "The model of our new asset",
    "strBarcode" : "1111011101110111",
    "strMake" : "The make of our new asset",
    "strSerialNumber" : "1234567890",
    "intSiteID": 408456
  },
  "callback": function(ret) {
    if (!ret.error) {
      output(ret.object);
    } else output(ret.error);
  }
});

Notice how the request is returning the newly created object and how we have to specify the fields we want to be returned like we did for the find request.

Now let's say we need to add a whole bunch of assets. We can do this with a batch request, the same way we did for retrieving several objects.

// Add several assets with a batch request
// Asset  A
var addA = fiixCmmsClient.prepareAdd({
  "className" : "Asset",
  "fields": "id, strName, strInventoryCode",
  "object" : {
    "strName" : "New asset A",
    "strInventoryCode" : "AAAX1",
    "intSiteID": 408456
  }
});

// Asset  B
var addB = fiixCmmsClient.prepareAdd({
  "className" : "Asset",
  "fields": "id, strName, strInventoryCode",
  "object" : {
    "strName" : "New asset B",
    "strInventoryCode" : "BBBX1",
    "intSiteID": 408456
  }
});

// Asset  C
var addC = fiixCmmsClient.prepareAdd({
  "className" : "Asset",
  "fields": "id, strName, strInventoryCode",
  "object" : {
    "strName" : "New asset C",
    "strInventoryCode" : "CCCX1",
    "intSiteID": 408456
  }
});

// Execute the batch request
fiixCmmsClient.batch({
  "requests": [addA, addB, addC],
  "callback": function(ret) {
    if (!ret.error) {
      var obj = {
        "A": ret.responses[0].object,
        "B": ret.responses[1].object,
        "C": ret.responses[2].object
      };
      output(obj);
    } else output(ret.error);
  }
});

Updating an asset

Here is a simple example of how to update an existing object :

// Update an asset
fiixCmmsClient.change({
  "className" : "Asset",
  "changeFields" : "strDescription, strModel, strMake",
  "object" : {
    "id": 408634,
    "strDescription" : "Not the same description anymore",
    "strModel" : "Not the same model anymore",
    "strMake" : "Not the same make anymore",
    "qtyStockCount" : 4
  },
  "fields" : "strName, strModel, strMake, qtyStockCount",
  "callback": function(ret) {
    if (!ret.error) {
      output(ret.object);
    } else output(ret.error);
  }
});

There are a few things to be noticed here :

Creating a work order

Now that we have created some assets, we are going to create a work order for one of the asset. We are going to add a WorkOrder object. If you look at the reference for the Asset object, you can see that intSiteID and intWorkOrderStatusId are required fields. First we are going to list the sites using a filtered find request :

// List sites
fiixCmmsClient.find({
  "className": "Asset",
  "filters": [{"ql": "bolIsSite = ?", "parameters": [1]}],
  "fields": "id, strName",
  "callback": function(ret) {
    if (!ret.error) {
      output(ret.objects);
    } else output(ret.error);
  }
});

Please refer to the Filters section of the reference documentation for more details about filters.

Let's list the work order statuses :

// List work order statuses
fiixCmmsClient.find({
  "className": "WorkOrderStatus",
  "fields": "id, strName, intSysCode",
  "orderBy": "intSysCode",
  "callback": function(ret) {
    if (!ret.error) {
      output(ret.objects);
    } else output(ret.error);
  }
});

We are going to use the (No Site) site and the Draft status. We can now create a work order :

// Create a work order
fiixCmmsClient.add({
  "className" : "WorkOrder",
  "object" : {
    "intSiteID": 408456,
    "intWorkOrderStatusID": 13341
  },
  "fields" : "id",
  "callback": function(ret) {
    if (!ret.error) {
      WORKORDER_ID = ret.object.id;
      output(ret.object);
    } else output(ret.error);
  }
});

Associating assets to the work order

We now want to define the assets that are concerned by the work order. We are going to use the association object called WorkOrderAsset.

// Associate a work order with assets

if (!WORKORDER_ID) output('Create a work order first');

// Associate it with one asset
var addFirst = fiixCmmsClient.prepareAdd({
  "className" : "WorkOrderAsset",
  "object" : {
    "intWorkOrderID": WORKORDER_ID,
    "intAssetID": 408488
  },
  "fields" : "id"
});

// Associate it with a second asset
var addSecond = fiixCmmsClient.prepareAdd({
  "className" : "WorkOrderAsset",
  "object" : {
    "intWorkOrderID": WORKORDER_ID,
    "intAssetID": 408489
  },
  "fields" : "id"
});

// Execute the batch
fiixCmmsClient.batch({
  "requests": [addFirst, addSecond],
  "callback": function(ret) {
    output(ret);
  }
});

Creating work order tasks

Now that we have a work order associated with assets, we are going to create some tasks inside of it. Tasks are represented by the WorkOrderTask object. We are going to assign the task to one of the user with the intAssignedToUserID fields.

// Create some tasks

if (!WORKORDER_ID) output('Create a work order first');

var task1 = fiixCmmsClient.prepareAdd({
  "className": "WorkOrderTask",
  "object": {
    "intWorkOrderID": WORKORDER_ID,
    "intAssetID": 408488,
    "intTaskType": 0,
    "intOrder": 0,
    "intAssignedToUserID": 32741
  },
  "fields": "id"
});

var task2 = fiixCmmsClient.prepareAdd({
  "className": "WorkOrderTask",
  "object": {
    "intWorkOrderID": WORKORDER_ID,
    "intAssetID": 408489,
    "intTaskType": 0,
    "intOrder": 1,
    "intAssignedToUserID": 32742
  },
  "fields": "id"
});

// Execute the batch
fiixCmmsClient.batch({
  "requests": [task1, task2],
  "callback": function(ret) {
    output(ret);
  }
});

For convenience purpose, the WorkOrder object has some special fields for accessing associated assets and users directly. This way, we can check the associations we have just created :

// Retrieve work order with associated users and assets

if (!WORKORDER_ID) output('Create a work order first');

fiixCmmsClient.findById({
  "className" : "WorkOrder",
  "id": WORKORDER_ID,
  "fields" : "id, strAssetIds, strAssets, strAssignedUserIds, strAssignedUsers",
  "callback": function(ret) {
    if (!ret.error) {
      output(ret.object);
    } else output(ret.error);
  }
});

Uploading a file

In order to upload a file to an object via a HTTP call, use the uploadFile method as in the below example. This will upload an empty file into an Asset and WorkOrder object identified by sourceIdString.

Do note that the actual logic to fetch the file via a form will need to be implemented by the client.


        const assetUploadFile = "";
        const woUploadFile = "";
        var descriptionArray = [{
            sourceInfo : "ASSET_INFO",
            sourceIdString: "512",
            fieldName : "assetUploadFile"
        },
            {
                sourceInfo : "WORK_ORDER_INFO",
                sourceIdString: "1",
                fieldName : "workUploadFile"
            },
        ];

        const result = fiixCmmsClient.uploadFile(
            {
                "descriptions" : descriptionArray,
                "assetUploadFile": assetUploadFile,
                "workUploadFile": woUploadFile
            });