Once an access token is obtained from OAuth2.0, the ProcessMaker REST endpoints can be called using that access token. This page explains how to call REST endpoints using PHP, standard JavaScript and JQuery (which is a library of JavaScript).

Because there is a lot of code involved in sending out each HTTP request and processing the response, it is recommended to create a custom function named pmRestRequest() that will handle the REST requests. Using this function will simplify your code and help avoid duplication and errors.

Response values

When a REST request is successful, it will set the HTTP status code to 200 (OK) or 201 (Created). It is a good idea to always check whether a REST request was successful after executing it.

ProcessMaker REST endpoints have response values that will return JSON (JavaScript Object Notation) strings, which need to be decoded. In PHP, the response value can be decoded using json_decode().

In JavaScript, the JSON.parse() function can be used to decode JSON strings if using a recent web browser that supports JSON (Internet Explorer 8+, Firefox 3.1+, Chrome 3+, Safari 4.0.3+ and Opera 10.5+). For older browsers, eval() needs to be used, although it is not as safe. It is recommended to check whether the JSON object exists before calling the JSON.parse() method:

var req = new XMLHttpRequest();
...
oRet = (JSON) ? JSON.parse(req.responseText) : eval(req.responseText);

Errors

If ProcessMaker detects an error in a REST request, the HTTP status code will be set to 400 (Bad Request) and the following error object will be returned:

{
   error: {
      code: 400,
      message: "error-message"
   }
}

If unable to handle the error, it is recommended to display the error to the user so someone can be contacted to fix the problem.

If an error occurs that isn't handled by ProcessMaker, then the HTTP status code will be set to another number and there will be no response value. For example, if the endpoint is misspelled or doesn't exist, the status code will be 404 (Not Found). If the workspace is misspelled or doesn't exist, the status code will be 503 (Service Unavailable). In these cases it is recommended to print the status code so the user can figure out what the problem is.

Expired Authorization

If the access token has expired or is invalid, the HTTP status code will be set to 401 (Unauthorized) and the following error object will be returned:

{
   error: {
      code:    401,
      message: "Unauthorized"
   }
}

PHP

The cURL library in PHP can be used to call ProcessMaker REST endpoints. For each REST request, the configuration of the HTTP header is different, depending on whether the method is GET, POST, PUT or DELETE.

All requests of a ProcessMaker REST endpoint need to include the access token in the HTTP header. For example, if the access token is "38d25eab20873124becc8948df03e14519f93695", then it is included in the header in this manner:

$ch = curl_init("https://example.com/api/1.0/workflow/users");
curl_setopt($ch, CURLOPT_HTTPHEADER, array("Authorization: Bearer 38d25eab20873124becc8948df03e14519f93695"));

GET Requests

To call a GET endpoint using cURL and get the response object and HTTP status code:

$ch = curl_init("url"); curl_setopt($ch, CURLOPT_HTTPHEADER, array("Authorization: Bearer access-token")); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $oRet = json_decode(curl_exec($ch)); $status = curl_getinfo($ch, CURLINFO_HTTP_CODE);

For example, to get print a list of all the active ProcessMaker users:

$pmServer = "https://example.com"; //set to your ProcessMaker address
 
$accessToken = isset($_COOKIE['access_token']) ? $_COOKIE['access_token'] : getAccessToken();
 
$ch = curl_init($pmServer . "/api/1.0/workflow/users");
curl_setopt($ch, CURLOPT_HTTPHEADER, array("Authorization: Bearer " . $accessToken));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$aUsers = json_decode(curl_exec($ch));
$statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
 
if ($statusCode != 200) {
   if (isset ($aUsers) and isset($aUsers->error))
      print "Error code: {$aUsers->error->code}\nMessage: {$aUsers->error->message}\n";
   else
      print "Error: HTTP status code: $statusCode\n";
}
else {
   foreach ($aUsers as $oUser) {
      if ($oUser->usr_status == "ACTIVE") {
         print "{$oUser->usr_firstname} {$oUser->usr_lastname} ({$oUser->usr_username})\n";
      }
   }
}

POST Requests

