Zymonic API

From Zymonic

Instead of using the GUI, Zymonic can also be used as an API for other web applications using POST requests. The data can be in the format of both JSON and XML for compatibility with JS and other applications.


Example Requests[edit]

Typically a given request will include authentication for the user you want to run the request as, the system, whether the webservicemode request is targeting a Filter or Process, and then any details you optionally may want to pass on, such as SearchFields for a Filter or any details you want to save to a Table for a Process.

These work as they would in the GUI, so you don't need to provide every single field on a Filter or Process, only the ones you're actually submitting data for.

For instance, if we had a filter with a ZName of ts_filter_test with SearchFields for a user's name, postcode and email, we could send a search request like this:

Filter[edit]

XML

<ZymonicRequest>
  <Authentication>
    <username>your_username</username>
    <password>your_password</password>
  </Authentication>
  <ZymonicHeader>
    <authmode>db</authmode>
    <system>test_system</system>
    <webservicemode>filter</webservicemode>
  </ZymonicHeader>
  <ts_filter_test>
    <ZymonicHeader />
    <search>Show Results</search>
    <refresh_this_filter_mvs>true</refresh_this_filter_mvs>
    <search_field_button>Hide Search Fields</search_field_button>
    <results_per_page>100</results_per_page>
    <go_to_page>1</go_to_page>
    <ts_f_forename>John</ts_f_forename>
    <ts_f_surname>Doe</ts_f_surname>
    <ts_f_postcode>AB1 2CD</ts_f_postcode>
    <ts_f_email>johndoe9001@email.website</ts_f_email>
  </ts_filter_test>
</ZymonicRequest>

JSON

{  
  "Authentication":{  
    "username":"your_username",
    "password":"your_password"
  },
  "ZymonicHeader":{  
    "system":"test_system",
    "webservicemode":"filter",
    "debug":"false"
  },
  "ts_filter_test":{  
    "search":"Show Results",
    "tc_f_forename":"John",
    "tc_f_surname":"Doe",
    "tc_f_postcode":"AB1 2CD",
    "tc_f_email":"johndoe9001@email.website"
  }
}

Process[edit]

XML

<ZymonicRequest>
  <ZymonicHeader>
    <system>test_system</system>
    <webservicemode>process</webservicemode>
    <debug>false</debug>
  </ZymonicHeader>
  <test_system_process>
    <Transition>test_system_process_save</Transition>
    <test_system_process_field>66</test_system_process_field>
  </test_system_process>
  <Authentication>
    <Credentials record='ZZNEW'>
      <username>your_username</username>
      <password>your_password</password>
    </Credentials>
  </Authentication>
</ZymonicRequest>


JSON

{

 "Authentication":{  
   "username":"your_username",
   "password":"your_password"
 },
 "ZymonicHeader":{  
   "system":"test_system",
   "webservicemode":"process",
   "debug":"false"
 },
 "test_system_process":{  
   "Transition":"test_system_process_save",
   "test_system_process_field":"88",
 }

}


curl -k -d xmldata='<ZymonicRequest><ZymonicHeader><system>ztsm</system><webservicemode>filter</webservicemode><debug>false</debug></ZymonicHeader><cbos_su_barcodes_table_filter><search>Show Results</search><cbos_barcode_field_hidden>88888074</cbos_barcode_field_hidden><search_field_button>Hide Search Fields</search_field_button></cbos_su_barcodes_table_filter></ZymonicRequest>' https://md2.zednax.com/zymonicmp


You can submit these requests via any HTTP POST method available to you, for instance you can send them via curl like so, specifying the correct content type headers:

XML

curl -X POST -H "Content-Type: text/xml" -d '[your xml string here]' https://zymonic.site.address/zymonicmp

JSON

curl -X POST -H "Content-Type: application/json" -d '[your json string here]' https://zymonic.site.address/zymonicmp

Alternatively, instead of posting the requests with headers specifying the content type, you can specify json or xml mode with params instead:

XML

curl -X POST -d xmldata='[your xml string here]' https://zymonic.site.address/zymonicmp

JSON

curl -X POST -d jsondata='[your json string here]' https://zymonic.site.address/zymonicmp

Example Responses[edit]

After sending an API Request, you should expect to see a Response in the same format as the request you made. For our example above with the filter, we might expect to see something like this if there's only two matches for our search, with two different accounts registered to the same name, email and address:

