Input Documents

The following endpoints are used to control Input Document files uploaded to cases:

Get a list of Input Documents: GET /cases/{app_uid}/input-documents

Returns a list of the uploaded Input Document files for a given case. If versioning is enabled, it only returns the most recent versions of Input Document files. Note that only Input Document files are returned when the logged in user has one of the following rights to view the files:

  • The Input Document is a step in the current task of the case and the logged-in user is currently assigned to work on the case.
  • The logged in user has process permissions to view the task where the Input Document is a step.

Note that it is possible to still get the list of Input Documents for a case, regardless of the case's status, so it is possible to get the Input Document files for cases which have been paused, canceled or completed if the user has process permissions.

Note that this endpoint does NOT return Input Document files when the logged-in user is assigned as Process Supervisor to the Input Document, so the user will have to be given Process Permissions (This issue is fixed from version 3.0.1.5).

GET /api/1.0/{workspace}/cases/{app_uid}/input-documents

URL Parameters:

Parameter Description Example
workspace Workspace name which by default is "workflow". /api/1.0/workflow/cases/37213410154d375de3e3620044382558/input-documents
app_uid Case's unique ID. /api/1.0/workflow/cases/37213410154d375de3e3620044382558/input-documents

Result:

If successful, the HTTP status is set is 200 and array of objects is returned with information about each uploaded Input Document file:

[ Start array of file objects.
{ Start first file object.
"app_doc_uid", Unique ID of Input Document file.
"app_doc_filename", Filename of Input Document file
"doc_uid", Unique ID of the Input Document definition.
"app_doc_version", Version of the uploaded file, with counts starting from "1". If versioning isn't enabled, then this value is always "1".
"app_doc_create_date", Datetime in "YYYY-MM-DD HH:MM:SS" format when file was uploaded.
"app_doc_create_user", User who uploaded file to the case in "last-name, first-name (username)" format.
"app_doc_type", Type of document which can be: "INPUT", "OUTPUT" or "ATTACHED". (An "ATTACHED" file is uploaded through a DynaForm's file field which isn't associated with an Input Document).
"app_doc_index", The case document index which counts the files in the order they were uploaded/created in the case, regardless of whether they are Input Document files, Output Document files or attached to a file field in a DynaForm. The first file has an index of 1, the second has an index of 2, etc. This index also counts files which are uploaded as previous versions of Input Document files.
"app_doc_link", Relative URL to download the file at "cases/cases_ShowDocument?a={app_doc_uid}&v={app_doc_version}". To form a complete URL, prepend "https://{domain}/sys{workspace}/{lang}/{skin}/" to this relative URL. It is possible to download the file as long as the user has an active login session, which by default should last for 24 minutes, so the file can be downloaded by the same script which called this endpoint, using a download program such as cURL or wget. In PHP, functions like file() and file_get_contents() can be used to download the contents of a file from a URL. In JavaScript, the web browser can be redirected to open this URL by assigning it to window.location.href. XMLHttpRequest can be used to download the contents of the file to a variable.
}, End first file object
... Any additional file objects
] End array.

For example:

[
   {
      "app_doc_uid": "8113107945330516f47ccc0076416056",
      "app_doc_filename": "receipts.pdf",
      "doc_uid": "70158392952979dedd77fe0058957493",
      "app_doc_version": "1",
      "app_doc_create_date": "2014-03-24 11:38:23",
      "app_doc_create_user": "Administrator (admin)",
      "app_doc_type": "INPUT",
      "app_doc_del_index": 1,
      "app_doc_link": "cases/cases_ShowDocument?a=8113107945330516f47ccc0076416056&v=1"
   },
   {
      "app_doc_uid": "412239205533051a99876b8018449052",
      "app_doc_filename": "ClientInfo.html",
      "doc_uid": "70158392952979dedd77fe0058957493",
      "app_doc_version": "1",
      "app_doc_create_date": "2014-03-24 11:39:21",
      "app_doc_create_user": "Doe, Jane (janedoe)",
      "app_doc_type": "INPUT",
      "app_doc_del_index": 2,
      "app_doc_link": "cases/cases_ShowDocument?a=412239205533051a99876b8018449052&v=1"
   }
]
Note: The logged-in user may only see information about Input Document files if he/she is currently assigned to the case or has process permissions to see the Input Document to which the files were uploaded.