To send a POST request, create an associative array where each key is the name of a POST variable. This associative array is included with the request by using the CURLOPT_POSTFIELDS option. If the POST variables contain an array within an array (which may happen with a few endpoints such as /cases/ and /cases/{app_uid}/variables), then the http_build_query() function needs to be used to convert the array into a string and URL-encode it. Even if the POST variables don't contain an array within an array, it doesn't cause any problems to use http_build_query(), so it it is recommended to use it for all POST requests. $aVars = array( "variable1" => "value1", "variable2" => "value2" ); $ch = curl_init("url"); curl_setopt($ch, CURLOPT_HTTPHEADER, array("Authorization: Bearer access-token")); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($aVars)); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $oRet = json_decode(curl_exec($ch)); $status = curl_getinfo($ch, CURLINFO_HTTP_CODE);

Converting to UTF-8

If the values of the POST or PUT variables do not use the UTF-8 character set, then they first need to be converted to UTF-8 using the mb_convert_encoding() function. For example, if converting from ISO-8859-15 to UTF-8:

$aVars = array(
   "position"  => "Lingüista español",
   "associate" => "José Ibáñez"
);
foreach($aVars as $key => $value) {
   $aVars[$key] = mb_convert_encoding($value, 'UTF-8', 'ISO-8859-15');
}

PUT Requests

PUT requests are similar to POST requests. The command curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT") is used to change the request from POST to PUT. Like POST requests, it is recommended to use the http_build_query() function to convert the array of PUT variables into a string and URL-encode it:

$aVars = array( "variable1" => "value1", "variable2" => "value2", ... ); $ch = curl_init("url"); curl_setopt($ch, CURLOPT_HTTPHEADER, array("Authorization: Bearer access-token")); curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT"); curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($aVars)); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $oRet = json_decode(curl_exec($ch)); $status = curl_getinfo($ch, CURLINFO_HTTP_CODE);

Example:

The following example changes the status of a user to "VACATION" and sets the replacement user:

$apiServer = "https://example.com";            //set to your ProcessMaker address
$userId = "75740355754dd28ba73d7d6082172937";  //set to the unique ID of a user
 
$accessToken = isset($_COOKIE['access_token']) ? $_COOKIE['access_token'] : getAccessToken();
 
$postParams = array(
  'usr_status'      => "VACATION",
  'usr_replaced_by' => "14680180454ca4477335a27034362107"
);
 
$ch = curl_init($apiServer . "/api/1.0/workflow/user/" . $userId);
curl_setopt($ch, CURLOPT_HTTPHEADER, array("Authorization: Bearer $accessToken"));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postParams));
$oResult = json_decode(curl_exec($ch));
$statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
 
if (isset($oResult) and isset($oResult->error)) {
   print "Error in $apiServer: \nCode: {$oResult->error->code}\nMessage: {$oResult->error->message}\n";
}
elseif (isset($oResult) and isset($oResult->usr_uid)) {
   print "User '{$oResult->usr_uid}' updated:\n";
   print_r($oResult);
}
else {
   print "Error updating user: HTTP status code: $statusCode\n";
}
curl_close($ch);

DELETE Requests

To send a DELETE request:

$ch = curl_init("url"); curl_setopt($ch, CURLOPT_HTTPHEADER, array("Authorization: Bearer access-token")); curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "DELETE") curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $oRet = json_decode(curl_exec($ch)); $status = curl_getinfo($ch, CURLINFO_HTTP_CODE);

Most DELETE requests don't have a response value, so make sure to check whether the HTTP status code is 200 to determine whether the request was successful.

Example:
This example deletes a user:

$apiServer = "https://example.com"; //set to your ProcessMaker address
$userId    = "75740355754dd28ba73d7d6082172937"; //set to a user's ID
$accessToken = isset($_COOKIE['access_token']) ? $_COOKIE['access_token'] : getAccessToken();
 
$ch = curl_init($apiServer . "/api/1.0/workflow/user/$userId");
curl_setopt($ch, CURLOPT_HTTPHEADER, array("Authorization: Bearer $accessToken"));
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "DELETE");
$oResult = json_decode(curl_exec($ch));
$statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
 
if ($statusCode != 200) {
   if (isset($oResult) and isset($oResult->error)) {
      print "Error in $apiServer: \nCode: {$oResult->error->code}\nMessage: {$oResult->error->message}\n";
   }
   else {
      print "Error: HTTP status code: $statusCode\n";
   }
}
curl_close($ch);

PHP pmRestRequest() Function

