diff --git a/director-cli.sh b/director-cli.sh
index 6bc7c5a5b8aa1f4b5c4e5dd8884eb6135e1bafe1..3b62dfd70b3aa575c78af35ce0c3160b3bc76420 100755
--- a/director-cli.sh
+++ b/director-cli.sh
@@ -10,7 +10,6 @@
 #     actions for a host, commands, services
 #
 # This script contains specific logic for IML
-#   - use puppet facts
 #   - UniBe network and group names - see hostCreate()
 #
 # ----------------------------------------------------------------------
@@ -21,19 +20,18 @@
 # 2023-02-17  v0.5  ah  add hostnamme into CFGSTORAGE
 # 2023-02-17  v0.6  ah  remove invalid line in cleanup
 # 2023-02-17  v0.7  ah  check inc_getconfig.sh exists and hostname -f has a value
+# 2023-10-25  v0.8  ah  generate json with "jo"; optimze http requests on services; parallel service function call
 # ======================================================================
 
-_version="0.7"
 
-tmpfile=/tmp/outcurl.tmp
-tmpfile2=/tmp/outcurl2.tmp
+_version="0.8"
+
+which curl >/dev/null || exit 1
+which jo   >/dev/null || exit 1
 
 # a custom file to source instead of detecting local data
 loadfile=
 
-# UNUSED
-# APICLIENT=`dirname $0`/api2director
-
 
 # MY_NAME=`facter fqdn | cut -f -2 -d ">"`
 # MY_IP=`facter ipaddress | cut -f -2 -d ">"`
@@ -45,6 +43,15 @@ loadfile=
 typeset cfg_debug=false
 typeset cfg_dryrun=false
 
+export regexPrivateNetworks="^(10\.|172\.1[6-9]\.|172.2[0-9]\.|172\.3[01]\.|192.168\.)"
+
+# json for a host: set group if the system is pingable by Icinga or in a private network
+hostImportReachable="host in network"
+hostImportPrivate="host passive only"
+
+# default groups (jo params)
+hostDefaultgroups="groups[]=iml groups[]=iml-server"
+
 # ======================================================================
 #
 # FUNCTIONS
@@ -83,138 +90,94 @@ typeset cfg_dryrun=false
 # ----------------------------------------------------------------------
 
   # ............................................................
