Maximo JSON API: An IoT Example

I’ve had a lot of conversations recently with folks attempting to implement more Condition Monitoring within their organization. The benefits of shifting from time-based maintenance to condition- or use-based maintenance are well documented and very real. However, making that shift involves a fair amount of planning, analysis, and technology. This article will show an example of how to bridge a small portion of the technology gap; specifically we will focus on creating meter readings in Maximo via the JSON API available in Maximo 7.6.0.2 and higher.

Meter readings are the heart of how Condition Monitoring is implemented in Maximo. They represent a piece of data at a point in time associated with an asset. This data could be related to the asset’s condition such as temperature, pressure, voltage, etc. This data could also be related to the asset’s usage such as an odometer reading, the number of cycles of the asset, etc. Lastly, the data could be based on a simple value list such as Pass/Fail, Open/Closed, Blowing / Not Blowing, etc.

To create a new meter reading via Maximo’s JSON API, let’s start with an example:

POST http://mxapprove.a3jgroup.com/maximo/oslc/os/mxasset/_QkVERk9SRC8xMTQ1MA==?lean=1
maxauth: c21pdGg6c21pdGgx
Content-Type: application/json
properties: *
x-method-override: PATCH
patchtype: MERGE
{
    "assetmeter": [
        {
            "metername": "O-PRESSUR",
            "linearassetmeterid": 0,
            "newreading": "4900"
        }
    ]
}

Let’s look at this part-by-part. First, we start with the HTTP POST itself.

POST /maximo/oslc/os/mxasset/_QkVERk9SRC8xMTQ1MA==?lean=1

This message needs to be an HTTP POST (not HTTP GET). The http://mxapprove.a3jgroup.com/maximo portion of the URL is your Maximo environment’s URL. Substitute that for your own environment’s URL. The /oslc part of the path represents the usage Maximo JSON API. The /os part of the path tells the API that the next part of the path (in our example is /mxasset) will be an Object Structure in Maximo. Finally, the /_QkVERk9SRC8xMTQ1MA== represents a unique identifier for an Asset record that can be referenced in the MXASSET Object Structure. This identifier can be found be querying for the asset using an HTTP GET to the same MXASSET Object Structure, or it can be derived by base64 encoding the asset’s SITEID + “/” + ASSETNUM and prefixing that string with an underscore (“_”) character. The ?lean=1 part of the path allows us to not have to specify namespace prefixes in the body of the request.

Next are the various headers.

maxauth: c21pdGg6c21pdGgx
Content-Type: application/json
properties: *
x-method-override: PATCH
patchtype: MERGE

The maxauth header represents the credentials that are being used to broker the transaction. The value is a base64 encoded string of the format USERNAME + “:” PASSWORD. In an LDAP environment, switch the maxauth header to Authorization and prefix the string “Basic ” to the base64 encoded value. The Content-Type header tells the HTTP request that the body of the message will be in JSON format. The properties header tells the request which fields from the MXASSET Object Structure should be sent back in the HTTP response, with the * character representing all fields in the object structure. The x-method-override header with a value of PATCH tells Maximo that this will be an update to the asset record, and the patchtype header with a value of MERGE tells Maximo to add a new record while keeping the other ASSETMETER records. Without that header, the integration will replace all of the ASSETMETER records with the list in the message.

Next is the body of the message.

{
    "assetmeter": [
        {
            "metername": "O-PRESSUR",
            "linearassetmeterid": 0,
            "newreading": "4900"
        }
    ]
}

Note that we don’t need any identifying information about the asset in the message body, such as the ASSETNUM or SITEID. This is because we are required to specify the unique identifier in the URL string. We specify the assetmeter key as an array of meters associated with the asset. For this example, we are only updating a single meter against the asset (Outlet Pressure). In our object, we specify the Meter Name and New Reading value. The linearassetmeterid key with a value of 0 is necessary due to that field being part of the unique identifier on the ASSETMETER table. Values such as the New Reading Date and Inspector will default based on the current date and the logged in user credentials, but can also be specified explicitly in the message.

Please feel free to leave questions or comments below. Good luck in your IoT journey!

Call Maximo Automation Scripts from JSON API

It was not until I read chapter 14 of IBM’s overview of the Maximo JSON API that it occurred to me that we could use the JSON API to launch an automation script in Maximo and then see the results in the return message. We can create our own APIs using the relative simplicity of an automation script and not have to write a single line of Java code. Truly powerful stuff!

The example provided in the article was also useful to me in that I was going through the process of loading data into Maximo when I came across the article. The script used in the article queries Maximo objects and reports back a record count. In my situation this was a very poignant and timely revelation.

Creating the Script