The best way to avoid code duplication is to create a generic function that can handle ProcessMaker REST requests. This function will set the headers depending on the HTTP method and execute the request using cURL. If an error occurs, it will print the error. Then, it returns an object containing the HTTP status code and the response object.

$pmServer = "https://example.com"; //set to address of the ProcessMaker server
 
/*Function to call a ProcessMaker REST endpoint and return the HTTP status code and
response if any.
Parameters:
 $method:      HTTP method: "GET", "POST", "PUT" or "DELETE"
 $endpoint:    The PM endpoint, not including the server's address and port number.
               Ex: "/api/1.0/workflow/cases"
 $aVars:       Optional. Associative array containing the variables to use in the request
               if "POST" or "PUT" method.
 $accessToken: Optional. The access token, which comes from oauth2/token. If not defined
               then uses the access token in $_COOKIE['access_token']
Return Value:
 object {
    response: Response from REST endpoint, decoded with json_decode().
    status:   HTTP status code: 200 (OK), 201 (Created), 400 (Bad Request), 404 (Not found), etc.
 }                                                                                              */

function pmRestRequest($method, $endpoint, $aVars = null, $accessToken = null) {
   global $pmServer;
 
   if (empty($accessToken) and isset($_COOKIE['access_token']))
      $accessToken = $_COOKIE['access_token'];
 
   if (empty($accessToken)) { //if the access token has expired
      //To check if the PM login session has expired: !isset($_COOKIE['PHPSESSID'])
      header("Location: loginForm.php"); //change to match your login method
      die();
   }
 
   //add beginning / to endpoint if it doesn't exist:
   if (!empty($endpoint) and $endpoint[0] != "/")
      $endpoint = "/" . $endpoint;
 
   $ch = curl_init($pmServer . $endpoint);
   curl_setopt($ch, CURLOPT_HTTPHEADER, array("Authorization: Bearer " . $accessToken));
   curl_setopt($ch, CURLOPT_TIMEOUT, 30);
   curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
   $method = strtoupper($method);
 
   switch ($method) {
      case "GET":
         break;
      case "DELETE":
         curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "DELETE");
         break;
      case "PUT":
         curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");
      case "POST":
         curl_setopt($ch, CURLOPT_POST, 1);
         curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($aVars));
         break;
      default:
         throw new Exception("Error: Invalid HTTP method '$method' $endpoint");
         return null;
   }
 
   $oRet = new StdClass;
   $oRet->response = json_decode(curl_exec($ch));
   $oRet->status   = curl_getinfo($ch, CURLINFO_HTTP_CODE);
   curl_close($ch);
 
   if ($oRet->status == 401) { //if session has expired or bad login:
      header("Location: loginForm.php"); //change to match your login method
      die();  
   }
   elseif ($oRet->status != 200 and $oRet->status != 201) { //if error
      if ($oRet->response and isset($oRet->response->error)) {
         print "Error in $pmServer:\nCode: {$oRet->response->error->code}\n" .
               "Message: {$oRet->response->error->message}\n";
      }
      else {
         print "Error: HTTP status code: $oRet->status\n";
      }
   }
 
   return $oRet;
}

The pmRestRequest() function can be passed an access token to use when calling the REST endpoint. If the access token is not included as a parameter in the function, then pmRestRequest() uses the access token that is saved as a cookie. If the access token doesn't exist or has expired, then the pmRestRequest() function redirects to a web page where the user can enter their credentials to log into ProcessMaker. If doing automatic logins with saved credentials, then change this code to call pmRestLogin() directly.

After calling the REST endpoint, the pmRestRequest() function checks for errors in the response and prints them to inform the user of the problem. Then, it places the response and HTTP status code from the endpoint call in a object that is returned. When calling pmRestRequest(), check that the status code is 200 (or 201 for some endpoints) to make sure that there were no errors and then process the response.

For example, to call the GET /api/1.0/{workspace}/users endpoint using the pmRestRequest() function and print out a list of users:

$oRet = pmRestRequest('GET', '/api/1.0/workflow/users');
if ($oRet and $oRet->status == 200) {
   foreach ($oRet->response as $oUser) {
      print "{$oUser->usr_firstname} {$oUser->usr_lastname} ({$oUser->usr_username})\n";
   }
}