XML

<Zymonic token="[session token here]">
  <ts_filter_test>
    <FilterResultCount group_ident="_ts_filter_test_nogroup">
      <Count>2</Count>
    </FilterResultCount>
    <report expanded="true" group_ident="no_group" group_level="0" has_headers="true" ident="_ts_filter_test_report" result_count="2">
      <navigation current_page="1" last_page="1">
      </navigation>
      <result>
        <ts_f_id>
          <Value>3</Value>
        </ts_f_id>
        <ts_f_forename>
          <Value>John</Value>
        </ts_f_forename>
        <ts_f_surname>
          <Value>Doe</Value>
        </ts_f_surname>
        <ts_f_postcode>
          <Value>AB1 2CD</Value>
        </ts_f_postcode>
        <ts_f_email>
          <Value>johndoe9001@email.website</Value>
        </ts_f_email>
        <ts_f_account_name>
          <Value>NoJohns9001</Value>
        </ts_f_account_name>
        <ts_f_memorable_phrase>
          <Value>Doe Or Doe Not There Is No Try</Value>
        </ts_f_memorable_phrase>
      </result>
      <result>
        <ts_f_id>
          <Value>16</Value>
        </ts_f_id>
        <ts_f_forename>
          <Value>John</Value>
        </ts_f_forename>
        <ts_f_surname>
          <Value>Doe</Value>
        </ts_f_surname>
        <ts_f_postcode>
          <Value>AB1 2CD</Value>
        </ts_f_postcode>
        <ts_f_email>
          <Value>johndoe9001@email.website</Value>
        </ts_f_email>
        <ts_f_account_name>
          <Value>TotallyNotJohnDoe</Value>
        </ts_f_account_name>
        <ts_f_memorable_phrase>
          <Value>These Are Not The Does You're Looking For</Value>
        </ts_f_memorable_phrase>
      </result>
    </report>
  </ts_filter_test>
</Zymonic>

JSON

{  
  "session_errors":[],
  "ts_filter_test":{  
    "report":{  
      "group_level":0,
      "navigation":{  
        "error":[],
        "last_page":1,
        "current_page":1
      },
      "result":[  
        {  
          "ts_f_id":{  
            "Value":{  
              "content":"3"
            },
            "output_error":[]
          },
          "ts_f_forename":{  
            "Value":{  
              "content":"John"
            },
            "output_error":[]
          },
          "ts_f_surname":{  
            "Value":{  
              "content":"Doe"
            },
            "output_error":[]
          },
          "ts_f_postcode":{  
            "Value":{  
              "content":"AB1 2CD"
            },
            "output_error":[]
          },
          "ts_f_email":{  
            "Value":{  
              "content":"johndoe9001@email.website"
            },
            "output_error":[]
          },
          "ts_f_account_name":{  
            "Value":{  
              "content":"NoJohns9001"
            },
            "output_error":[]
          },
          "ts_f_memorable_phrase":{  
            "Value":{  
              "content":"Doe Or Doe Not There Is No Try"
            },
            "output_error":[]
          },
        }
      ],
      "result":[  
        {  
          "ts_f_id":{  
            "Value":{  
              "content":"16"
            },
            "output_error":[]
          },
          "ts_f_forename":{  
            "Value":{  
              "content":"John"
            },
            "output_error":[]
          },
          "ts_f_surname":{  
            "Value":{  
              "content":"Doe"
            },
            "output_error":[]
          },
          "ts_f_postcode":{  
            "Value":{  
              "content":"AB1 2CD"
            },
            "output_error":[]
          },
          "ts_f_email":{  
            "Value":{  
              "content":"johndoe9001@email.website"
            },
            "output_error":[]
          },
          "ts_f_account_name":{  
            "Value":{  
              "content":"TotallyNotJohnDoe"
            },
            "output_error":[]
          },
          "ts_f_memorable_phrase":{  
            "Value":{  
              "content":"These Are Not The Does You're Looking For"
            },
            "output_error":[]
          },
        }
      ],
      "has_headers":"true",
      "result_count":2,
      "group_ident":"no_group",
      "expanded":"true",
      "ident":"_ts_filter_test_report"
    },
    "FilterResultCount":[  
      {  
        "group_ident":"_ts_filter_test_nogroup",
        "Count":{  
          "content":1
        }
      }
    ]
  },
  "json_mode":"true"
}