PHP examples:

This example looks for an Input Document file named "client_bill.txt" and then uses the file_get_contents() function to download it. It then uses the preg_match() function to look for the first line which contains "Invoice No: XXXXXXXXXXXX" so it can extract the invoice number. Note that file_get_contents() can be used to download both text files and binary files, but preg_match() can only be used to search in text files.

$caseId = '44756102555c4e859630f43089650367';
$url = "/api/1.0/{workspace}/cases/$caseId/input-documents";
$method = "GET";
$oRet = pmRestRequest($method, $url);
if ($oRet->status == 200 and count($oRet->response) > 0) {
   //look for client_bill.txt file in array of files
   foreach ($oRet->response as $oDoc) {
      if ($oDoc->app_doc_filename == "client_bill.txt") {
         $fileUrl = 'http://myserver.com/sysworkflow/en/neoclassic/' . $oDoc->app_doc_link;
         $sFile = file_get_contents($fileUrl) or die("Unable to retrieve file '$fileUrl'");

         if (preg_match('/^Invoice No: ([A-Z0-9]{12})/', $sFile, $match)) {
            $invoiceNo = $match[1];
            //do something with the invoice number
         }
      }
   }
}

This example uses cURL to download all the Input Document file(s) for a case. If image files are found, then they are stored on the harddrive. Using cURL downloads both the contents of the file and its header, which can be useful if needing information from the header. The tricky part is separating the contents from the header.

$caseId = '44756102555c4e859630f43089650367';
$url = "/api/1.0/{workspace}/cases/$caseId/input-documents";
$method = "GET";
$oRet = pmRestRequest($method, $url);

if ($oRet->status == 200 and count($oRet->response) > 0) {
   set_time_limit(0);

   foreach($oRet->response as $oDoc) {
      $fileUrl = 'http://localhost:301/sysworkflow/en/neoclassic/' . $oDoc->app_doc_link;

      $resource = curl_init();
      curl_setopt($resource, CURLOPT_URL, $fileUrl);
      curl_setopt($resource, CURLOPT_HEADER, 1);
      curl_setopt($resource, CURLOPT_RETURNTRANSFER, 1);
      curl_setopt($resource, CURLOPT_BINARYTRANSFER, 1);
      $file = curl_exec($resource);
      $status = curl_getinfo($resource, CURLINFO_HTTP_CODE);

      if ($status != 200) {
         die("Error Status: $status\nUnable to retrieve $fileUrl");
      }
      //separate the HTTP header from the file contents:
      $aFileParts = explode("\n\r", $file, 2);
      $header = $aFileParts[0];
      $contents = substr($aFileParts[1], 1);

      //create an associative array of header information:
      preg_match_all('/^([a-zA-Z\-]+): (.+)/m', $header, $aMatches, PREG_SET_ORDER);
      $aHeader = array();
      foreach ($aMatches as $aMatch) {
         $aHeader[$aMatch[1]] = trim($aMatch[2]);
      }

      //if an image file, then save file to harddrive:
      if (strpos($aHeader['Content-Type'], 'image') === 0) {
         file_put_contents('/some/dir/' . $filename, $contents);
      }
   }
}

The following example first uses cURL to download the first file in the case, then it serves up that same file so the user can download the file as an attachment in the user's web browser. Depending on the configuration of the web browser, file will either be automatically downloaded to the user's local computer or a dialog box will open asking where the user wants to save the file, which gives the user the opportunity to cancel the download.

Note that nothing should be printed by the code or it will corrupt the contents of the downloaded file. It is only possible to download one file at a time with this sample code, so it is recommended to combine all the files in a ZIP file if needing to download more than one file.