To log into ProcessMaker and then call the pmRestRequest() function using the access token that was obtained while logging in:

$oToken = pmRestLogin("GHDPKQUUBPKFXVEQCCGFNKAQUTXCFCWT", "5691904375509982564af14078068885", "johndoe", "p4ssw0rd");
$oRet = pmRestRequest("GET", '/api/1.0/workflow/users', null, $oToken->access_token);
if ($oRet and $oRet->status == 200) {
   foreach ($oRet->response as $oUser) {
      print "{$oUser->usr_firstname} {$oUser->usr_lastname} ({$oUser->usr_username})\n";
   }
}

JavaScript

In standard JavaScript, the XMLHttpRequest() method can be used to call a ProcessMaker REST endpoint. XMLHttpRequest() is available in Internet Explorer 7+, FireFox, Chrome, Opera 8+, Safari 1.2+ and iCab 3.0+. In Internet Explorer 5, 5.5 and 6, ActiveXObject("Microsoft.XMLHTTP") can be used instead of XMLHttpRequest().

Examples are listed below of GET, POST, PUT and DELETE requests, but the easiest way to implement REST is to use the generic pmRestRequest() function below that can handle all the HTTP methods and does standard error checking.

GET Requests

This JavaScript example creates a array of active users. It obtains the list of all the users in the workspace and stores it in an array named aUsers. Then it loops through the array and checks whether the user's status is "ACTIVE". If so, it adds the user's UID and username to a new array named aActiveUsers.

pmServer = "https://example.com"; //set to address of your ProcessMaker server
pmWorkspace = "workflow";  //set to the workspace of your ProcessMaker server
 