-  # set $ch to store all object vars
-
+  # generate json parameters for jo
   function _generateJsonForHost(){
 
     if [ -z "$loadfile" ]; then
       # --- host infos
-
       local MY_Platform=$(uname -a | cut -f 1 -d ' ')
       . $(dirname $0)/plugins/inc_pluginfunctions || exit 1
       local MY_OSName=$(ph.getOS)
       local MY_OSMajorVersion=$(ph.getOSMajor)
     fi
 
-    export CFGSTORAGE="${MY_NAME}-directorhost"
-    (
-      $ch --flush
-      $ch --set  object_name     \"$MY_NAME\"
-      $ch --set  object_type     '"object"'
-      $ch --set  address         \"$MY_IP\"
-      $ch --set  display_name    \"$MY_NAME\"
-      $ch --set  zone            \"$MY_ZONE\"
-
-      $ch --set  icon_image      \"/images/os/${MY_OSName}.png\"
-      $ch --set  icon_image_alt  \"${MY_Platform}\:\ ${MY_OSName}\ ${MY_OSMajorVersion}\"
-    ) 2>/dev/null 
-
-    # --- detect phase
-    # local phase="live"
-    # for myphase in preview stage demo
-    # do
-    #   echo $MY_NAME | grep "\.$myphase\." >/dev/null && phase=$myphase
-    # done
-
-    (
-      # ----- facter data to host vars
-      $ch --set  vars.platform  \"${MY_Platform}\"
-      $ch --set  vars.os        \"${MY_OSName}${MY_OSMajorVersion}\"
-
-      # ----- set host type
-
-      # host in the UNIBE network:
-      if echo "$MY_IP" | grep -E "^(10\.|172\.1[6-9]\.|172.2[0-9]\.|172\.3[01]\.|192.168\.)" >/dev/null
-      then
-        $ch --set  imports  '["host passive only"]'
-      else
-        $ch --set  imports  '["host in network"]'
+    local JSONPARAMS="
+      object_name=$MY_NAME
+      object_type=object 
+      address=$MY_IP
+      display_name=$MY_NAME
 
-        # port checks initiated by icinga server to monitor client
-        if [ -n "${host_vars_tcpport}" -a "${host_vars_tcpport}" != "[]" ]; then
-          host_vars_tcpport=$(echo ${host_vars_tcpport} | sed "s# ##g")
-          $ch --set  vars.tcp_port  "${host_vars_tcpport}"
-        fi
-      fi
-
-
-      # ----- /host type
+      zone=$MY_ZONE
 
+      icon_image=/images/os/${MY_OSName}.png
+      icon_image_alt="\"${MY_Platform}:\ ${MY_OSName}\ ${MY_OSMajorVersion}\""
 
-      # ----- host groups
-      #       all host groups must exist in director - otherwise the creation
-      #       of a host will fail
-      #       see https://icinga.one.iml.unibe.ch/icingaweb2/director/dashboard?name=hosts#!/icingaweb2/director/hostgroups
-
-      $ch --set  groups        '["iml", "iml-server"]'
+      vars.platform=${MY_Platform} \
+      vars.os=${MY_OSName}${MY_OSMajorVersion}
 
+    "
+    # ----- set host type
+    # check if host is in a private network:
+    if echo "$MY_IP" | grep -E "${regexPrivateNetworks}" >/dev/null
+    then
+      JSONPARAMS+='imports[]="${hostImportPrivate}" '
+    else
+      JSONPARAMS+='imports[]="${hostImportReachable}" '
+    fi
 
-      # ... and add some others
-      # $ch --add  groups        \"iml-phase-$phase\"
+    # port checks initiated by icinga server to monitor client
+    if [ -n "${host_vars_tcpport}" -a "${host_vars_tcpport}" != "[]" ]; then
+      JSONPARAMS+='vars.tcp_port=${host_vars_tcpport} '
+    fi
 
-    ) 2>/dev/null
+    # ----- host groups
+    # all host groups must exist in director - otherwise the creation
+    # of a host will fail
+    JSONPARAMS+="${hostDefaultgroups} "
 
-    # ----- generate data and send to DIRECTOR
-    # DATA=`$ch --json 2>/dev/null`
-    # $ch --flush 2>/dev/null
+    echo "$JSONPARAMS"
   }
 
   # ............................................................
-  # set $ch to store all object vars
-  # UNUSED see response of GET director/commands/templates
-  # function _generateJsonForCommand(){
-  #   export CFGSTORAGE="command-${IDC_command__obj_name}"
-  #   (
-  #     $ch --flush
-  #     $ch --set  object_name     "\"${IDC_command__obj_name}\""
-  #     $ch --set  object_type     \"template\"
-  # 
-  #   ) 2>/dev/null
-  # }
-
-  # ............................................................
-  # set $ch to store all object vars
+  # generate json parameters for jo
+  # global  int     checkInterval           fetched in check configuration by _parseCheckConfig
+  # global  string  IDC_service__obj_name   generated var from check name in _generateVarsByCheckname
+  # global  string  IDC_command__obj_name   generated var from check name in _generateVarsByCheckname
   function _generateJsonForServicetemplate(){
-    export CFGSTORAGE="${MY_NAME}-service-${IDC_service__obj_name}"
-    (
-      $ch --flush
-      $ch --set  object_name     "\"${IDC_service__obj_name}\""
-      $ch --set  check_command   \"${IDC_command__obj_name}\"
-      $ch --set  object_type     \"template\"
+    local JSONPARAMS="
+      object_name="\"${IDC_service__obj_name}\""
+      check_command=\""${IDC_command__obj_name}\""
+      object_type=template
 
-      $ch --set  enable_active_checks  false
-      $ch --set  enable_passive_checks true
+      enable_active_checks=false
+      enable_passive_checks=true
 
-      $ch --set  check_interval        "\"${checkInterval}s\""  # see _parseCheckConfig FILE
+      check_interval="\"${checkInterval}s\"" 
 
       # graphite
-      # $ch --set  enable_perfdata       true 
-      # $ch --set  vars.check_command    \"${checkName}\"         # for graphite plugin
-
+      enable_perfdata=true 
+      vars.check_command=\"${checkName}\"
+    "
       if [ ! -z "${checkIcon}" ]; then
-        $ch --set  icon_image      \"${checkIcon}\"
-        $ch --set  icon_image_alt  \"${checkName}\"
+        JSONPARAMS+="icon_image=\"${checkIcon}\" icon_image_alt=\"${checkName}\" "
       fi
 
       if [ ! -z "${checkMaxAttempts}" ]; then
-        $ch --set  max_check_attempts  \"${checkMaxAttempts}\"
+        JSONPARAMS+="max_check_attempts=${checkMaxAttempts}"
       fi
-      
-
-    ) 2>/dev/null
+    echo "$JSONPARAMS"
   }
 
   # ............................................................