The first step in this process is to create an automation script that we want Maximo to run. I took the script provided in the example and expanded the list of objects to suit my situation. Besides the additional objects I wanted a total count of records that were loaded which is the purpose of the “Get Total Count” section at the end of the script.

Source Code:

importPackage(Packages.psdi.server);
// Create the response object
var resp = {};
// Get the Site ID from the Query Parameters
var site = request.getQueryParam("site");
// Count of Work Orders
var woset = MXServer.getMXServer().getMboSet("WORKORDER", request.getUserInfo());
woset.setQbe("SITEID","="+site);
var woCount = woset.count();
resp.wo_count = woCount;
woset.close();
// Count of Service Requests
var srset = MXServer.getMXServer().getMboSet("SR", request.getUserInfo());
srset.setQbe("siteid","="+site);
var srCount = srset.count();
resp.sr_count = srCount;
srset.close();
// Count of Items
var itmset = MXServer.getMXServer().getMboSet("ITEM", request.getUserInfo());
var itmCount = itmset.count();
resp.item_count = itmCount;
itmset.close();
// Get Total Count
resp.total = woCount+srCount+itmCount;
var responseBody = JSON.stringify(resp);

Navigate to the Automation Script application and select Create and then choose Script.


Since we are going to be launching this script from an HTTP call we just need to create the script and not provide a separate launch point.

Fill out the script Name, Description, Language and the Source Code from above.

Make sure the script is Active and select Create to save the script.

Executing the Script

We need three pieces of information to complete a successful JSON API call:

  • Site ID
    • In this example we are using the demonstration data, so our site is BEDFORD.
  • Username and Password
    • User Name: maxadmin
    • Password: maxadmin
  • URL
    • http://maximo_host/maximo/oslc/script/a3j_recordcount?_lid=maxadmin&_lpwd=maxadmin&site=BEDFORD
    • Note that there are underscores in front of lid and lpwd which might now be obvious from the link formatting above.

Script Results

{
"wo_count": 1331,
"sr_count": 41,
"item_count": 357,
"total": 1729
}

Querying Maximo using the REST and JSON APIs

In a recent exchange on the IBM developerWorks forum for Maximo, it was discussed how best to query Maximo through the Integration Framework that is configured for LDAP. Getting data from an LDAP-based Maximo is similar to an environment that is configured to use native authentication, with a few subtle differences. This article will demonstrate how to query for data using the REST API that is found in Maximo 7.5.0.3 and higher, and the JSON API that is found in Maximo 7.6.0.2 and higher.

The information detailed below is available in an IBM article (available as a PDF or as a web page) titled “Maximo NextGen REST API”. Based on questions I have received from our customers and other Maximo professionals, there seems to be some confusion on how to use this information.

There are many tools available that will facilitate communication to and from Maximo using the REST and JSON APIs. This article uses the Postman application which can be downloaded for free here.

Before we dive into the “How” we should discuss the “Why”. What are some reasons for wanting to use these Maximo APIs? Here are a few:

  • Creating new records
  • Modifying existing records
  • Querying Maximo data from an external application
  • Performing calculations on Maximo data such as averaging a cost, finding maximum cost or summing a budget from an external application
  • Creating lists based on Maximo data
  • Querying related records from an external application such as retrieving a list of work orders for a given asset
  • Deleting data
  • Replacing data

Querying Maximo Data with Native Authentication

Let’s start off with a simple scenario: show me all Person records that start with the string ‘CAR’. Note that we are using the Maximo demonstration data for these examples.

To start, we need two pieces of information to complete a successful API call:

  1. Maximo API URL
  2. Maximo Username and Password

However, just having the Maximo Username and Password is not good enough to make an API call. We’ll need to encode those credentials before calling the API.

The credentials will need to be Base64 encoded using the username:password format. For example, if your credentials were maxadmin:maxadmin, your Base64 encoded credentials would be bWF4YWRtaW46bWF4YWRtaW4=. You can use this online utility to perform a successful encode. Place your username:password in the first box and click the > ENCODE < button. Your Base64 encoded string will appear in the box below.

Now we can fire up our Postman application to perform the calls to Maximo.

JSON API

For the JSON API, our Maximo URL will look like this:

http://maximo_host/maximo/oslc/os/mxperson?oslc.where=personid="CAR%"

Substitute your Maximo host name for the maximo_host, and include a port number if necessary.

Next, we’ll need to supply the credentials as an HTTP Header. The header key for Native Maximo Authentication is maxauth. The header value will be your Base64 encoded credentials. Finally, we’ll use the HTTP Method of GET. It comes together like this:

GET http://maximo_host/maximo/oslc/os/mxperson?oslc.where=personid="CAR%"
maxauth: bWF4YWRtaW46bWF4YWRtaW4=

In Postman:

Maximo will perform a wildcard search so all person records that contain the string CAR will be returned. In the case of the sample or demonstration data, that is one record.