function getUsers() {
   if (getCookie("access_token") == false || getCookie("PHPSESSID") == false) {
      location.window.href = "login.html";
      return;
   }
 
   var req = new XMLHttpRequest();
   req.open("GET", $pmServer + "/api/1.0/" + $pmWorkspace + "/users", true);
   req.setRequestHeader("Authorization", "Bearer " + getCookie('access_token'));
 
   req.onreadystatechange = function() {
   if (req.readyState==4) {
      if (req.status==200) {
         var aActiveUsers = [];
         var aUsers = JSON.parse(req.responseText);
 
         for (var i = 0; i < aUsers.length; i++) {
            if (aUsers[i].usr_status == "ACTIVE") {
               aActiveUsers.push({
                  'uid':      aUsers[i].usr_uid,
                  'username': aUsers[i].usr_username
               });
            }
         }
      }
      else {
         alert("Error status code: " + req.status);
      }
   }
   req.send(null);
}

PUT Requests

To do PUT requests in JavaScript, place the parameters in an object and then use encodeURIComponent() to encode them so they can be sent in the HTTP header with URL-encoding:

var oVars = {
   "variable1": "value1",
   "variable2": "value2"
};
 
for (var v in oVars) {
   if (oVars.hasOwnProperty(v))
      oVars[v] = encodeURIComponent(oVars[v]);
}

The following example changes the status of a user to "VACATION" and sets the user who will replace this user when they goes on vacation.

$pmServer = "https://example.com";            //set to your ProcessMaker address
$userId = "75740355754dd28ba73d7d6082172937"; //set to the unique ID of a user
 
var oVars = {
  'usr_status':      "VACATION",
  'usr_replaced_by': "14680180454ca4477335a27034362107"
};
 
for (var v in oVars) {
   if (oVars.hasOwnProperty(v))
      oVars[v] = encodeURIComponent(oVars[v]);
}
 
var req = XMLHttpRequest();
req.open('PUT', pmServer + '/api/1.0/workflow/user/' + userId, true);
req.setRequestHeader("Authorization", "Bearer " + getCookie("access_token"));
var sVars = JSON.stringify(oVars);  
req.setRequestHeader('Content-type','application/json; charset=utf-8');
req.setRequestHeader('Content-length', sVars.length);
 
req.onreadystatechange = function() {
   if (req.readyState==4) {
      if (req.responseText) {
         //use JSON.parse() to decode response text if the web browser supports it:
         oResult = (JSON) ? JSON.parse(req.responseText) : eval(req.responseText);
 
      if (req.status == 401) {
          window.location.href = login.html;
      }
      else if (req.status != 200 && req.status != 400) {
          alert("Error status code: " + req.status);
      }
      else if (req.status == 400) {  
          alert("Error Code: " + oResult.error.code + "\nMessage: " + oResult.error.message);
      }
      else {
          //nothing required if success
      }
   }
}
req.send(null);

JavaScript pmRestRequest() Function

The best way to avoid code duplication is to create a generic JavaScript function called pmRestRequest() that can handle ProcessMaker REST requests. This function will set the HTTP headers depending on the HTTP method and then execute the call using XMLHttpRequest(). If an error occurs, it will display the error to the user.

var pmServer = "https://example.com"; //set to IP address of ProcessMaker server
 
//function to read cookie by name. If it returns false, then the cookie doesn't exist.
//if it returns "", then the cookie exists, but has no value.
function getCookie(name) {
   function escape(s) {
      return s.replace(/([.*+?\^${}()|\[\]\/\\])/g, '\\$1');
   };
   var match = document.cookie.match(RegExp('(?:^|;\\s*)' + escape(name) + '=([^;]*)'));
   return match ? match[1] : null;
}
 
//Global variables set by synchronous call to last REST endpoint:
var oResponse  = null; //response object returned by REST endpoint and decoded with JSON.parse():
var httpStatus = null; //HTTP status code of call to REST endpoint
 
/*function to call a ProcessMaker endpoint. If a synchronous call, it sets the global variables
httpStatus to the HTTP status code and oResponse to the decoded JSON response string.
Parameters:
 method:        HTTP method: "GET", "POST", "PUT" or "DELETE"
 endpoint:      The PM endpoint, not including the server's address and port number.
                Ex: "/api/1.0/workflow/cases"
 asynchronous:  Optional. Set to true if asynchronous request. If false (the default value), then
                processing waits until the HTTP request completes, which means the browser freezes.
 oVars:         Optional. Object containing variables to use in the request if "POST" or "PUT" method.
 func:          Optional. Custom function to be called after the endpoint request, whose first parameter
                is the response object and the second parameter is the HTTP status code. */

function pmRestRequest(method, endpoint, asynchronous, oVars, func) {
   //set optional parameters:
   asynchronous = (typeof asynchronous === 'undefined') ? false : asynchronous;
   oParams      = (typeof oParams === 'undefined')      ? null  : oParams;
   func         = (typeof func === 'undefined')         ? null  : func;
 
   while (!getCookie("access_token")) {
       pmRestLogin();
   }  
 
   if (typeof XMLHttpRequest != "undefined") {
      var req = XMLHttpRequest();
   }
   else {
      try {  //for IE 5, 5.5 & 6:
         var req = new ActiveXObject("Microsoft.XMLHTTP");
      }
      catch (e) {
         alert ("Error: This browser does not support XMLHttpRequest.");
         return;
      }
   }
 
   req.open(method, pmServer + endpoint, asynchronous);
   req.setRequestHeader("Authorization", "Bearer " + getCookie("access_token"));
   sVars = null;
   method = method.toUpperCase().trim();
 
   switch (method) {
      case "GET":
      case "DELETE":
         break;
      case "PUT":
         //URL encode the values of any variables in oVars:
         if (oVars) {
            for (var v in oVars) {
               if (oVars.hasOwnProperty(v))
                  oVars[v] = encodeURIComponent(oVars[v]);
            }
         }    
      case "POST":
         var sVars = JSON.stringify(oVars);  
         req.setRequestHeader('Content-type','application/json; charset=utf-8');
         req.setRequestHeader('Content-length', sVars.length);
         break;
      default:
         alert("Error: Invalid HTTP method '" + url + "'.");
         return;
   }
 
   req.onreadystatechange = function() {
      if (req.readyState == 4) { //the request is completed
         var status = req.status;
         var oResp = null;
 
         if (req.responseText) {
            //use JSON.parse() to decode response text if the web browser supports it:
            oResp = (JSON) ? JSON.parse(req.responseText) : eval(req.responseText);
         }
 
         if (!asynchronous) {
            httpStatus = status;
            oResponse = oResp;
         }
         if (status == 401) {
            window.location.href = "login.html";
            return;
         }
         else if (oResp && oResp.error) {
            var msg = "Error code: " + oResp.error.code + "\nMessage: " + oResp.error.message;
            alert(msg);
            //throw error if wanting to handle it:
            //throw new Error(msg);
         }
         else if (status != 200 && status != 201) {  
            alert("HTTP status error: " + req.status);
            //throw error if wanting to handle it:
            //throw new Error("HTTP status error: " + req.status);
         }
 
         if (func) {  //call custom function to handle response:
            func(oResp, status);      
         }
      }
   };
 
   if (asynchronous) {
      req.timeout   = 20000;   //timeout after 20 seconds
      req.ontimeout = function() { alert("Timed out calling " + $endpoint); };
   }
   req.send(sVars);
}

Executing pmRestRequest() Asynchronously

The REST endpoint can be called synchronously or asynchronously using the pmRestRequest() function. It is recommended to call it asynchronously, since it doesn't freeze the web browser while waiting for a response from the ProcessMaker server. If calling asynchronously and needing to process the response, then a custom function should be defined to process the response and pass this function as the last parameter of the pmRestRequest() function. The first parameter of the custom function should be the response object returned by the endpoint, and the second parameter should be the HTTP status code of the endpoint request.

For example, to print the list of users with "ACTIVE" status in the <body> of the current web page, define a custom function named printUserList and pass it as the last parameter in the pmRestRequest() function. Notice that the custom function's name printUserList is passed as a parameter, not printUserList(), since the function's reference is passed and not executed.

function printUserList(aUsers, status) {
   if (status != 200)
      return;
 
   list = "Active users:\n<ol>\n";
 
   for (var i = 0; i < aUsers.length; i++) {
      if (aUsers[i].usr_status == "ACTIVE") {
         list += '<li>' + aUsers[i].usr_firstname + ' ' + aUsers[i].usr_lastname +
            '(' + aUsers[i].usr_username + ')</li>\n';
      }  
   }
   var p = document.createElement('p');
   p.innerHTML = list + "</ol>\n";
   document.body.appendChild(p);          
}
 
pmRestRequest('GET', '/api/1.0/workspace/users', true, null, printUserList); //execute when page loads

Executing pmRestRequest() Synchronously

Executing the REST call asynchronously can be difficult if doing a whole series of actions in a row. In some instances it may necessary to execute REST requests synchronously so that things can happen in a sequence. Just remember that doing this will freeze the web browser while waiting for the response from the ProcessMaker server.

After pmRestRequest() is called synchronously, the HTTP status code from the endpoint request will be set in the global variable httpStatus and the response object will be placed in oResponse. Check these variables to see the result of the REST request.

For example:

pmRestRequest('GET', '/api/1.0/workspace/users', false);
if (httpStatus == 200 and oResponse) {
   var aUsers = oResponse;
   list = "Active users:\n<ol>\n";
 
   for (var i = 0; i < aUsers.length; i++) {
      if (aUsers[i].usr_status == "ACTIVE") {
         list += '<li>' + aUsers[i].usr_firstname + ' ' + aUsers[i].usr_lastname +
            '(' + aUsers[i].usr_username + ')</li>\n';
      }  
   }
   var p = document.createElement('p');
   p.innerHTML = list + "</ol>\n";
   document.body.appendChild(p);
}

Source Code for Endpoints

If in doubt about what parameters are accepted by an endpoint, all the endpoints and their GET parameters are listed in the file:
     <INSTALL-DIRECTORY>/shared/compiled/routes.php (version 3.0.1.8 and earlier)
     <INSTALL-DIRECTORY>/shared/sites/workspace/routes.php (version 3.1 and later)

The routes.php file is automatically generated the first time the REST API is called (or the first time it is called after the compiled cache is deleted).

The source code for the endpoints is located in the directory:
     <INSTALL-DIRECTORY>/workflow/engine/src/ProcessMaker/Services/Api

When the endpoints are executed, they call internal classes and functions used in ProcessMaker. When in doubt about the functioning of an endpoint, check the source code of the endpoint and use a search tool such as grep to find the internal classes and functions that it calls.

For example, the endpoint GET /api/1.0/{workspace}/cases calls the Cases::doGetCasesListToDo() method, which is defined in:
     workflow/engine/src/ProcessMaker/Services/Api/Cases.php

That method in turn calls the Cases::getList() method, which is defined in:
     workflow/engine/src/ProcessMaker/BusinessModel/Cases.php

That method in turn calls the Applications::getAll() method, which is defined in:
     workflow/engine/classes/class.applications.php