Error Responses[edit]

Not all API Requests will yield a successful result, see below for a few examples of Responses where there was a problem with the Request:

Example 1 - Invalid Password[edit]

XML Request

<ZymonicRequest>
  <ZymonicHeader>
    <system>test_system</system>
    <webservicemode>process</webservicemode>
    <debug>false</debug>
  </ZymonicHeader>
  <Authentication>
    <username>some_user</username>
    <password>some_pass</password>
  </Authentication>
</ZymonicRequest>

XML Response

<Zymonic token="[session token here]">
  <AuthFailed>true</AuthFailed>
  <AuthFailedMessage>Password Incorrect</AuthFailedMessage>
  <credentials sequence="1">
    <DisplayName>Username</DisplayName>
    <DisplaySize>30</DisplaySize>
    <MaximumLength>255</MaximumLength>
    <ZName>username</ZName>
  </credentials>
  <credentials sequence="2">
    <DisableAutocomplete>true</DisableAutocomplete>
    <DisplayName>Password</DisplayName>
    <DisplaySize>30</DisplaySize>
    <HiddenContent>true</HiddenContent>
    <MaximumLength>255</MaximumLength>
    <ZName>password</ZName>
  </credentials>
</Zymonic>

Most errors should be like the one above where the error message is fairly self-explanatory and explains which part of the request caused it to be rejected.

Example 2 - Missing or Incorrect System Name[edit]

JSON Request

{  
  "Authentication":{  
    "username":"superuser",
    "password":"some_secure_pw"
  },
  "ZymonicHeader":{  
    "system":"fake_sys",
    "webservicemode":"filter",
    "debug":"false"
  },
  "fs_p_order":{  
    "fs_f_order_cost":"15000.00",
    "fs_f_order_currency":"GBP",
    "fs_f_order_ref":"F4K30RD3R",
    "fs_f_order_contact_email":"support@email.site"
  }
}

HTTP Response

error Invalid or missing system name

Note that if the system is missing/invalid, your request is sufficiently formatted or the server is misconfigured you'll likely get a HTML web page response or plain text signifying a 422 (Invalid or missing system name) or 500 (Internal Server Error) response, instead of JSON/XML as you'd otherwise expect.

Example 3 - Field Validation[edit]

XML Request

<ZymonicRequest>
  <ZymonicHeader>
    <system>order_pnp</system>
    <webservicemode>process</webservicemode>
    <debug>false</debug>
  </ZymonicHeader>
  <Authentication>
    <username>api_tester</username>
    <password>i_can't_believe_it's_not_a_secure_password!</password>
  </Authentication>
  <pnp_p_simple_order>
    <Transition>pnp_simple_start</Transition>
    <pnp_fm_simple_order_request record='ZZNEW'>
      <pnp_f_simple_site_name>West Branch 02</pnp_f_simple_site_name>
      <pnp_f_simple_customer_title>Mrs</pnp_f_simple_customer_title>
      <pnp_f_simple_customer_forename>Testanne</pnp_f_simple_customer_forename>
      <pnp_f_simple_customer_surname>User</pnp_f_simple_customer_surname>
      <pnp_f_simple_customer_street>No Way!?</pnp_f_simple_customer_street>
      <pnp_f_simple_customer_postcode>NG! +ZZ</pnp_f_simple_customer_postcode>
      <pnp_f_simple_short_code>9630</pnp_f_simple_short_code>
    </pnp_fm_one_shot_order_request>
  </pnp_p_simple_order>
</ZymonicRequest>

XML Response