$caseId = '44756102555c4e859630f43089650367';
$url = "/api/1.0/{workspace}/cases/$caseId/input-documents";
$method = "GET";
$oRet = pmRestRequest($method, $url);

if ($oRet->status == 200 and count($oRet->response) > 0) {
   set_time_limit(0);
   //get first file
   $oDoc = $oRet->response[0];
   $fileUrl = 'http://localhost:301/sysworkflow/en/neoclassic/' . $oDoc->app_doc_link;
   $resource = curl_init();
   curl_setopt($resource, CURLOPT_URL, $fileUrl);
   curl_setopt($resource, CURLOPT_HEADER, 1);
   curl_setopt($resource, CURLOPT_RETURNTRANSFER, 1);
   curl_setopt($resource, CURLOPT_BINARYTRANSFER, 1);
   $file = curl_exec($resource);
   $status = curl_getinfo($resource, CURLINFO_HTTP_CODE);

   if ($status != 200) {
      die("Error Status: $status\nUnable to retrieve $fileUrl");
   }
   //separate the HTTP header from the file contents:
   $aFileParts = explode("\n\r", $file, 2);
   $header = $aFileParts[0];
   $contents = substr($aFileParts[1], 1);

   //create an associative array of header information:
   preg_match_all('/^([a-zA-Z\-]+): (.+)/m', $header, $aMatches, PREG_SET_ORDER);
   $aHeader = array();
   foreach ($aMatches as $aMatch) {
      $aHeader[$aMatch[1]] = trim($aMatch[2]);
   }
   //serve up file to be downloaded in web browser:
   header('Cache-Control: no-store, no-cache, must-revalidate');
   header('Content-Disposition: ' . $aHeader['Content-Disposition']);
   header('Content-Length: '      . $aHeader['Content-Length']);
   header('Content-Type: '        . $aHeader['Content-Type']);
   echo $contents;
   ob_flush();
   flush();
}

Get Input Document Information: GET /cases/{app_uid}/input-document/{app_doc_uid}

Return the details of an uploaded document for a given case.

GET /api/1.0/{workspace}/cases/{app_uid}/input-document/{app_doc_uid}

Parameters:

Name Type Description
workspace String Workspace name
app_uid String Case unique ID
app_doc_uid String Input Document file's unique ID.

Result:

Returns an object with the same information about the specified Input Document file which is returned by GET /cases/{app_uid}/input-documents. For example:

{
   "app_doc_uid": "8113107945330516f47ccc0076416056",
   "app_doc_filename": "ProductionQuota.docx",
   "doc_uid": "70158392952979dedd77fe0058957493",
   "app_doc_version": "1",
   "app_doc_create_date": "2014-03-24 11:38:23",
   "app_doc_create_user": "Doe, John (johndoe)",
   "app_doc_type": "INPUT",
   "app_doc_index": 1,
   "app_doc_link": "cases/cases_ShowDocument?a=8113107945330516f47ccc0076416056&v=1"
}

Get the Versions of an Input Document: GET /cases/{app_uid}/input-document/{app_doc_uid}/versions

Available: As of ProcessMaker 3.2.2 on.

Returns all the versions of an uploaded document for a given case.

GET /api/1.0/{workspace}/cases/{app_uid}/input-document/{app_doc_uid}/versions

Parameters:

Name Type Description
workspace String Workspace name
app_uid String Case unique ID
app_doc_uid String Input Document file's unique ID.

Result:

Returns an object with the information about the versions of the Input Document file.

Example:

[
    {
        "app_doc_uid": "171494860599388bce0ad56022239268",
        "app_doc_filename": "logo5.jpg",
        "doc_uid": "51430740358c81cdf74c507076011651",
        "app_doc_version": "5",
        "app_doc_create_date": "2017-08-16 14:36:43",
        "app_doc_create_user": "travis, Travis Grady (travis)",
        "app_doc_type": "INPUT",
        "app_doc_index": "9"
    },
    {
        "app_doc_uid": "171494860599388bce0ad56022239268",
        "app_doc_filename": "logo4.jpg",
        "doc_uid": "51430740358c81cdf74c507076011651",
        "app_doc_version": "4",
        "app_doc_create_date": "2017-08-16 14:34:13",
        "app_doc_create_user": "travis, Travis Grady (travis)",
        "app_doc_type": "INPUT",
        "app_doc_index": "8"
    },
    ....
]