The result will be something similar to this:

{
  "member": [
    {
      "href": "http://maximo_host/maximo/oslc/os/mxperson/_Q0FSU09O"
    }
  ],
  "responseInfo": {
    "href": "http://maximo_host/maximo/oslc/os/mxperson?lean=1&oslc.where=personid=%22CAR%25%22"
  },
  "href": "http://maximo_host/maximo/oslc/os/mxperson"
}

When using the JSON API you will get a URI back. This URI is especially useful as you can use this URL to query, perform updates, or perform a delete action on a specific record. In this case you can take the URL and place that back into Postman to perform a GET action. You will receive all of the pertinent record information for that specific record.

http://maximo_host/maximo/oslc/os/mxperson/_Q0FSU09O

REST API

For the REST API, our Maximo URL will look slightly different; however, the concept of authentication remains the same. Substitute your Maximo host name for the maximo_host, and include a port number if necessary:

http://maximo_host/maxrest/rest/os/mxperson?personid=CAR%

It comes together like this:

GET http://maximo_host/maxrest/rest/os/mxperson?personid=CAR%
maxauth: bWF4YWRtaW46bWF4YWRtaW4=

In Postman:

The results are:

{
  "QueryMXPERSONResponse": {
    "rsStart": 0,
    "rsCount": 1,
    "MXPERSONSet": {
      "PERSON": [
        {
          "rowstamp": "[0 0 0 0 0 106 -81 -98]",
          "ACCEPTINGWFMAIL": true,
          "ADDRESSLINE1": "62 Winthrop Street",
          "BIRTHDATE": "1962-08-22T00:00:00-04:00",
          "CITY": "Medford",
          "COUNTRY": "US",
          "DISPLAYNAME": "Tara Carson",
          "FIRSTNAME": "Tara",
          "HIREDATE": "1997-08-01T00:00:00-04:00",
          "LASTEVALDATE": "2001-08-01T00:00:00-04:00",
          "LASTNAME": "Carson",
          "LOCTOSERVREQ": true,
          "NEXTEVALDATE": "2002-08-01T00:00:00-04:00",
          "PERSONID": "CARSON",
          "PERSONUID": 21,
          "POSTALCODE": "02155",
          "PRIMARYEMAIL": "tara.carson@helwig.com",
          "PRIMARYPHONE": "781-555-6247",
          "STATEPROVINCE": "MA",
          "STATUS": "ACTIVE",
          "STATUSDATE": "2003-09-25T15:44:38-04:00",
          "STATUSIFACE": false,
          "TRANSEMAILELECTION": "NEVER",
          "WFMAILELECTION": "PROCESS",
          "PHONE": [
            {
              "rowstamp": "[0 0 0 0 0 96 57 -106]",
              "ISPRIMARY": true,
              "PHONEID": 145855,
              "PHONENUM": "781-555-6247",
              "TYPE": "WORK"
            }
          ],
          "EMAIL": [
            {
              "rowstamp": "[0 0 0 0 0 93 114 125]",
              "EMAILADDRESS": "tara.carson@helwig.com",
              "EMAILID": 145855,
              "ISPRIMARY": true,
              "TYPE": "WORK"
            }
          ]
        }
      ]
    }
  }
}

To get information about a single record in the REST API, you need to reference the Unique ID of the record. In this example, since we are referencing the PERSON object, the PERSONUID attribute is our Unique ID. To query for a specific Person record, include the PERSONUID in the URL:

http://maximo_host/maxrest/rest/os/mxperson/88?_format=json&_compact=1

Querying Maximo Data with LDAP Authentication

If your Maximo instance is configured to use LDAP Authentication, you must use a slightly different HTTP Header to supply the appropriate Maximo credentials. The other information, such as the URL and HTTP Method, remain the same.

In place of MAXAUTH, Authorization is used as the property in the HTTP Header. The same Base64 encoded username:password combination created earlier is also used for the value, however, this time it is preceded with the word Basic and a space character.

It comes together like this using the JSON API:

GET http://maximo_host/maximo/oslc/os/mxperson?oslc.where=personid="CAR%"
Authorization: Basic bWF4YWRtaW46bWF4YWRtaW4=

In Postman:

Similarly, for the REST API:

GET http://maximo_host/maxrest/rest/os/mxperson?personid=CAR%
Authorization: Basic bWF4YWRtaW46bWF4YWRtaW4=

Maintaining Your Session

Once you establish a successful connection to Maximo, you will receive a cookie back in the response with a JSESSIONID token.

It is recommended to use this token in subsequent requests back to the Maximo API. This will improve performance and limit the number of sessions that Maximo creates.

Please feel free to leave any comments or questions below. For visual instruction of the previous steps, check out our video tutorial.