<Zymonic token="[session token here]">
  <error>
    <code>pnp_p_simple_order.pnp_simple_start</code>
    <description>Form Validation or Action Failed</description>
  </error>
  <error>
    <code>pnp_p_simple_order.pnp_f_simple_short_code</code>
    <description>Short Code is too long; allowed: 3, actual: 4</description>
  </error>
  <error>
    <code>pnp_p_simple_order.pnp_f_simple_short_code</code>
    <description>Short Code is required.</description>
  </error>
  <error>
    <code>pnp_p_simple_order.pnp_f_simple_customer_street</code>
    <description>Street contains disallowed characters : EXCLAMATION MARK, QUESTION MARK</description>
  </error>
  <error>
    <code>pnp_p_simple_order.pnp_f_simple_customer_street</code>
    <description>Street is required.</description>
  </error>
  <error>
    <code>pnp_p_simple_order.pnp_f_simple_customer_postcode</code>
    <description>Postcode contains disallowed characters : EXCLAMATION MARK, PLUS SIGN</description>
  </error>
  <error>
    <code>pnp_p_simple_order.pnp_f_simple_customer_postcode</code>
    <description>Postcode is required.</description>
  </error>
  <error>
    <code>pnp_p_simple_order.pnp_f_simple_customer_email</code>
    <description>Email is required.</description>
  </error>
  <pnp_p_simple_order process_id="112659">
    <pnp_fm_simple_order_request>
      <navigation current_page="1" error="" last_page="1"/>
      <record new_record="true">
        <pnp_f_simple_customer_email>
          <Value/>
          <input_error error="Email is required." translated="true" type="required"/>
        </pnp_f_simple_customer_email>
        <pnp_f_simple_customer_forename>
          <Value>Testanne</Value>
        </pnp_f_simple_customer_forename>
        <pnp_f_simple_customer_postcode>
          <Value/>
          <input_error error="Postcode contains disallowed characters : EXCLAMATION MARK, PLUS SIGN" illegal_chars="true" joined_char_list="EXCLAMATION MARK, PLUS SIGN">
            <character_list>EXCLAMATION MARK</character_list>
            <character_list>PLUS SIGN</character_list>
          </input_error>
          <input_error error="Postcode is required." translated="true" type="required"/>
        </pnp_f_simple_customer_postcode>
        <pnp_f_simple_customer_street>
          <Value/>
          <input_error error="Street contains disallowed characters : EXCLAMATION MARK, QUESTION MARK" illegal_chars="true" joined_char_list="EXCLAMATION MARK, QUESTION MARK">
            <character_list>EXCLAMATION MARK</character_list>
            <character_list>QUESTION MARK</character_list>
          </input_error>
          <input_error error="Street is required." translated="true" type="required"/>
        </pnp_f_simple_customer_street>
        <pnp_f_simple_customer_sub_building>
          <Value/>
        </pnp_f_simple_customer_sub_building>
        <pnp_f_simple_customer_surname>
          <Value>User</Value>
        </pnp_f_simple_customer_surname>
        <pnp_f_simple_customer_title>
          <Value>Mrs</Value>
        </pnp_f_simple_customer_title>
        <pnp_f_simple_delivery_method>
          <Value/>
          <input_error actual_length="4" error="Short Code is too long; allowed: 3, actual: 4" maximum_length="3" too_long="true"/>
          <input_error error="Short Code is required." translated="true" type="required"/>
        </pnp_f_simple_delivery_method>
      </record>
    </pnp_fm_simple_order_request>
    <pnp_simple_start/>
    <pnp_s_simple_order_start Deleted=""/>
    <transitions>
      <pnp_simple_start enabled="true" type="Transition">
        <DisplayName>Send Order</DisplayName>
      </pnp_simple_start>
    </transitions>
  </pnp_p_simple_order>
</Zymonic>

In this example, several fields on the Process were marked as Required and thus we cannot submit the Transition without ensuring they're all filled in. In addition, some had special characters that were not allowed or exceeded the maximum character length. Hopefully each example error message here is clear, but this helps illustrate that when dealing with API Requests you need some mechanism to handle the responses and log any errors.

Example 4 - Valid System, Non Existent Filter/Process ZName[edit]

JSON Request

{  
  "Authentication":{  
    "username":"validUser",
    "password":"1qazxsw23edcvfr4"
  },
  "ZymonicHeader":{  
    "system":"bank_one_system",
    "webservicemode":"filter",
    "debug":"false"
  },
  "bank_two_exclusive_currency_filter":{  
    "search":"Show Results",
    "bank_two_f_swift":"JPY",
    "bank_two_f_denom":"1000",
  }
}

JSON Response

{  
    "token":"[session token]",
    "session_errors":[  

    ],
    "error":{  
        "message":{  
            "content":"Unfortunately a fault has occurred, the details of the problem have \nbeen sent to the development team and it will be investigated. If you \nwish to track the status of the issue, find out more information or have \nany other query then please contact the site owner, quoting reference: VIIORJ306Y"
        },
        "reference":"VIIORJ306Y"
    },
    "json_mode":"true"
}