Upload Input Document: POST /cases/{app_uid}/input-document

Uploads a new Input Document file to a specified case. Note that the logged-in user must either be currently assigned to work on the case or a Process Supervisor with permissions to access the Input Document; otherwise, this endpoint returns an HTTP status code of 302.

Permission:

Users must have the PM_CASES permission assigned to their role to perform this action.

Structure:

POST /api/1.0/{workspace}/cases/{app_uid}/input-document

URL Parameters:

Name Type Description
workspace String Workspace name
app_uid String Case UID

POST Fields:

Name Type Description
inp_doc_uid String The unique ID of the Input Document definition.
tas_uid String The unique ID of the task where the Input Document is a step.
app_doc_comment String A comment in plain text about the uploaded file.
form String The path to the file to upload to the ProcessMaker server. This path cannot be a web URL. If needing to use a file located on the internet, first download the file and save it as a local file to be uploaded.
If using PHP, be sure to place "@" before the path to include the file. If @ is not used, the status code will be 400 with the message "Bad Request: This filename does not exist!". If using PHP 5.5 or later, a new security feature has been added to prevent code injection attacks, so use a CurlFile object instead of @. See the code example below which uses phpversion() to check the PHP version before instantiating CurlFile(). The uploaded file will have the same filename. To rename the file, move it to a new file location before uploading it to this REST endpoint.

Result:

If the file was successfully uploaded, it returns an HTTP status code of 200 and a response object with information about the new Input Document file, such as:

{
   "app_doc_uid":         "43019952255dfa40100e0b7048036445",
   "app_doc_filename":    "companyVideo.ogv",
   "doc_uid":             "30967501355df8ce0132ac7027392886",
   "app_doc_version":     "1",
   "app_doc_create_date": "2015-08-27 19:57:52",
   "app_doc_create_user": "Doe, Bob (bob)",
   "app_doc_type":        "INPUT",
   "app_doc_index":       "3",
   "app_doc_link":        "cases/cases_ShowDocument?a=43019952255dfa40100e0b7048036445&v=1"
}
If an error occurs, an HTTP status code of 300 or greater is returned with a message object such as:
{
   "error":  {
      "code":    413,
      "message": "Request Entity Too Large: Uploaded file (companyVideo.ogv) is too big."
    }
}

Note: If using PHP, in order to send POST fields to REST endpoints which contain objects or arrays, the POST fields have to be encoded with the http_build_query() function. However, passing the filename through the http_build_query() function mangles it and this endpoint will return a status code of 400 and the message "Bad Request: This filename does not exist!". Either make a pmRestRequest() function which doesn't use the http_build_query() function or use code like the example below to upload the file.

Note: If the uploaded file is larger than the upload_max_filesize setting in the php.ini file on the ProcessMaker server, then the HTTP status code will be 413 with the error message "Request Entity Too Large: Uploaded file (filename) is too big.". If the uploaded file is larger than the post_max_size setting in the php.ini file on the ProcessMaker server, then the endpoint will return a status code and the message "Bad Request: `tas_uid` is required but missing".

Note: It is not possible to send a file to the POST cases/{app_uid}/input-document endpoint using JavaScript, because the JavaScript language is not designed to handle file uploads. If using JavaScript, then some server-side code will need to be added to handle file uploads. See the PHP code examples below.

PHP Example 1:

$oToken = pmRestLogin("IAIERTORPBHIJZXEPNSUANXLKYPKODJU", "71308091055cb7094026089092397336", "bob", "p4sSw0rd");

