diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,10 @@
 The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
 and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
 
+## 0.9.0
+### Changed
+- Use an STM listener instead of a publisher for the node API.
+
 ## 0.8.2
 ### Added
 - Expose `ChainMessage` and `ManagerMessage` types from `Haskoin.Node` module.
diff --git a/haskoin-node.cabal b/haskoin-node.cabal
--- a/haskoin-node.cabal
+++ b/haskoin-node.cabal
@@ -2,10 +2,10 @@
 --
 -- see: https://github.com/sol/hpack
 --
--- hash: 36262f24dd4ab0072b836e69359d401f0c68d0ad7a9b50db212087b10a6b071d
+-- hash: 1a84bd58732e99811ec849f42d0294accf3b078c9f8663c2b1e7f67614f0e359
 
 name:           haskoin-node
-version:        0.8.2
+version:        0.9.0
 synopsis:       Haskoin Node P2P library for Bitcoin and Bitcoin Cash
 description:    Bitcoin and Bitcoin Cash peer-to-peer protocol library featuring headers-first synchronisation.
 category:       Bitcoin, Finance, Network
diff --git a/src/Haskoin/Node.hs b/src/Haskoin/Node.hs
--- a/src/Haskoin/Node.hs
+++ b/src/Haskoin/Node.hs
@@ -110,13 +110,13 @@
                 ChainHeaders p (map fst hcs) `sendSTM` ch
             PeerConnected p a -> do
                 ChainPeerConnected p a `sendSTM` ch
-                Event (PeerEvent event) `sendSTM` nodeConfEvents cfg
+                nodeConfEvents cfg $ PeerEvent event
             PeerDisconnected p a -> do
                 ChainPeerDisconnected p a `sendSTM` ch
-                Event (PeerEvent event) `sendSTM` nodeConfEvents cfg
-            _ -> Event (PeerEvent event) `sendSTM` nodeConfEvents cfg
+                nodeConfEvents cfg $ PeerEvent event
+            _ -> nodeConfEvents cfg $ PeerEvent event
     chain_events event = do
-        Event (ChainEvent event) `sendSTM` nodeConfEvents cfg
+        nodeConfEvents cfg $ ChainEvent event
         case event of
             ChainBestBlock b -> ManagerBestBlock (nodeHeight b) `sendSTM` mgr
             _ -> return ()
diff --git a/src/Network/Haskoin/Node/Common.hs b/src/Network/Haskoin/Node/Common.hs
--- a/src/Network/Haskoin/Node/Common.hs
+++ b/src/Network/Haskoin/Node/Common.hs
@@ -99,7 +99,7 @@
       -- ^ network address for the local host
     , nodeConfNet      :: !Network
       -- ^ network constants
-    , nodeConfEvents   :: !(Publisher NodeEvent)
+    , nodeConfEvents   :: !(Listen NodeEvent)
       -- ^ node events are sent to this publisher
     , nodeConfTimeout  :: !Int
       -- ^ timeout in seconds
diff --git a/test/Haskoin/NodeSpec.hs b/test/Haskoin/NodeSpec.hs
--- a/test/Haskoin/NodeSpec.hs
+++ b/test/Haskoin/NodeSpec.hs
@@ -115,33 +115,26 @@
     -> m a
 withTestNode net str f =
     runNoLoggingT $
-    withSystemTempDirectory ("haskoin-node-test-" <> str <> "-") $ \w ->
-        withPublisher $ \pub ->
-            withSubscription pub $ \node_inbox -> do
-                db <-
-                    R.open
-                        w
-                        R.defaultOptions
-                            { R.createIfMissing = True
-                            , R.compression = R.SnappyCompression
-                            }
-                let cfg =
-                        NodeConfig
-                            { nodeConfMaxPeers = 20
-                            , nodeConfDB = db
-                            , nodeConfPeers = []
-                            , nodeConfDiscover = True
-                            , nodeConfNetAddr =
-                                  NetworkAddress 0 (SockAddrInet 0 0)
-                            , nodeConfNet = net
-                            , nodeConfEvents = pub
-                            , nodeConfTimeout = 10
-                            }
-                withNode cfg $ \(mgr, ch) ->
-                    lift $
-                    f
-                        TestNode
-                            { testMgr = mgr
-                            , testChain = ch
-                            , nodeEvents = node_inbox
-                            }
+    withSystemTempDirectory ("haskoin-node-test-" <> str <> "-") $ \w -> do
+        node_inbox <- newInbox
+        db <-
+            R.open
+                w
+                R.defaultOptions
+                    { R.createIfMissing = True
+                    , R.compression = R.SnappyCompression
+                    }
+        let cfg =
+                NodeConfig
+                    { nodeConfMaxPeers = 20
+                    , nodeConfDB = db
+                    , nodeConfPeers = []
+                    , nodeConfDiscover = True
+                    , nodeConfNetAddr = NetworkAddress 0 (SockAddrInet 0 0)
+                    , nodeConfNet = net
+                    , nodeConfEvents = (`sendSTM` node_inbox)
+                    , nodeConfTimeout = 10
+                    }
+        withNode cfg $ \(mgr, ch) ->
+            lift $
+            f TestNode {testMgr = mgr, testChain = ch, nodeEvents = node_inbox}