In this case we have specified a system that does exist and correct credentials, but we're searching for a bank_two field on a bank_one system. If we check the error file at /var/errors/ with that reference we see that the filter wasn't found on our system: <ErrorMessage>object not found: Filter ZName bank_two_exclusive_currency_filter</ErrorMessage>

There are other cases which could produce a system fault but this is likely the most common mistake to make.

While we want to avoid system faults in general, this applies especially to API requests as with the other errors there's some indication of what might have gone wrong, but with these errors third parties have no ability to diagnose the issue besides contacting the providers of the zymonic system with the aforementioned reference code.

Example 5 - Malformed XML/JSON[edit]

XML Response

<Zymonic>
  <session_errors>Invalid incoming XML: :15: parser error : Opening and ending tag mismatch: ec_f_forename2 line 15 and ec_f_forename
        <ec_f_forename2>John</ec_f_forename>
                                            ^
 - See error log UXMDMG7VFD for more details</session_errors>
</Zymonic>

JSON Response

{  
    "json_mode":"true",
    "session_errors":[  
        "Invalid incoming JSON: malformed JSON string, neither tag, array, object, number, string or atom, at character offset 368 (before "John",\\n        "ec_...") at /usr/local/lib64/perl5/5.24.3/Zymonic/Session.pm line 1345.\n - See error log KVMUQQOCU0 for more details"
    ]
}

For the two above responses (or anything that resembles them) the issue is not anything about the Zymonic API specifically, but general XML and JSON parsing errors instead, such as mismatched tags, use of certain unescaped special characters or typos in the formatting like using "-" instead of ":". Try running your request through an XML or JSON validator if the response seems unclear.

Sample Requests with JavaScript[edit]

The following requests will have the same output from Zymonic, but one of them will return JSON and the other XML.

XML

      let xmlRequest = '<ZymonicRequest>' +
          '<Authentication>' +
            '<username>' + document.getElementById("Username").value + '</username>' +
            '<password>' + document.getElementById("Password").value + '</password>' +
          '</Authentication>' +
          '<ZymonicHeader>' +
             '<authmode>db</authmode>' +
             '<system>' + document.getElementById("System").value + '</system>' +
             '<webservicemode>filter</webservicemode>' +
          '</ZymonicHeader>' +
          '<ts_filter_test>' +
             '<ZymonicHeader/>' +
             '<search>Show Results</search>' +
             '<refresh_this_filter_mvs>true</refresh_this_filter_mvs>' +
             '<search_field_button>Hide Search Fields</search_field_button>' +
             '<results_per_page>100</results_per_page>' +
             '<go_to_page>1</go_to_page>' +
             '<ts_f_forename>' + document.getElementById("Name").value + '</ts_f_forename>' +
             '<ts_f_surname>' + document.getElementById("Surname").value + '</ts_f_surname>' +
             '<ts_f_postcode>' + document.getElementById("Postcode").value + '</ts_f_postcode>' +
             '<ts_f_email>' + document.getElementById("Email").value + '</ts_f_email>' +
          '</ts_filter_test>' +
        '</ZymonicRequest>';

      $.ajax("/zymonicmp", {
        type: "POST",
        data: xmlRequest,
        datatype: "xml",
        contentType: "text/xml",
        success: function(response){
          // Decide what to do when the browser can communicate with the server.
        },
        error: function(xhr, textStatus, errorThrown) {
          // Decide what to do when the browser cannot communicate with the server.
        }
      });

JSON

      let formData = {
        "Authentication" : {
          "username" : document.getElementById("Username").value,
          "password" : document.getElementById("Password").value
        },
        "ZymonicHeader" : {
          "system" : document.getElementById("System").value,
          "webservicemode" : "filter",
          "debug" : "false"
        },
        "ts_filter_test": {
          "search": "Show Results",
          "ts_f_forename" : document.getElementById("Name").value,
          "ts_f_surname" : document.getElementById("Surname").value,
          "ts_f_postcode" : document.getElementById("Postcode").value,
          "ts_f_email" : document.getElementById("Email").value,
        }
      };
      let jsonRequest = JSON.stringify(formData);

      $.ajax("/zymonicmp", {
        type: "POST",
        data: jsonRequest,
        datatype: "json",
        contentType: "application/json",
        success: function(response){
          // Decide what to do when the browser can communicate with the server.
        },
        error: function(xhr, textStatus, errorThrown) {
          // Decide what to do when the browser cannot communicate with the server.
        }
      });