$inputDocId = '30967501355df8ce0132ac7027392886';
$taskId     = '39558947555df747738bc05034476159';
$caseId     = '46509787255df8bc70f2f17099023224';
$url        = 'http://'. $_SERVER['SERVER_NAME'] .':'. $_SERVER['SERVER_PORT'] . "/api/1.0/workflow/cases/$caseId/input-document";
$path     = '/home/user/companyVideo.ogv';

$aVars = array(
   'inp_doc_uid'     => $inputDocId,
   'tas_uid'         => $taskId,
   'app_doc_comment' => 'Promotional video for clients',
   'form'            => (phpversion() >= "5.5") ? new CurlFile($path) : '@' . $path
);

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Authorization: Bearer ' . $oToken->access_token));
curl_setopt($ch, CURLOPT_POSTFIELDS, $aVars);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$oResponse = json_decode(curl_exec($ch));
$httpStatus = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if ($httpStatus == 200) {
    $caseFileId = $oResponse->app_doc_uid;
}
elseif (is_object($oResponse) and isset($oResponse->error)) {
   print "Error code: {$oResponse->error->code}\n" .
         "Message: {$oResponse->error->message}\n";
}
else {
   print "Error code: $httpStatus";
}

PHP Example 2:

The following HTML form contains a file input field named "receipts[]" which allows multiple files to be selected and uploaded at the same time:

<html>
<form action="processFiles.php" enctype="multipart/form-data" method="post">
<p>
Select receipt file(s) to upload:<br>
<input type="file" name="receipts[]" id="receipts[]" multiple="multiple" size="40">
</p>
<p>
<input type="submit" value="Send">
</p>
</form>
</html>

When file(s) are selected and the above form is submitted, the $_FILES superglobal in PHP will contain information about the files which were uploaded to the "receipts[]" file field. For example, if two files were uploaded named "officeExpenses.jpg" and "inventoryList.xls", then $_FILES might contain:

$_FILES = array(
  "receipts" => array(
    "name" => array(
      "officeExpenses.jpg",
      "inventoryList.xls"
    ),
    "type" => array(
      "image/jpeg",
      "application/excel"
    ),
    "tmp_name" => array(
      "/tmp/phpuYgFXM",
      "/tmp/phpbiwPUZ"
    ),
    "error" => array(
      0,
      0
    ),
    "size" => array(
      11016,
      8962
    )
  )
);

In the same directory, the following processFiles.php file takes the files which were uploaded and sends them to the POST cases/{app_uid}/input-document endpoint:

$oToken = pmRestLogin("IAIERTORPBHIJZXEPNSUANXLKYPKODJU", "71308091055cb7094026089092397336", "bob", "p4sSw0rd");
if (empty($oToken) or isset($oToken->error))
  die("Error " . $oToken->error->code .': '. $oToken->error->message);

$inputDocId = '30967501355df8ce0132ac7027392886';
$taskId     = '39558947555df747738bc05034476159';
$caseId     = '46509787255df8bc70f2f17099023224';
$url        = 'http://'. $_SERVER['SERVER_NAME'] .':'. $_SERVER['SERVER_PORT'] . "/api/1.0/workflow/cases/$caseId/input-document";
$nFiles = count($_FILES['receipts']['name']);

for ($i = 0; $i < $nFiles; $i++) {
   $path = $_FILES['receipts']['tmp_name'][$i];
   $type = $_FILES['receipts']['type'][$i];
   $filename = $_FILES['receipts']['name'][$i];
   //rename file from temp name to real name:
   rename($path, sys_get_temp_dir() .'/'. $filename); //reverse \ for windows systems

   $aVars = array(
      'inp_doc_uid'     => $inputDocId,
      'tas_uid'         => $taskId,
      'app_doc_comment' => '',
      'form'            => (phpversion() >= "5.5") ? new CurlFile($path, $type) : '@'.$path
   );

   $ch = curl_init();
   curl_setopt($ch, CURLOPT_URL, $url);
   curl_setopt($ch, CURLOPT_HTTPHEADER, array('Authorization: Bearer ' . $oToken->access_token));
   curl_setopt($ch, CURLOPT_POSTFIELDS, $aVars);
   curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
   $oResponse = json_decode(curl_exec($ch));
   $httpStatus = curl_getinfo($ch, CURLINFO_HTTP_CODE);
   curl_close($ch);
   unlink(sys_get_temp_dir() .'/'. $filename); //delete file
}

