This site contains the documentation that is relevant to older WSO2 product versions and offerings.
For the latest WSO2 documentation, visit https://wso2.com/documentation/.

Appointment Creation in Cliniko

The second use case in the Cliniko business scenario is appointment creation. This page describes the relevant tasks and the operations you use in the Cliniko connector and the other ESB connectors. 

Overview 

The flow for appointment creation is illustrated in the following diagram. The ESB connectors for LiveChat will be used to connect to each service.

  1. Retrieve all patients from the Cliniko API using the listPatients operation.
  2. Retrieve appointment types from the Cliniko API using the getAppointmentType operation.
  3. Retrieve all the tickets tagged as 'Appointments' daily from the LiveChat API using the listTickets operation.
  4. If the patient does not exist, create the patient in the Cliniko API using the createPatient operation.
  5. Retrieve practitioner from the Cliniko API using the getPractitioner operation.
  6. Retrieve the business ID from the Cliniko API using the listBusinesses operation.
  7. Retrieve the availability of the practitioner from the Cliniko API using the getNextAvailableTime operation.
  8. Retrieve appointments for a patient from the Cliniko API using the listAppointments operation in order to check if there any new appointments for the retrieved practitioner.
  9. Create an appointment for the patient in the Cliniko API using the createAppointment operation.
  10. Create a calendar event for the appointment in the Google Calendar API using the createEvent operation.
LiveChat operations
Cliniko operations
Google Calendar operations

Prerequisites

  • A tag named 'Appointments' should be created in LiveChat.
  • The ticket subject should contain the practitioner ID of Cliniko for whom the appointment should be created followed by the subject. Please adhere to the following format:

    e.g. Red Eye (Practitioner ID:41213)

  • The requester name of the ticket should be given in the format where the first name and the last name is separated by a space:

    e.g. Elena Gilbert

  • The time zones of the Cliniko API and Google Calendar API should be the same.

Samples
Sample Template for creating appointments in Cliniko and events in Google Calendar
<?xml version="1.0" encoding="UTF-8"?>
<!--
   Copyright (c) 2005-2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
   WSO2 Inc. licenses this file to you under the Apache License,
   Version 2.0 (the "License"); you may not use this file except
   in compliance with the License.
   You may obtain a copy of the License at
   http://www.apache.org/licenses/LICENSE-2.0
   Unless required by applicable law or agreed to in writing,
   software distributed under the License is distributed on an
   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
   KIND, either express or implied.  See the License for the
   specific language governing permissions and limitations
   under the License.