-  # set $ch to store all object vars
+  # generate json parameters for jo
   function _generateJsonForSvclink(){
-    export CFGSTORAGE="${MY_NAME}-servicelink-${IDC_svcathost__obj_name}"
-    (
-      $ch --flush
-      $ch --set  object_name     "\"${IDC_svcathost__obj_name}\""
-      $ch --set  object_type     \"object\"
-      $ch --set  host            "\"${MY_NAME}\""
-      $ch --set  imports         "[ \"${IDC_service__obj_name}\" ]"
-    ) 2>/dev/null
+    local JSONPARAMS="
+      object_name="\"${IDC_svcathost__obj_name}\""
+      check_type=object
+      host=${MY_NAME}
+      imports[]="\"${IDC_service__obj_name}\""
+    "
+    echo "JSONPARAMS"
   }
 
   # ............................................................
@@ -271,7 +234,7 @@ typeset cfg_dryrun=false
         _sUrlDelete=director/host?name=${_object_name}
 
         _existFilter="object_name"
-        _generateJsonForHost
+        _jsonparams="$( _generateJsonForHost )"
         ;;
 
       'service')
@@ -286,7 +249,7 @@ typeset cfg_dryrun=false
         _sUrlDelete=director/service?name=${_object_name}
 
         _existFilter='"object_name": '
-        _generateJsonForServicetemplate
+        _jsonparams="$( _generateJsonForServicetemplate )"
         ;;
 
       'svclink')
@@ -303,7 +266,7 @@ typeset cfg_dryrun=false
         # _existFilter="object_name.*${IDC_svcathost__obj_name}"
         _existFilter='"object_name": '
 
-        _generateJsonForSvclink
+        _jsonparams="$( _generateJsonForSvclink )"
         ;;
 
       *)
@@ -361,12 +324,10 @@ typeset cfg_dryrun=false
       return
     fi
 
-
     # --- get json data of object
     if [ $_bSendData = true ]; then
-      _jsondata=$($ch --json 2>/dev/null)
+      _jsondata=$( eval jo -p -d. $_jsonparams )
     fi
-    $ch --flush 2>/dev/null
 
     # --- http request
     if [ ${_paramDryrun} = false ]; then
@@ -377,7 +338,7 @@ typeset cfg_dryrun=false
         exit 1
       fi
       if [ $_bShowResponse = true ]; then
-        http.getResponseHeader
+        # http.getResponseHeader
         http.getResponse
       fi
 
@@ -427,22 +388,6 @@ typeset cfg_dryrun=false
 # ----------------------------------------------------------------------
 
 
-
-  # ............................................................
-  # helper to create a base config for the current host
-  # UNUSED
-  function UNUSED_initHostdata(){
-    export CFGSTORAGE="${MY_NAME}-directorhost"
-    (
-      $ch --flush
-      $ch --set  object_name   \"$MY_NAME\"
-      $ch --set  object_type   '"object"'
-      $ch --set  address       \"$MY_IP\"
-      $ch --set  display_name  \"$MY_NAME\"
-    ) 2>/dev/null
-  }
-
-
   # ............................................................
   # create a host with PUT on director API
   function hostCreate(){
@@ -539,12 +484,9 @@ typeset cfg_dryrun=false
     IDC_command__obj_name="${checkName}"
     IDC_service__obj_name="service-template_for_command_${checkName}"
     IDC_svcathost__obj_name="$(_getName4Svcathost ${checkName})"
-    # IDC_service__obj_name="${checkName}"
-    # IDC_svcathost__obj_name="${checkName}"
-
     IDC_command__cachefile="${dir_data}/command_${checkName}__at-director.txt"
-    # IDC_service__cachefile="${dir_data}/all_defined_services__at-director.txt"
-    # IDC_svcathost__cachefile="${dir_data}/all_services_on_host__at-director.txt"
+    # set | grep "^IDC"
+
   }
 
 