Download an Input Document: GET /cases/{app_uid}/input-document/{app_doc_uid}/file?v={app_doc_version}

Download an uploaded document for a given case.

GET /api/1.0/{workspace}/cases/{app_uid}/input-document/{app_doc_uid}/file?v={app_doc_version}

Parameters:

Name Type Description
workspace String Workspace name.
app_uid String Case unique ID.
app_doc_uid String Input Document file's unique ID.
app_doc_version Integer (Optional)Version of the document, with counts starting from "1". If not included, the last version of the document will be downloaded.

Result:

If the file is successfully download, then the HTTP status code is set to 200 and there is no return object. Otherwise, the HTTP status code is set to 300 or greater and an error object is returned, such as:

{
    "error": {
        "code": 400,
        "message": "Bad Request: Error loading Document 30441284158458441472297061707703/3. This row doesn't exist!"
    }
}

Warning: If the disable_download_documents_session_validation flag is set to "0" or is not included in the env.ini file, a user is restricted from downloading the file if that person is not who uploaded the file. The user needs an Input Document process permission to download the file.

PHP example:
Download the uploaded input document file into the specified path.

$output_filename = "/opt/Receipt_1.png"; //Path where to download the document and name of the file
$host = "http://localhost/api/1.0/workflow/cases/8814697265845840e4a5452044453554/input-document/30441284158458441472297061707703/file?v=1";

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $host);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Authorization: Bearer 3904087b7b9a2bd192eb07babefcbfd9d06b2b19' ));
curl_setopt($ch, CURLOPT_VERBOSE, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_AUTOREFERER, false);
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
curl_setopt($ch, CURLOPT_HEADER, 0);
$result = curl_exec($ch);
curl_close($ch);

$fp = fopen($output_filename, 'w');
fwrite($fp, $result);
fclose($fp);

Delete Input Document: DELETE /cases/{app_uid}/{del_index}/input-document/{app_doc_uid}

Remove an Input Document file from a given case.

Permission:

Users must have the PM_CASES permission assigned to their role to perform this action.

Structure:

DELETE /api/1.0/{workspace}/cases/{app_uid}/{del_index}/input-document/{app_doc_uid}

Note: This endpoint does not delete the record of the Input Document file from the database, nor delete its file on the server's harddrive, stored at {install-directory}/shared/sites/{workspace}/files/XXX/XXX/XXX/XXXXXXXXXXXXXXXXXXXXXXX/{app_doc_uid}_{version}.{extension}, where XXX... is the app_uid (case ID). All it does change the value of the wf_{workspace}.APP_DOCUMENT.APP_DOC_STATUS field in the database from "ACTIVE" to "DELETED" so the file will not appear in the ProcessMaker interface. Therefore, the deletion of the file can be undone by updating the database record to change the status back to "ACTIVE".

URL Parameters:

Name Type Description
workspace String Workspace name
app_uid String Case UID
app_doc_uid String Document UID

Result:

If the file was successfully removed, then the HTTP status code is set to 200 and there is no return object. Otherwise, the HTTP status code is set to 300 or greater and an error object is returned, such as:

{
   "error": {
      "code": 400,
      "message": "Bad Request: This input document with inp_doc_uid: 97205510555e4a28a092857090745482 does not exist!"
   }
}

PHP example:

$caseId     = '44756102555c4e859630f43089650367';
$caseFileId = '97205510555e4a28a092857090745482';
$url = "/api/1.0/{workspace}/cases/$caseId/input-document/$caseFileId";
$oRet = pmRestRequest("DELETE", $url);

if ($oRet->status == 200) {
   print "Input Document file deleted.\n";
}