diff --git a/pusher-http-haskell.cabal b/pusher-http-haskell.cabal
--- a/pusher-http-haskell.cabal
+++ b/pusher-http-haskell.cabal
@@ -1,6 +1,6 @@
 cabal-version: 1.18
 name:          pusher-http-haskell
-version:       2.0.0.3
+version:       2.1.0.0
 license:       MIT
 license-file:  LICENSE
 copyright:     (c) Will Sewell, 2016
diff --git a/src/Network/Pusher.hs b/src/Network/Pusher.hs
--- a/src/Network/Pusher.hs
+++ b/src/Network/Pusher.hs
@@ -64,7 +64,11 @@
 
     -- ** Trigger events
     trigger,
+    triggerBatch,
 
+    -- *** Event type for 'triggerBatch'
+    Event (..),
+
     -- ** Channel queries
     channels,
     channel,
@@ -99,6 +103,7 @@
 import qualified Data.Text as T
 import Network.Pusher.Data
   ( Address (..),
+    Event (..),
     Pusher (..),
     Settings (..),
     Token (..),
@@ -146,6 +151,18 @@
   (requestParams, requestBody) <-
     Pusher.mkTriggerRequest pusher chans event dat socketId
       <$> getSystemTimeSeconds
+  liftIO $ HTTP.post (pConnectionManager pusher) requestParams requestBody
+
+-- | Trigger multiple events.
+triggerBatch ::
+  MonadIO m =>
+  Pusher ->
+  -- | The list of events to trigger.
+  [Event] ->
+  m (Either PusherError ())
+triggerBatch pusher events = do
+  (requestParams, requestBody) <-
+    Pusher.mkTriggerBatchRequest pusher events <$> getSystemTimeSeconds
   liftIO $ HTTP.post (pConnectionManager pusher) requestParams requestBody
 
 -- | Query a list of channels for information.
diff --git a/src/Network/Pusher/Data.hs b/src/Network/Pusher/Data.hs
--- a/src/Network/Pusher/Data.hs
+++ b/src/Network/Pusher/Data.hs
@@ -13,6 +13,7 @@
     Pusher (..),
     newPusher,
     newPusherWithConnManager,
+    Event (..),
   )
 where
 
@@ -20,6 +21,8 @@
 import Data.Aeson ((.:), (.:?))
 import qualified Data.Aeson as A
 import qualified Data.ByteString as B
+import Data.Maybe (maybeToList)
+import qualified Data.Text as T
 import Data.Text.Encoding (encodeUtf8)
 import Data.Word (Word16, Word32)
 import Network.HTTP.Client (Manager)
@@ -142,3 +145,24 @@
           pToken = pusherToken settings,
           pConnectionManager = connectionManager
         }
+
+data Event
+  = Event
+      { -- | Channel to trigger on.
+        eventChannel :: T.Text,
+        -- | Event name.
+        eventName :: T.Text,
+        -- | Event data. Often encoded JSON.
+        eventData :: T.Text,
+        -- | An optional socket ID of a connection you wish to exclude.
+        eventSocketId :: Maybe T.Text
+      }
+
+instance A.ToJSON Event where
+  toJSON (Event channel name dat socketId) =
+    A.object $
+      [ ("name", A.String name),
+        ("channel", A.String channel),
+        ("data", A.String dat)
+      ]
+        ++ maybeToList (fmap (\sID -> ("socket_id", A.String sID)) socketId)
diff --git a/src/Network/Pusher/Internal.hs b/src/Network/Pusher/Internal.hs
--- a/src/Network/Pusher/Internal.hs
+++ b/src/Network/Pusher/Internal.hs
@@ -7,6 +7,7 @@
 -- Stability   : stable
 module Network.Pusher.Internal
   ( mkTriggerRequest,
+    mkTriggerBatchRequest,
     mkChannelsRequest,
     mkChannelRequest,
     mkUsersRequest,
@@ -21,7 +22,7 @@
 import Data.Text.Encoding (encodeUtf8)
 import Data.Word (Word64)
 import Network.HTTP.Types (Query)
-import Network.Pusher.Data (Pusher (..))
+import Network.Pusher.Data (Event, Pusher (..))
 import Network.Pusher.Internal.Auth (makeQS)
 import Network.Pusher.Internal.HTTP
   ( RequestParams (RequestParams),
@@ -50,6 +51,16 @@
             ++ maybeToList (fmap (\sID -> ("socket_id", A.String sID)) socketId)
       bodyBS = BL.toStrict $ A.encode body
    in (mkPostRequest pusher "events" [] bodyBS timestamp, body)
+
+mkTriggerBatchRequest ::
+  Pusher ->
+  [Event] ->
+  Word64 ->
+  (RequestParams, A.Value)
+mkTriggerBatchRequest pusher events timestamp =
+  let body = A.object [("batch", A.toJSON events)]
+      bodyBS = BL.toStrict $ A.encode body
+   in (mkPostRequest pusher "batch_events" [] bodyBS timestamp, body)
 
 mkChannelsRequest ::
   Pusher ->