@@ -553,22 +495,20 @@ typeset cfg_dryrun=false
   # create a service in Icinga director
   # uses global variables only
   function serviceCreateOrUpdate(){
-    _h2 "${FUNCNAME[0]}()"
-
-    local sMode=update
-    local sMethod=POST
-    local _sUrl="director/service?name=${IDC_service__obj_name}"
+    # _h2 "${FUNCNAME[0]}()"
+    echo ">>> ${FUNCNAME[0]}() - ${IDC_service__obj_name}"
 
-    ObjAction exists service
-    if [ $? -ne 0 ]; then
-      ObjAction create service
-    else
-      ObjAction update service
+    local _action=create
+    if ObjAction exists service; then
+      _action=update
     fi
-    if [ $? -ne 0 ]; then
-      echo "ERROR :/"
+
+    if ObjAction $_action service; then
+      echo "OK $_action service ${IDC_service__obj_name}"
+      return 0
     else
-      echo "OK"
+      echo "ERROR :/ $_action service ${IDC_service__obj_name}"
+      return 1
     fi
   }
 
@@ -577,25 +517,26 @@ typeset cfg_dryrun=false
   # create a service in Icinga director
   # param   string  filename of check config
   function serviceCreateByCfgFile(){
-      _h2 "${FUNCNAME[0]}($1) - create single service of given file"
+      # _h2 "${FUNCNAME[0]}($1) - create single service of given file"
+      echo ">>>>>> ${FUNCNAME[0]}($1) - create single service of given file"
       _parseCheckConfig "${1}"
       _generateVarsByCheckname "${checkName}"
 
       # create command if it does not exist
-      serviceCreateOrUpdate
-
-      ObjAction exists service
-      if [ $? -eq 0 ]; then
-        ObjAction exists svclink
-        if [ $? -ne 0 ]; then
-          ObjAction create svclink
+      if serviceCreateOrUpdate >/dev/null ; then
+        if ! ObjAction exists svclink; then
+          if ObjAction create svclink; then
+            echo "OK: linked service ${checkName} on host [$MY_NAME] was created"
+          else
+            echo "ERROR :-/ unable to create linked service ${checkName} on host [$MY_NAME]"
+          fi
         else
           echo "SKIP: linked service on host [${IDC_svcathost__obj_name}] exists"
           # TODO, uncomment -- wenn es sinnvolle Features gibt
           # ObjAction update svclink
         fi
       else
-        echo "SKIP link ... service template for ${checkName} not ready."
+        echo "SKIP: service ${checkName} not ready - unable to create a service link."
       fi
   }
 
@@ -608,9 +549,18 @@ typeset cfg_dryrun=false
     # loop over all services and create
     for mycheckfile in $(getChecks)
     do
-      serviceCreateByCfgFile "${mycheckfile}"
-      echo
+      serviceCreateByCfgFile "${mycheckfile}" &
+    done
+    
+    # wait until all background processes are done.
+    # 1 line in output is the header and one sub process is the ps command --> check > 2 items
+    local _iProcesses=$( getChecks | wc -w )
+    while [ $_iProcesses -gt 2 ]; do
+      echo "Processes: $_iProcesses"
+      sleep 2
+      _iProcesses=$( ps --ppid "$$" | wc -l ) 
     done
+    echo "Done ${FUNCNAME[0]}"
   }
 
 
@@ -861,8 +811,7 @@ do
       hostDelete
       ;;
     '--hs' | '--hostshow')
-      _generateJsonForHost
-      $ch --json 2>/dev/null
+      eval jo -p -d. $( _generateJsonForHost )
       ;;
 
     # ----- check actions