-->
<!-- This template creates appointments in cliniko and events in Google Calendar -->
<template xmlns="http://ws.apache.org/ns/synapse" name="createAppointments">
   <!--Cliniko parameters-->
   <parameter name="cliniko.apiKey" description="Encrypted alphanumeric string to authenticate the cliniko credentials." />
   <parameter name="cliniko.apiUrl" description="The cliniko API URL." />
   <parameter name="cliniko.patientId" description="ID of the cliniko patient." />
   <parameter name="cliniko.practionerId" description="ID of the cliniko practitioner." />
   <parameter name="cliniko.appointmentTypeId" description="ID of the cliniko appointment type." />
   <parameter name="cliniko.appointmentNote" description="Note of the appointment." />
   <parameter name="cliniko.accountName" description="Name of the cliniko account." />
   
   <!-- GoogleCalender parameters-->
   <parameter name="googlecalendar.accessToken" description="Encrypted alphanumeric string to authenticate the googlecalendar credentials." />
   <parameter name="googlecalendar.apiUrl" description="The googlecalendar API URL." />
   <parameter name="googlecalendar.calendarId" description="The ID of the common calender." />
   
   <!-- Common parameters-->
   <parameter name="shared.timeZone" description="Time zone in which the application runs." />
   <parameter name="common.id" description="ID of the resource from the appointment details are taken." />
   
   <sequence>
      <property name="cliniko.apiKey" expression="$func:cliniko.apiKey" />
      <property name="cliniko.apiUrl" expression="$func:cliniko.apiUrl" />
      <property name="cliniko.patientId" expression="$func:cliniko.patientId" />
      <property name="cliniko.practionerId" expression="$func:cliniko.practionerId" />
      <property name="cliniko.appointmentTypeId" expression="$func:cliniko.appointmentTypeId" />
      <property name="cliniko.appointmentNote" expression="$func:cliniko.appointmentNote" />
      <property name="cliniko.accountName" expression="$func:cliniko.accountName" />
      <property name="common.id" expression="$func:common.id" />
      <property name="googlecalendar.accessToken" expression="$func:googlecalendar.accessToken" />
      <property name="googlecalendar.apiUrl" expression="$func:googlecalendar.apiUrl" />
      <property name="googlecalendar.calendarId" expression="$func:googlecalendar.calendarId" />
      <property name="shared.timeZone" expression="$func:shared.timeZone" />
   
	  <!--Call cliniko connector getPractitioner method to get practitioner  -->
      <cliniko.init>
         <apiUrl>{$ctx:cliniko.apiUrl}</apiUrl>
         <apiKey>{$ctx:cliniko.apiKey}</apiKey>
      </cliniko.init>
      <cliniko.getPractitioner>
         <practitionerId>{$ctx:cliniko.practionerId}</practitionerId>
      </cliniko.getPractitioner>
      
	  <!-- Get the response status. -->
      <property name="responseStatus" expression="$axis2:HTTP_SC" />
      
	  <!-- START: Proceed only if the getPractitioner call is successful. -->
      <filter xpath="get-property('responseStatus') != 200">
         <then>
            <!-- Append an error message to be sent to the user. -->
            <property name="cliniko.errorResponse" expression="json-eval($)" />
            <call-template target="responseHandlerTemplate">
               <with-param name="activity" value="cliniko_getPractitioner" />
               <with-param name="id" value="{$ctx:id.empty}" />
               <with-param name="status" value="error" />
               <with-param name="message" value="The appointment has not been created since the practitioner ID is not given." />
            </call-template>
         </then>
         <else>
            <property name="uri.var.cliniko.user" expression="json-eval($.user.links.self)" />
            
			<!--Get the email address of the practitioner using the getUser API method -->
            <header name="Accept" value="application/json" scope="transport" />
            <header name="Content-Type" value="application/json" scope="transport" />
            <header name="Authorization" expression="fn:concat('Basic ', base64Encode(fn:concat(get-property('cliniko.apiKey'), ':')))" scope="transport" />
            <call>
               <endpoint>
                  <http method="get" uri-template="{uri.var.cliniko.user}" />
               </endpoint>
            </call>
            <property name="cliniko.practitionerEmail" expression="json-eval($.email)" />
            
			<!--Call cliniko connector listBusinesses method to get the business ID  -->
            <cliniko.init>
               <apiUrl>{$ctx:cliniko.apiUrl}</apiUrl>
               <apiKey>{$ctx:cliniko.apiKey}</apiKey>
            </cliniko.init>
            <cliniko.listBusinesses />
            <property name="cliniko.businessId" expression="json-eval($.businesses[0].id)" />
            
			<!--Call cliniko connector getNextAvailableTime method to get the availability of the practitioner  -->
            <cliniko.init>
               <apiUrl>{$ctx:cliniko.apiUrl}</apiUrl>
               <apiKey>{$ctx:cliniko.apiKey}</apiKey>
            </cliniko.init>
            <cliniko.getNextAvailableTime>
               <practitionerId>{$ctx:cliniko.practionerId}</practitionerId>
               <appointmentTypeId>{$ctx:cliniko.appointmentTypeId}</appointmentTypeId>
               <businessId>{$ctx:cliniko.businessId}</businessId>
            </cliniko.getNextAvailableTime>
            <property name="cliniko.appointmentStart" expression="json-eval($.appointment_start)" />
            <property name="uri.var.urlQuery" action="remove" />
            <sequence key="removeResponseHeaders" />
            
			<!--Call cliniko connector listAppointments method to list appointments for a patient -->
            <cliniko.init>
               <apiUrl>{$ctx:cliniko.apiUrl}</apiUrl>
               <apiKey>{$ctx:cliniko.apiKey}</apiKey>
            </cliniko.init>
            <cliniko.listAppointments>
               <patientId>{$ctx:cliniko.patientId}</patientId>
            </cliniko.listAppointments>
            <property name="cliniko.appointmentCount" expression="//appointments" />
            
			<!-- START: Proceed only if there is at least one appointment -->
            <filter xpath="get-property('cliniko.appointmentCount') != 0.0">
               <then>
                  <!--Check the possibility of creating new appointments to the patient with the required practitioner-->
                  <script language="js"><![CDATA[payload = mc.getPayloadJSON();
						 var appointmentArray = payload.appointments;
						 var requestPractioner = ''+mc.getProperty('cliniko.practionerId');
						 var nextTime = mc.getProperty('cliniko.appointmentStart');       
						 
						 var proceed = 0;
						  
						 for(var i=0;i<appointmentArray.length;i++) {
							var practitionerUrl = ''+appointmentArray[i].practitioner.links.self;
							var practionerId=practitionerUrl.substring(practitionerUrl.lastIndexOf('/') + 1);
							var cancelTime = appointmentArray[i].cancellation_time;
							if(cancelTime == null) {
								var endTime = appointmentArray[i].appointment_end;
								 var startTime = appointmentArray[i].appointment_start;
								if(practionerId == requestPractioner) {
									var sdf = java.text.SimpleDateFormat.getInstance();
						   
									sdf= new java.text.SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
									sdf.setTimeZone(java.util.TimeZone.getTimeZone("UTC"));
									var currentTime = sdf.format(new java.util.Date());
								   
									if(endTime>currentTime) {
										proceed = 1;
										mc.setProperty('cliniko.newAppointments',"true");
										break;
									}
								} 
								else {
									if(startTime<=nextTime && endTime>=nextTime) {
										mc.setProperty('cliniko.newPractitionerApp',"true");
										break;
									}	
								}
							}
						 }
						 if(proceed == 0) {
							 var timeZone = mc.getProperty('shared.timeZone');
							 var hours = parseInt((timeZone.split(':')[0])*60);
							 var mins = parseInt(timeZone.split(':')[1]);
							 var timeGap = hours+mins;
							 var timeFormat = "yyyy-MM-dd'T'HH:mm:ss";
							 var newStartTime = ''+new java.text.SimpleDateFormat(timeFormat).format(new java.util.Date(new java.text.SimpleDateFormat(timeFormat).parse(nextTime).getTime() + timeGap*60*1000))+timeZone;
							 var newEndTime = new java.text.SimpleDateFormat(timeFormat).format(new java.util.Date(new java.text.SimpleDateFormat(timeFormat).parse(newStartTime).getTime() + 30*60*1000))+timeZone;
							 
							  mc.setProperty('cliniko.appointmentEndTime',newEndTime);
							  mc.setProperty('cliniko.appointmentStartTime',newStartTime);
						 }
					  ]]>
					</script>
               </then>
            </filter>
            <!-- END: Proceed only if there is at least one appointment -->
			
            <!-- START: Process only if there are no new appointments for the patient with the given practitioner -->
            <filter source="boolean(get-property('cliniko.newAppointments'))" regex="false">
               <then>
                  
				  <!--Call cliniko connector createAppointment method to create an appointment  -->
                  <cliniko.init>
                     <apiUrl>{$ctx:cliniko.apiUrl}</apiUrl>
                     <apiKey>{$ctx:cliniko.apiKey}</apiKey>
                  </cliniko.init>
                  <cliniko.createAppointment>
                     <appointmentEndTime>{$ctx:cliniko.appointmentEndTime}</appointmentEndTime>
                     <appointmentStartTime>{$ctx:cliniko.appointmentStartTime}</appointmentStartTime>
                     <notes>{$ctx:cliniko.appointmentNote}</notes>
                     <patientId>{$ctx:cliniko.patientId}</patientId>
                     <practitionerId>{$ctx:cliniko.practionerId}</practitionerId>
                     <appointmentTypeId>{$ctx:cliniko.appointmentTypeId}</appointmentTypeId>
                     <businessId>{$ctx:cliniko.businessId}</businessId>
                  </cliniko.createAppointment>
                  <property name="cliniko.appointmentId" expression="json-eval($.id)" />
                  
				  <!-- START: Append the response message according to the createAppointment response -->
                  <filter source="boolean(get-property('cliniko.appointmentId'))" regex="false">
                     <then>
                        <property name="id" expression="fn:concat('resource_id:',get-property('common.id'),',cliniko_patientId:',get-property('cliniko.patientId'))" />
                        <property name="status" value="error" />
                        <property name="message" expression="json-eval($)" />
                        <!--Call the responseHandler template-->
                        <call-template target="responseHandlerTemplate">
                           <with-param name="activity" value="cliniko_createAppointment" />
                           <with-param name="id" value="{$ctx:id}" />
                           <with-param name="status" value="{$ctx:status}" />
                           <with-param name="message" value="{$ctx:message}" />
                        </call-template>
                     </then>
                     <else>
                        <!-- START: Append the response message according to the the time overlapping of the appointments of patients -->
                        <filter source="boolean(get-property('cliniko.newPractitionerApp'))" regex="true">
                           <then>
                              <property name="id" expression="fn:concat('resource_id:',get-property('common.id'),',cliniko_patientId:',get-property('cliniko.patientId'),',cliniko_appointmentId:',get-property('cliniko.appointmentId'))" />
                              <property name="status" value="success" />
                              <property name="message" value="An appointment has been successfully created. But there is a time overlap." />
                              <!--Call the responseHandler template-->
                              <call-template target="responseHandlerTemplate">
                                 <with-param name="activity" value="cliniko_createAppointment" />
                                 <with-param name="id" value="{$ctx:id}" />
                                 <with-param name="status" value="{$ctx:status}" />
                                 <with-param name="message" value="{$ctx:message}" />
                              </call-template>
                           </then>
                           <else>
                              <property name="id" expression="fn:concat('resource_id:',get-property('common.id'),',cliniko_patientId:',get-property('cliniko.patientId'),',cliniko_appointmentId:',get-property('cliniko.appointmentId'))" />
                              <property name="status" value="success" />
                              <property name="message" value="An appointment has been successfully created." />
                              <!--Call the responseHandler template-->
                              <call-template target="responseHandlerTemplate">
                                 <with-param name="activity" value="cliniko_createAppointment" />
                                 <with-param name="id" value="{$ctx:id}" />
                                 <with-param name="status" value="{$ctx:status}" />
                                 <with-param name="message" value="{$ctx:message}" />
                              </call-template>
                              
							  <property name="googlecalendar.attendees" expression="fn:concat('[{&quot;email&quot;:&quot;',get-property('cliniko.practitionerEmail'),'&quot;}]')" />
                              <property name="googlecalendar.description" expression="fn:concat('Appointment :',get-property('cliniko.appointmentNote'))" />
                              <property name="googlecalendar.summary" expression="fn:concat('Appointment - ',get-property('cliniko.accountName'))" />
                              
							  <payloadFactory media-type="json">
                                 <format>{
									  "start": {
										 "dateTime": "$1"
									  },
									  "end": {
										 "dateTime": "$2"
									  }
								   }</format>
                                 <args>
                                    <arg expression="get-property('cliniko.appointmentStartTime')" />
                                    <arg expression="get-property('cliniko.appointmentEndTime')" />
                                 </args>
                              </payloadFactory>
                              <property name="googlecalendar.eventStart" expression="json-eval($.start)" />
                              <property name="googlecalendar.eventEnd" expression="json-eval($.end)" />
                              
							  <!--Call googlecalendar connector createEvent for the appointment  -->
                              <googlecalendar.init>
                                 <apiUrl>{$ctx:googlecalendar.apiUrl}</apiUrl>
                                 <accessToken>{$ctx:googlecalendar.accessToken}</accessToken>
                              </googlecalendar.init>
                              <googlecalendar.createEvent>
                                 <calendarId>{$ctx:googlecalendar.calendarId}</calendarId>
                                 <description>{$ctx:googlecalendar.description}</description>
                                 <summary>{$ctx:googlecalendar.summary}</summary>
                                 <start>{$ctx:googlecalendar.eventStart}</start>
                                 <end>{$ctx:googlecalendar.eventEnd}</end>
                                 <attendees>{$ctx:googlecalendar.attendees}</attendees>
                                 <sendNotifications>true</sendNotifications>
                              </googlecalendar.createEvent>
                              <property name="googleCalendar.eventId" expression="json-eval($.id)" />
                              
							  <!-- START: Append the response message according to the createEvent response -->
                              <filter source="boolean(get-property('googleCalendar.eventId'))" regex="false">
                                 <then>
                                    <property name="id" expression="fn:concat('resource_id:',get-property('common.id'),',cliniko_appointmentId:',get-property('cliniko.appointmentId'))" />
                                    <property name="status" value="error" />
                                    <property name="message" expression="json-eval($)" />
                                 </then>
                                 <else>
                                    <property name="id" expression="fn:concat('resource_id:',get-property('common.id'),',cliniko_appointmentId:',get-property('cliniko.appointmentId'),',googlecalendar_eventId:',get-property('googleCalendar.eventId'))" />
                                    <property name="status" value="success" />
                                    <property name="message" value="A calendar event has been successfully created for the practitioner." />
                                 </else>
                              </filter>
                              <call-template target="responseHandlerTemplate">
                                 <with-param name="id" value="{$ctx:id}" />
                                 <with-param name="activity" value="googleCalendar_createEvent" />
                                 <with-param name="status" value="{$ctx:status}" />
                                 <with-param name="message" value="{$ctx:message}" />
                              </call-template>
                           </else>
                        </filter>
                        <!-- END: Append the response message according to the the time overlapping of the appointments of patients -->
                     </else>
                  </filter>
                  <!-- END: Append the response message according to the createAppointment response -->
               </then>
            </filter>
            <!-- END: Process only if there are no new appointments for the patient with the given practitioner -->
         </else>
      </filter>
      <!-- END: Proceed only if the getPractitioner call is successful. -->
   </sequence>
