diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -1,26 +1,28 @@
-ZooVisitor
-==========
+# ZooVisitor
 
 [![Hackage](https://img.shields.io/hackage/v/zoovisitor.svg?style=flat)](https://hackage.haskell.org/package/zoovisitor)
 
 An Apache [zookeeper](https://zookeeper.apache.org/) client for Haskell.
 
-Tested on zookeeper 3.4, a higher version should work but not guaranteed.
+Tested with libzookeeper-mt [3.4, 3.6], a higher version should work but not
+guaranteed.
 
 **NOTE: this library is still in development.**
 
-
 ## Features
 
 - Simple
-  + Does not require knowledge of the C APIs
-  + Does not require malloc and free memory manually
-  + High-level api written in Haskell
 
+  - Does not require knowledge of the C APIs
+  - Does not require malloc and free memory manually
+  - High-level api written in Haskell
+
 - Safe
-  + Type safe
-  + A failure action should throw an exception
 
+  - Type safe
+  - A failure action should throw an exception
+
 - Fast
-  + All underlying calls are non-blocking, you can use Haskell lightweight threads to speed up your tasks.
-  + The speed should be compatible to C implementation
+  - All underlying calls are non-blocking, you can use Haskell lightweight
+    threads to speed up your tasks.
+  - The speed should be compatible to C implementation
diff --git a/include/hs_zk.h b/include/hs_zk.h
--- a/include/hs_zk.h
+++ b/include/hs_zk.h
@@ -75,11 +75,6 @@
 
 // ----------------------------------------------------------------------------
 
-zhandle_t* hs_zookeeper_init(HsStablePtr mvar, HsInt cap,
-                             hs_watcher_ctx_t* watcher_ctx, const char* host,
-                             int recv_timeout, const clientid_t* clientid,
-                             int flags);
-
 int hs_zoo_aget_acl(zhandle_t* zh, const char* path, HsStablePtr mvar,
                     HsInt cap, hs_acl_completion_t* completion);
 
diff --git a/src/ZooKeeper.hs b/src/ZooKeeper.hs
--- a/src/ZooKeeper.hs
+++ b/src/ZooKeeper.hs
@@ -7,6 +7,7 @@
   , U.Resource
 
   , zooCreate
+  , zooCreateIfMissing
   , zooSet
   , zooGet
   , zooWatchGet
@@ -25,8 +26,10 @@
   , zooDeleteOpInit
   , zooSetOpInit
   , zooCheckOpInit
+  , assertZooOpResultOK
 
   , zooClientID
+  , I.peekClientId
   , zooState
   , zooRecvTimeout
   , isUnrecoverable
@@ -36,6 +39,7 @@
   , zookeeperClose
   ) where
 
+import Control.Exception (catch)
 import           Control.Monad            (void, when, zipWithM, (<=<))
 import           Data.Bifunctor           (first)
 import           Data.Maybe               (fromMaybe)
@@ -73,7 +77,7 @@
   -- ^ The id of a previously established session that this client will be
   -- reconnecting to. Pass 'Nothing' if not reconnecting to a previous
   -- session. Clients can access the session id of an established, valid,
-  -- connection by calling 'zooGetClientID'. If the session corresponding to
+  -- connection by calling 'zooClientID'. If the session corresponding to
   -- the specified clientid has expired, or if the clientid is invalid for
   -- any reason, the returned 'T.ZHandle' will be invalid -- the 'T.ZHandle'
   -- state will indicate the reason for failure (typically 'T.ZooExpiredSession').
@@ -130,6 +134,19 @@
   where
     csize = I.csize @T.StringCompletion
 
+-- TODO: Add option to create its parents too
+-- see: https://hackage.haskell.org/package/directory-1.3.7.0/docs/System-Directory.html#v:createDirectoryIfMissing
+zooCreateIfMissing
+  :: T.ZHandle
+  -> CBytes
+  -> Maybe Bytes
+  -> T.AclVector
+  -> T.CreateMode
+  -> IO (Maybe T.StringCompletion)
+zooCreateIfMissing zh path m_value acl mode =
+  catch (Just <$> zooCreate zh path m_value acl mode) $
+    \(_ :: E.ZNODEEXISTS) -> pure Nothing
+
 -- | Sets the data associated with a node.
 --
 -- Throw one of the following exceptions on failure:
@@ -540,6 +557,13 @@
                    (I.c_hs_zoo_amulti zh (fromIntegral len) mbai# mbar#)
   zipWithM ($) (map fst res) (chunkPtr ptr_result I.zooOpResultSize)
 
+assertZooOpResultOK :: HasCallStack => T.ZooOpResult -> IO ()
+assertZooOpResultOK (T.ZooCreateOpResult ret _) = void $ E.throwZooErrorIfNotOK ret
+assertZooOpResultOK (T.ZooDeleteOpResult ret)   = void $ E.throwZooErrorIfNotOK ret
+assertZooOpResultOK (T.ZooSetOpResult ret _)    = void $ E.throwZooErrorIfNotOK ret
+assertZooOpResultOK (T.ZooCheckOpResult ret)    = void $ E.throwZooErrorIfNotOK ret
+{-# INLINE assertZooOpResultOK #-}
+
 -- | Internal helper function to set zoo op.
 initOp :: (I.ZooOp, Ptr I.CZooOp)
        -> IO (Ptr I.CZooOpResult -> IO T.ZooOpResult, I.TouchListBytes)
@@ -560,12 +584,14 @@
   -> Maybe Bytes
   -- ^ The data to be stored in the node.
   -> CInt
-  -- ^ The max buffer size of the created new node path (this might be
-  -- different than the supplied path because of the 'T.ZooSequence' flag).
-  -- If this size is 0,
+  -- ^ Max Size of the buffer results in 'ZooOpResult' which will be filled
+  -- with the path of the new node (this might be different than the supplied
+  -- path because of the 'T.ZooSequence' flag).
   --
   -- Note: we do NOT check if the size is non-negative.
   --
+  -- If this size is 0, you will get an empty ZooCreateOpResult.
+  --
   -- If the path of the new node exceeds the buffer size, the path string will
   -- be truncated to fit. The actual path of the new node in the server will
   -- not be affected by the truncation.
@@ -576,7 +602,7 @@
   -- or an OR of the Create Flags
   -> T.ZooOp
 zooCreateOpInit path m_value buflen acl mode = I.ZooCreateOp $ \op -> do
-  let buflen' = buflen + 1  -- including space for the null terminator
+  let buflen' = buflen + 1  --  The path string will always be null-terminated.
   CBytes.withCBytesUnsafe path $ \path' -> do
     mba@(Z.MutableByteArray mba#) <- Z.newPinnedByteArray (fromIntegral buflen')
     case m_value of
@@ -675,7 +701,7 @@
   -- ^ The id of a previously established session that this client will be
   -- reconnecting to. Pass 'Nothing' if not reconnecting to a previous
   -- session. Clients can access the session id of an established, valid,
-  -- connection by calling 'zooGetClientID'. If the session corresponding to
+  -- connection by calling 'zooClientID'. If the session corresponding to
   -- the specified clientid has expired, or if the clientid is invalid for
   -- any reason, the returned 'T.ZHandle' will be invalid -- the 'T.ZHandle'
   -- state will indicate the reason for failure (typically 'T.ZooExpiredSession').
@@ -695,7 +721,7 @@
   void $ E.throwZooErrorIfNotOK =<< I.c_zookeeper_close zh
 {-# INLINABLE zookeeperClose #-}
 
--- | Return the client session id, only valid if the connections
+-- | Return the opaque client session id, only valid if the connections
 -- is currently connected (ie. last watcher state is 'T.ZooConnectedState')
 zooClientID :: T.ZHandle -> IO T.ClientID
 zooClientID = I.c_zoo_client_id
diff --git a/src/ZooKeeper/Internal/Types.hsc b/src/ZooKeeper/Internal/Types.hsc
--- a/src/ZooKeeper/Internal/Types.hsc
+++ b/src/ZooKeeper/Internal/Types.hsc
@@ -25,8 +25,23 @@
 newtype ZHandle = ZHandle { unZHandle :: Ptr () }
   deriving (Show, Eq)
 
+-- | This structure holds the id and password for the session. This structure
+-- should be treated as opaque. It is received from the server when a session
+-- is established and needs to be sent back as-is when reconnecting a session.
 newtype ClientID = ClientID { unClientID :: Ptr () }
   deriving (Show, Eq)
+
+data HsClientID = HsClientID
+  { clientId     :: {-# UNPACK #-} !Int64
+  , clientPasswd :: {-# UNPACK #-} !CBytes
+  } deriving (Show, Eq)
+
+peekClientId :: ClientID -> IO HsClientID
+peekClientId (ClientID ptr) = do
+  client_id <- (#peek clientid_t, client_id) ptr
+  -- the pointer is getting from zhandle, so here we don't need to free it
+  passwd <- CBytes.fromCString =<< (#peek clientid_t, passwd) ptr
+  pure $ HsClientID{clientId=client_id, clientPasswd=passwd}
 
 newtype ZooLogLevel = ZooLogLevel CInt
   deriving (Eq, Storable)
diff --git a/src/ZooKeeper/Types.hs b/src/ZooKeeper/Types.hs
--- a/src/ZooKeeper/Types.hs
+++ b/src/ZooKeeper/Types.hs
@@ -1,6 +1,7 @@
 module ZooKeeper.Types
   ( I.ZHandle
   , I.ClientID
+  , I.HsClientID (..)
   , I.WatcherFn
 
   , I.ZooOp
diff --git a/zoovisitor.cabal b/zoovisitor.cabal
--- a/zoovisitor.cabal
+++ b/zoovisitor.cabal
@@ -1,6 +1,6 @@
 cabal-version:      2.2
 name:               zoovisitor
-version:            0.2.4.0
+version:            0.2.5.0
 synopsis:
   A haskell binding to Apache Zookeeper C library(mt) using Haskell Z project.
 
@@ -12,7 +12,7 @@
 copyright:          Copyright (c)
 author:             mu
 maintainer:         mu@laxcat.xyz
-tested-with:        GHC ==8.8.4 || ==8.10.7 || ==9.0.2 || ==9.2.5
+tested-with:        GHC ==8.10.7 || ==9.0.2 || ==9.2.8
 category:           Database
 homepage:           https://github.com/ZHaskell/zoovisitor
 bug-reports:        https://github.com/ZHaskell/zoovisitor/issues