</template>
Sample Proxy for retrieving daily tickets from LiveChat which are tagged as ‘Appointments’, creating the ticket requester as a patient in Cliniko if the patient does not exist, creating an appointment for the patient in Cliniko under the practitioner givein in the LiveChat ticket and creating an event in the common Google Calendar and adding the particular practitioner as an attendee for the created event
<?xml version="1.0" encoding="UTF-8"?>
<!--
   Copyright (c) 2005-2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
   WSO2 Inc. licenses this file to you under the Apache License,
   Version 2.0 (the "License"); you may not use this file except
   in compliance with the License.
   You may obtain a copy of the License at
   http://www.apache.org/licenses/LICENSE-2.0
   Unless required by applicable law or agreed to in writing,
   software distributed under the License is distributed on an
   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
   KIND, either express or implied. See the License for the
   specific language governing permissions and limitations
   under the License.
-->
<!--This scenario will create appointments in Cliniko and events in Google Calendar using tickets in Livechat. -->
<proxy xmlns="http://ws.apache.org/ns/synapse" name="cliniko_retrieveTicketsAndCreateAppointments" transports="https,http" statistics="disable" trace="disable" startOnLoad="true">
   <target>
      <inSequence onError="faultHandlerSeq">
        <!-- Cliniko Properties -->
         <property name="cliniko.apiUrl" expression="get-property('registry', 'connectors/Cliniko/apiUrl')" />
         <property name="cliniko.apiKey" expression="get-property('registry', 'connectors/Cliniko/apiKey')" />
         <property name="cliniko.appointmentType" expression="json-eval($.cliniko.appointmentType)" />
         <!-- Livechat Properties -->
         <property name="livechat.apiUrl" expression="get-property('registry', 'connectors/Livechat/apiUrl')" />
         <property name="livechat.login" expression="get-property('registry', 'connectors/Livechat/login')" />
         <property name="livechat.apiKey" expression="get-property('registry', 'connectors/Livechat/apiKey')" />
         <!-- GoogleCalendar Properties -->
         <property name="googlecalendar.apiUrl" expression="get-property('registry', 'connectors/Googlecalendar/apiUrl')" />
         <property name="googlecalendar.accessToken" expression="get-property('registry', 'connectors/Googlecalendar/accessToken')" />
         <property name="googlecalendar.calendarId" expression="json-eval($.googlecalendar.calendarId)" />
          <!-- Shared Properties -->
         <property name="shared.timeZone" expression="json-eval($.shared.timeZone)" />
         
         <!-- Operation scoped properties -->
         <property name="responseString" value="" scope="operation" />
         <!--Call cliniko connector listPatients method to list all the patients -->
         <cliniko.init>
            <apiUrl>{$ctx:cliniko.apiUrl}</apiUrl>
            <apiKey>{$ctx:cliniko.apiKey}</apiKey>
         </cliniko.init>
         <cliniko.listPatients/>
         <!-- Get the response status. -->
         <property name="responseStatus" expression="$axis2:HTTP_SC" />
         <!-- START: Proceed only if the call is successful. -->
         <filter xpath="get-property('responseStatus') != 200">
            <then>
               <!-- Append an error message to be sent to the user. -->
               <property name="error" expression="json-eval($)" />
               <call-template target="responseHandlerTemplate">
                  <with-param name="activity" value="cliniko_listPatients" />
                  <with-param name="id" value="{$ctx:id.empty}" />
                  <with-param name="status" value="error" />
                  <with-param name="message" value="{$ctx:error}" />
               </call-template>
               <loopback />
            </then>
         </filter>
         <!-- END: Proceed only if the call is successful. -->
         <!--Construct an object to store the patient's email and the ID-->
         <script language="js">
            <![CDATA[
               payload = mc.getPayloadJSON();
			   var patientArray = payload.patients;
               var patientObj = {};
               for(var i=0;i<patientArray.length;i++) {
                  patientObj[patientArray[i].email] = patientArray[i].id;
               }
               for(var key in patientObj) {
                  var id = patientObj[key];
               }
               
                mc.setPayloadJSON(patientObj);
               
            ]]>
         </script>
         
         <property name="cliniko.patientObject" expression="json-eval($.)" />
         
         <!--Call cliniko connector getAppointmentType method to get appointment types -->
         <cliniko.init>
            <apiUrl>{$ctx:cliniko.apiUrl}</apiUrl>
            <apiKey>{$ctx:cliniko.apiKey}</apiKey>
         </cliniko.init>
         <cliniko.getAppointmentType/>
         
         <!--Get the ID of the given appointmentType-->
         <script language="js">
            <![CDATA[
               payload = mc.getPayloadJSON();
			   var appointmentTypeArray = payload.appointment_types;
               var appType = mc.getProperty('cliniko.appointmentType');
               for(var i=0;i<appointmentTypeArray.length;i++) {
                  var name = appointmentTypeArray[i].name;
                  if(appType.toLowerCase() == name.toLowerCase()) {
                     var id = ''+appointmentTypeArray[i].id;
                     mc.setProperty('cliniko.appointmentTypeId',id);
                     break;
                  }
               }
               mc.setProperty('livechat.dateFrom',new java.text.SimpleDateFormat('yyyy-MM-dd').format(new java.util.Date()));
            ]]>
         </script>
         
         <!-- START: Proceed only if the appointmentType is existing. -->
         <filter source="boolean(get-property('cliniko.appointmentTypeId') )" regex="false">
            <then>
               <property name="id" value="{}" />
               <property name="status" value="skipped" />
               <property name="message" value="The given Appointment Type is invalid." />
               <call-template target="responseHandlerTemplate">
                  <with-param name="id" value="{$ctx:id}" />
                  <with-param name="activity" value="cliniko_listAppointmentTypes" />
                  <with-param name="status" value="{$ctx:status}" />
                  <with-param name="message" value="{$ctx:message}" />
               </call-template>
               <loopback />
            </then>
         </filter>
         <!-- END: Proceed only if the appointmentType is existing. -->
         
         <!--Extract cliniko_getSettingsSeq to get details of cliniko  account-->
         <sequence key="cliniko_getSettingsSeq" />
         
         <!--Call livechat connector listTickets method to list all the tickets tagged as 'Appointments'-->
         <livechat.init>
            <apiUrl>{$ctx:livechat.apiUrl}</apiUrl>
            <login>{$ctx:livechat.login}</login>
            <apiKey>{$ctx:livechat.apiKey}</apiKey>
         </livechat.init>
         <livechat.listTickets>
            <tag>Appointments</tag>
            <dateFrom>{$ctx:livechat.dateFrom}</dateFrom>
         </livechat.listTickets>
      
       <!-- START: Proceed only if the call is successful. -->
      <filter xpath="get-property('responseStatus') != 200">
         <then>
            <!-- Append an error message to be sent to the user. -->
            <property name="livechat.errorResponse" expression="json-eval($)" />
            <call-template target="responseHandlerTemplate">
               <with-param name="activity" value="livechat_listTickets" />
               <with-param name="id" value="{$ctx:id.empty}" />
               <with-param name="status" value="error" />
               <with-param name="message" value="{$ctx:livechat.errorResponse}" />
            </call-template>
            <loopback />
         </then>
      </filter>
       <!-- END: Proceed only if the call is successful. -->
      
      <property name="ticketIndex" expression="0" scope="operation" />
      <property name="livechat.ticketCount" expression="count(//tickets)" />
      
      <!-- START: Proceed only if there is at least one ticket -->
      <filter xpath="get-property('livechat.ticketCount') = 0.0">
         <then>
            <property name="id" value="{}" />
            <property name="status" value="skipped" />
            <property name="message" value="There are no tickets to process" />
            <call-template target="responseHandlerTemplate">
               <with-param name="id" value="{$ctx:id}" />
               <with-param name="activity" value="livechat_listTickets" />
               <with-param name="status" value="{$ctx:status}" />
               <with-param name="message" value="{$ctx:message}" />
            </call-template>
            <loopback />
         </then>
      </filter>
      <!-- END: Proceed only if there is at least one ticket -->
      
      <!--BEGIN : FOR EACH ticket -->
      <iterate continueParent="false" id="tickets" expression="//tickets" sequential="true">
         <target>
            <sequence>
               <property name="livechat.ticketId" expression="json-eval($.tickets.id)" />
               <property name="livechat.ticketSubject" expression="json-eval($.tickets.subject)" />
               <property name="livechat.requesterEmail" expression="json-eval($.tickets.requester.mail)" />
               <property name="livechat.requesterName" expression="json-eval($.tickets.requester.name)" />
               <property name="livechat.ticketName" expression="json-eval($.tickets.events[0].message)" />
               
			   
                <!--Check whether the patient is already existing using the above created patient object-->
                <script language="js">
                  <![CDATA[
                     var patientObj = eval("(" + mc.getProperty('cliniko.patientObject') + ")");
                     
                     var requesterMail = mc.getProperty('livechat.requesterEmail');
                     var requesterName = mc.getProperty('livechat.requesterName');
                     var subject = mc.getProperty('livechat.ticketSubject');
                     
                     var practioner = subject.match(/\(([^)]+)\)/)[1].split(':')[1];
                     mc.setProperty("cliniko.practionerId",practioner);
                     
                     if(patientObj.hasOwnProperty(requesterMail)) {
                        var id = ''+patientObj[requesterMail];
                        mc.setProperty("cliniko.patientId",id);
                     } else {
                        var firstName = requesterName.split(" ")[0];
                        var lastName = requesterName.split(" ")[1];
                        mc.setProperty("cliniko.firstName",firstName);
                        mc.setProperty("cliniko.lastName",lastName);
                     }
                  ]]>
               </script>
               
               <!-- START: Proceed according to the existence of the patient in cliniko -->
               <filter source="boolean(get-property('cliniko.patientId'))" regex="false">
                  <then>
                     <!--Call cliniko connector createPatient method to create a new patient -->
                     <cliniko.init>
                        <apiUrl>{$ctx:cliniko.apiUrl}</apiUrl>
                        <apiKey>{$ctx:cliniko.apiKey}</apiKey>
                     </cliniko.init>
                     <cliniko.createPatient>
                        <email>{$ctx:livechat.requesterEmail}</email>
                        <firstName>{$ctx:cliniko.firstName}</firstName>
                        <lastName>{$ctx:cliniko.lastName}</lastName>
                     </cliniko.createPatient>
                     
                     <property name="cliniko.patientId" expression="json-eval($.id)" />
                     
                     <!-- START: Append the response message according to the createPatient response -->
                     <filter source="boolean(get-property('cliniko.patientId'))" regex="false">
                        <then>
                            <property name="id" expression="fn:concat('livechat_ticketId:',get-property('livechat.ticketId'))" />
                            <property name="status" value="error" />
                            <property name="message" expression="json-eval($)" />
                        </then>
                        <else>
                            <property name="id" expression="fn:concat('livechat_ticketId:',get-property('livechat.ticketId'),',cliniko_patientId:',get-property('cliniko.patientId'))" />
                            <property name="status" value="success" />
                            <property name="message" value="A patient has been successfully created." />
                        </else>
                     </filter>
                     <!--Call the responseHandler template-->
                     <call-template target="responseHandlerTemplate">
                        <with-param name="activity" value="cliniko_createPatient" />
                        <with-param name="id" value="{$ctx:id}" />
                        <with-param name="status" value="{$ctx:status}" />
                        <with-param name="message" value="{$ctx:message}" />
                     </call-template>
                     
                  </then>
               </filter>
               <!-- END: Proceed according to the existence of the patient in cliniko -->
               
               <property name="uri.var.urlQuery" action="remove"/>
               
               <!-- START: Process only if the patient is existing -->
               <filter source="boolean(get-property('cliniko.patientId'))" regex="true">
                  <then>
                     <!-- Call createAppointments template to create appointments and events -->
                      <call-template target="createAppointments">
                          <with-param name="cliniko.apiKey" value="{$ctx:cliniko.apiKey}" />
                          <with-param name="cliniko.apiUrl" value="{$ctx:cliniko.apiUrl}" />
                          <with-param name="cliniko.patientId" value="{$ctx:cliniko.patientId}" />
                          <with-param name="cliniko.practionerId" value="{$ctx:cliniko.practionerId}" />
                          <with-param name="cliniko.accountName" value="{$ctx:cliniko.accountName}" />
                          <with-param name="common.id" value="{$ctx:livechat.ticketId}" />
                          <with-param name="cliniko.appointmentNote" value="{$ctx:livechat.ticketName}" />
                          <with-param name="googlecalendar.apiUrl" value="{$ctx:googlecalendar.apiUrl}" />
                          <with-param name="googlecalendar.accessToken" value="{$ctx:googlecalendar.accessToken}" />
                          <with-param name="googlecalendar.calendarId" value="{$ctx:googlecalendar.calendarId}" />
                          <with-param name="shared.timeZone" value="{$ctx:shared.timeZone}" />
                      </call-template>
                  </then>
               </filter>
               <!-- END: Process only if the patient is existing -->
			   
               <property name="ticketIndex" expression="get-property('operation','ticketIndex') + 1" scope="operation" />
               <filter xpath="get-property('operation','ticketIndex') = get-property('livechat.ticketCount')">
                  <then>
                     <loopback />
                  </then>
               </filter>
            </sequence>
         </target>
      </iterate>
       <!--END : FOR EACH ticket -->
         
      </inSequence>
      <outSequence>
         <property name="messageType" value="application/json" scope="axis2" />
         <filter source="boolean(get-property('operation', 'responseString'))" regex="false">
            <then>
               <payloadFactory media-type="json">
                  <format>{
                     "Response":{
                        "process":"cliniko_retrieveTicketsAndCreateAppointments",
                        "activityResponse":"No new appointments were created since the patients already have appointments with the practitioner."
                     }
                  }</format>
               </payloadFactory>
            </then>
            <else>
               <payloadFactory media-type="json">
                  <format>{
						"Response":{
							"process":"cliniko_retrieveTicketsAndCreateAppointments",
							"activityResponse":[$1]
						}
					}</format>
                  <args>
                     <arg expression="get-property('operation', 'responseString')" />
                  </args>
               </payloadFactory>
            </else>
         </filter>
         <send />
      </outSequence>
   </target>
</proxy>
Sample Request for retrieving daily tickets from LiveChat which are tagged as ‘Appointments’, creating the ticket requester as a patient in Cliniko if the patient does not exist, creating an appointment for the patient in Cliniko under the practitioner givein in the LiveChat ticket and creating an event in the common Google Calendar and adding the particular practitioner as an attendee for the created event
{
    "cliniko": {
        "appointmentType": "LiveChat Appointments"
    },
    "googlecalendar": {
        "calendarId": "5nu6p7lmpb1anng51mi391hghs@group.calendar.google.com"
    },
    "shared": {
        "timeZone": "+05:30"
    }
}

Note

 The following are the parameter descriptions:

  • cliniko.appointmentType: The name of the appointment type to which the appointments will be created. 
  • googlecalendar.calendarId: The ID of the common Google Calendar.
  • shared.timeZone: The time zone of both the APIs 'Cliniko' and 'Google Calendar'.(e.g. '+05:30').