diff --git a/pusher-http-haskell.cabal b/pusher-http-haskell.cabal
--- a/pusher-http-haskell.cabal
+++ b/pusher-http-haskell.cabal
@@ -1,5 +1,5 @@
 name:                 pusher-http-haskell
-version:              1.0.0.0
+version:              1.1.0.0
 cabal-version:        >=1.18
 build-type:           Simple
 license:              MIT
diff --git a/src/Network/Pusher.hs b/src/Network/Pusher.hs
--- a/src/Network/Pusher.hs
+++ b/src/Network/Pusher.hs
@@ -13,17 +13,11 @@
 well as functions for generating auth signatures for private and presence
 channels.
 
-The idea is that you must create a Pusher data structure with your credentials,
-then your write your block of code that calls functions from this library, and
-finally "run" this code with the Pusher data structure you created.
-
-The types of the functions are general enough to allow you to use the provided
-PusherM as the return type, or PusherT if you wish to use other monads in your
-applications monad transformer stack.
+First create a 'Pusher' data structure with your Pusher 'Credentials', and then
+call the functions defined in this module to make the HTTP requests.
 
-The functions return a MonadError type which means any can fail, and you must
-handle these failures in your client application. In the simplist case you can
-instantiate the type to an Either and case split on it.
+If any of the requests fail, the return values of the functions will result in
+a 'Left' 'PusherError' when run.
 
 An example of how you would use these functions:
 
@@ -47,19 +41,37 @@
 See https://pusher.com/docs/rest_api for more detail on the HTTP requests.
 -}
 module Network.Pusher (
-  -- * The Pusher config type
+  -- * Data types
+  -- ** Pusher config type
     Pusher(..)
   , Credentials(..)
+  , AppID
+  , AppKey
+  , AppSecret
   , getPusher
   , getPusherWithHost
   , getPusherWithConnManager
-  -- * Events
+  -- ** Channels
+  , Channel(..)
+  , ChannelName
+  , ChannelType(..)
+  , renderChannel
+  , renderChannelPrefix
+  , parseChannel
+  -- ** Events
+  , Event
+  , EventData
+  , SocketID
+  -- * HTTP Requests
+  -- ** Trigger events
   , trigger
-  -- * Channel queries
+  -- ** Channel queries
   , channels
   , channel
   , users
   -- * Authentication
+  , AuthString
+  , AuthSignature
   , authenticatePresence
   , authenticatePrivate
   -- * Errors
@@ -72,7 +84,6 @@
 import Control.Monad.IO.Class (MonadIO, liftIO)
 import Data.Maybe (maybeToList)
 import Data.Monoid ((<>))
-import Data.Text.Encoding (encodeUtf8)
 import Network.HTTP.Client (Manager)
 import qualified Data.Aeson as A
 import qualified Data.ByteString as B
@@ -80,29 +91,39 @@
 import qualified Data.Text as T
 
 import Network.Pusher.Data
-  ( Pusher(..)
+  ( AppID
+  , AppKey
+  , AppSecret
+  , Channel(..)
+  , ChannelName
+  , ChannelType(..)
   , Credentials(..)
+  , Event
+  , EventData
+  , Pusher(..)
+  , SocketID
   , getPusher
   , getPusherWithHost
   , getPusherWithConnManager
+  , parseChannel
+  , renderChannel
+  , renderChannelPrefix
   )
 import Network.Pusher.Error(PusherError(..))
 import Network.Pusher.Internal.Auth
-  ( authenticatePresence
+  ( AuthSignature
+  , AuthString
+  , authenticatePresence
   , authenticatePrivate
   , makeQS
   )
 import Network.Pusher.Internal.Util (getTime)
 import Network.Pusher.Protocol
-  ( Channel
-  , ChannelInfoQuery
+  ( ChannelInfoQuery
   , ChannelsInfo
   , ChannelsInfoQuery
-  , ChannelType
   , FullChannelInfo
   , Users
-  , renderChannel
-  , renderChannelPrefix
   , toURLParam
   )
 import qualified Network.Pusher.Internal as Pusher
@@ -114,11 +135,10 @@
   => Pusher
   -> [Channel]
   -- ^The list of channels to trigger to
-  -> T.Text
-  -- ^The event
-  -> T.Text
-  -- ^The data to send (often encoded JSON)
-  -> Maybe T.Text
+  -> Event
+  -> EventData
+  -- ^Often encoded JSON
+  -> Maybe SocketID
   -- ^An optional socket ID of a connection you wish to exclude
   -> m (Either PusherError ())
 trigger pusher chans event dat socketId =
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
@@ -1,35 +1,64 @@
+{-# LANGUAGE DeriveGeneric #-}
+
 {-|
 Module      : Network.Pusher.Data
-Description : Data structure to store Pusher config
+Description : Data structure representing Pusher concepts and config
 Copyright   : (c) Will Sewell, 2016
 Licence     : MIT
 Maintainer  : me@willsewell.com
 Stability   : experimental
 
-You must create an instance of this datatype with your particular Pusher app
-credentials in order to run the main API functions.
+You must create an instance of the Pusher datatype with your particular Pusher
+app credentials in order to run the main API functions.
+
+The other types represent Pusher channels and Pusher event fields.
 -}
-module Network.Pusher.Data
-  ( Pusher(..)
+module Network.Pusher.Data (
+  -- * Pusher config data type
+    AppID
+  , AppKey
+  , AppSecret
+  , Pusher(..)
   , Credentials(..)
   , getPusher
   , getPusherWithHost
   , getPusherWithConnManager
+  -- * Channels
+  , Channel(..)
+  , ChannelName
+  , ChannelType(..)
+  , renderChannel
+  , renderChannelPrefix
+  , parseChannel
+  -- Events
+  , Event
+  , EventData
+  , SocketID
   ) where
 
 import Control.Applicative ((<$>), (<*>))
 import Control.Monad.IO.Class (MonadIO, liftIO)
 import Data.Aeson ((.:))
+import Data.Foldable (asum)
+import Data.Hashable (Hashable)
 import Data.Maybe (fromMaybe)
 import Data.Monoid ((<>))
 import Data.Text.Encoding (encodeUtf8)
+import GHC.Generics (Generic)
 import Network.HTTP.Client (Manager, defaultManagerSettings, newManager)
+import Test.QuickCheck (Arbitrary, arbitrary, elements)
 import qualified Data.Aeson as A
 import qualified Data.ByteString as B
 import qualified Data.Text as T
 
 import Network.Pusher.Internal.Util (failExpectObj, show')
 
+type AppID = Integer
+
+type AppKey = B.ByteString
+
+type AppSecret = B.ByteString
+
 -- |All the required configuration needed to interact with the API.
 data Pusher = Pusher
   { pusherHost :: T.Text
@@ -40,9 +69,9 @@
 
 -- |The credentials for the current app.
 data Credentials = Credentials
-  { credentialsAppID :: Integer
-  , credentialsAppKey :: B.ByteString
-  , credentialsAppSecret :: B.ByteString
+  { credentialsAppID :: AppID
+  , credentialsAppKey :: AppKey
+  , credentialsAppSecret :: AppSecret
   }
 
 instance A.FromJSON Credentials where
@@ -79,3 +108,54 @@
 
 getConnManager :: MonadIO m => m Manager
 getConnManager = liftIO $ newManager defaultManagerSettings
+
+type ChannelName = T.Text
+
+-- |The possible types of Pusher channe.
+data ChannelType = Public | Private | Presence deriving (Eq, Generic, Show)
+
+instance Hashable ChannelType
+
+instance Arbitrary ChannelType where
+  arbitrary = elements [Public, Private, Presence]
+
+renderChannelPrefix :: ChannelType -> T.Text
+renderChannelPrefix Public = ""
+renderChannelPrefix Private = "private-"
+renderChannelPrefix Presence = "presence-"
+
+-- |The channel name (not including the channel type prefix) and its type.
+data Channel = Channel
+  { channelType :: ChannelType
+  , channelName :: ChannelName
+  } deriving (Eq, Generic, Show)
+
+instance Hashable Channel
+
+instance Arbitrary Channel where
+  arbitrary = Channel <$> arbitrary <*> (T.pack <$> arbitrary)
+
+renderChannel :: Channel -> T.Text
+renderChannel (Channel cType cName) = renderChannelPrefix cType <> cName
+
+-- |Convert string representation, e.g. private-chan into the datatype
+parseChannel :: T.Text -> Channel
+parseChannel chan =
+  -- Attempt to parse it as a private or presence channel; default to public
+  fromMaybe
+    (Channel Public chan)
+    (asum [parseChanAs Private,  parseChanAs Presence])
+ where
+  parseChanAs chanType =
+    let split = T.splitOn (renderChannelPrefix chanType) chan in
+    -- If the prefix appears at the start, then the first element will be empty
+    if length split > 1 && T.null (head split) then
+      Just $ Channel chanType (T.concat $ tail split)
+    else
+      Nothing
+
+type Event = T.Text
+
+type EventData = T.Text
+
+type SocketID = T.Text
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,9 +7,7 @@
 Stability   : experimental
 -}
 module Network.Pusher.Internal
-  ( PusherRequestParams(..)
-  , PusherRequestBody
-  , mkTriggerRequest
+  ( mkTriggerRequest
   , mkChannelsRequest
   , mkChannelRequest
   , mkUsersRequest
@@ -24,39 +22,41 @@
 import qualified Data.ByteString.Lazy as BL
 import qualified Data.Text as T
 
-import Network.Pusher.Data (Pusher(..), Credentials(..))
+import Network.Pusher.Data
+  ( Channel
+  , ChannelType
+  , Credentials(..)
+  , Event
+  , EventData
+  , Pusher(..)
+  , SocketID
+  , renderChannel
+  , renderChannelPrefix
+  )
 import Network.Pusher.Error(PusherError(..))
 import Network.Pusher.Internal.Auth (makeQS)
+import Network.Pusher.Internal.HTTP
+  ( RequestBody
+  , RequestParams(RequestParams)
+  , RequestQueryString
+  )
 import Network.Pusher.Protocol
-  ( Channel
-  , ChannelInfoQuery
+  ( ChannelInfoQuery
   , ChannelsInfo
   , ChannelsInfoQuery
-  , ChannelType
   , FullChannelInfo
   , Users
-  , renderChannel
-  , renderChannelPrefix
   , toURLParam
   )
 
-data PusherRequestParams = PusherRequestParams
-  { pusherRequestEndpoint :: T.Text
-  -- ^The API endpoint, for example http://api.pusherapp.com/apps/123/events
-  , pusherRequestQueryString :: [(B.ByteString, B.ByteString)]
-  -- ^List of query string parameters as key-value tuples
-  }
-
-type PusherRequestBody = A.Value
-
 mkTriggerRequest
   :: Pusher
   -> [Channel]
-  -> T.Text
-  -> T.Text
-  -> Maybe T.Text
+  -> Event
+  -> EventData
+  -> Maybe SocketID
   -> Int
-  -> Either PusherError (PusherRequestParams, PusherRequestBody)
+  -> Either PusherError (RequestParams, RequestBody)
 mkTriggerRequest pusher chans event dat socketId time = do
     when
       (length chans > 10)
@@ -79,7 +79,7 @@
   -> T.Text
   -> ChannelsInfoQuery
   -> Int
-  -> PusherRequestParams
+  -> RequestParams
 mkChannelsRequest pusher channelTypeFilter prefixFilter attributes time =
   let
     prefix = maybe "" renderChannelPrefix channelTypeFilter <> prefixFilter
@@ -95,7 +95,7 @@
   -> Channel
   -> ChannelInfoQuery
   -> Int
-  -> PusherRequestParams
+  -> RequestParams
 mkChannelRequest pusher chan attributes time =
   let
     params = [("info", encodeUtf8 $ toURLParam attributes)]
@@ -103,7 +103,7 @@
   in
     mkGetRequest pusher subPath params time
 
-mkUsersRequest :: Pusher -> Channel -> Int -> PusherRequestParams
+mkUsersRequest :: Pusher -> Channel -> Int -> RequestParams
 mkUsersRequest pusher chan time =
   let
     subPath = "channels/" <> renderChannel chan <> "/users"
@@ -113,29 +113,29 @@
 mkGetRequest
   :: Pusher
   -> T.Text
-  -> [(B.ByteString, B.ByteString)]
+  -> RequestQueryString
   -> Int
-  -> PusherRequestParams
+  -> RequestParams
 mkGetRequest pusher subPath params time =
   let
     (ep, fullPath) = mkEndpoint pusher subPath
     qs = mkQS pusher "GET" fullPath params "" time
   in
-    PusherRequestParams ep qs
+    RequestParams ep qs
 
 mkPostRequest
   :: Pusher
   -> T.Text
-  -> [(B.ByteString, B.ByteString)]
+  -> RequestQueryString
   -> B.ByteString
   -> Int
-  -> PusherRequestParams
+  -> RequestParams
 mkPostRequest pusher subPath params bodyBS time =
   let
     (ep, fullPath) = mkEndpoint pusher subPath
     qs = mkQS pusher "POST" fullPath params bodyBS time
   in
-    PusherRequestParams ep qs
+    RequestParams ep qs
 
 -- |Build a full endpoint from the details in Pusher and the subPath.
 mkEndpoint
@@ -153,10 +153,10 @@
   :: Pusher
   -> T.Text
   -> T.Text
-  -> [(B.ByteString, B.ByteString)]
+  -> RequestQueryString
   -> B.ByteString
   -> Int
-  -> [(B.ByteString, B.ByteString)]
+  -> RequestQueryString
 mkQS pusher =
   let
     credentials = pusherCredentials pusher
diff --git a/src/Network/Pusher/Internal/Auth.hs b/src/Network/Pusher/Internal/Auth.hs
--- a/src/Network/Pusher/Internal/Auth.hs
+++ b/src/Network/Pusher/Internal/Auth.hs
@@ -13,7 +13,9 @@
 users; these functions are re-exported in the main Pusher module.
 -}
 module Network.Pusher.Internal.Auth
-  ( authenticatePresence
+  ( AuthString
+  , AuthSignature
+  , authenticatePresence
   , authenticatePresenceWithEncoder
   , authenticatePrivate, makeQS
   ) where
@@ -22,29 +24,40 @@
 import Data.Text.Encoding (encodeUtf8)
 import GHC.Exts (sortWith)
 import qualified Data.Aeson as A
+import qualified Data.Aeson.Encode as A
 import qualified Data.ByteString as B
 import qualified Data.ByteString.Char8 as BC
 import qualified Data.ByteString.Base16 as B16
 import qualified Data.ByteString.Lazy as BL
 import qualified Data.Text as T
+import qualified Data.Text.Lazy as TL
+import qualified Data.Text.Lazy.Builder as TL
 import qualified Crypto.Hash.MD5 as MD5
 import qualified Crypto.Hash.SHA256 as SHA256
 import qualified Crypto.MAC.HMAC as HMAC
 
-import Network.Pusher.Data (Credentials(..))
+import Network.Pusher.Data
+  ( AppKey
+  , AppSecret
+  , Channel
+  , Credentials(..)
+  , SocketID
+  , renderChannel
+  )
+import Network.Pusher.Internal.HTTP (RequestQueryString)
 import Network.Pusher.Internal.Util (show')
 
 -- |Generate the required query string parameters required to send API requests
 -- to Pusher.
 makeQS
-  :: B.ByteString
-  -> B.ByteString
+  :: AppKey
+  -> AppSecret
   -> T.Text
   -> T.Text
-  -> [(B.ByteString, B.ByteString)] -- ^Any additional parameters
+  -> RequestQueryString -- ^Any additional parameters
   -> B.ByteString
   -> Int -- ^Current UNIX timestamp
-  -> [(B.ByteString, B.ByteString)]
+  -> RequestQueryString
 makeQS appKey appSecret method path params body ts =
   let
     -- Generate all required parameters and add them to the list of existing ones
@@ -65,24 +78,34 @@
     ("auth_signature", authSig) : allParams
 
 -- |Render key-value tuple mapping of query string parameters into a string.
-formQueryString :: [(B.ByteString, B.ByteString)] -> B.ByteString
+formQueryString :: RequestQueryString -> B.ByteString
 formQueryString =
   B.intercalate "&" . map (\(a, b) -> a <> "=" <> b)
 
+-- | The bytestring to sign with the app secret to create a signature from.
+type AuthString = B.ByteString
+
+-- | A Pusher auth signature.
+type AuthSignature = B.ByteString
+
 -- |Create a Pusher auth signature of a string using the provided credentials.
-authSignature :: B.ByteString -> B.ByteString -> B.ByteString
+authSignature :: AppSecret -> AuthString -> AuthSignature
 authSignature appSecret authString =
   B16.encode $ HMAC.hmac SHA256.hash 64 appSecret authString
 
+
 -- |Generate an auth signature of the form "app_key:auth_sig" for a user of a
 -- private channel.
 authenticatePrivate
-  :: Credentials -> B.ByteString -> B.ByteString -> B.ByteString
-authenticatePrivate cred socketID channelName =
+  :: Credentials
+  -> SocketID
+  -> Channel
+  -> AuthSignature
+authenticatePrivate cred socketID channel =
   let
     sig = authSignature
       (credentialsAppSecret cred)
-      (socketID <> ":" <> channelName)
+      (encodeUtf8 $ socketID <> ":" <> renderChannel channel)
   in
     credentialsAppKey cred <> ":" <> sig
 
@@ -90,27 +113,30 @@
 -- presence channel.
 authenticatePresence
   :: A.ToJSON a
-  => Credentials -> B.ByteString -> B.ByteString -> a -> B.ByteString
+  => Credentials
+  -> SocketID
+  -> Channel
+  -> a
+  -> AuthSignature
 authenticatePresence =
-  authenticatePresenceWithEncoder (BL.toStrict . A.encode)
+  authenticatePresenceWithEncoder
+    (TL.toStrict . TL.toLazyText . A.encodeToTextBuilder . A.toJSON)
 
 -- |As above, but allows the encoder of the user data to be specified. This is
 -- useful for testing because the encoder can be mocked; aeson's encoder enodes
 -- JSON object fields in arbitrary orders, which makes it impossible to test.
 authenticatePresenceWithEncoder
   :: A.ToJSON a
-  => (a -> B.ByteString) -- ^The encoder of the user data.
+  => (a -> T.Text) -- ^The encoder of the user data.
   -> Credentials
-  -> B.ByteString
-  -> B.ByteString
+  -> SocketID
+  -> Channel
   -> a
-  -> B.ByteString
-authenticatePresenceWithEncoder userEncoder cred socketID channelName userData =
+  -> AuthSignature
+authenticatePresenceWithEncoder userEncoder cred socketID channel userData =
   let
-    sig = authSignature (credentialsAppSecret cred)
-      ( socketID <> ":"
-      <> channelName <> ":"
-      <> userEncoder userData
-      )
+    authString =
+      encodeUtf8 $ socketID <> ":" <> renderChannel channel <> ":" <> userEncoder userData
+    sig = authSignature (credentialsAppSecret cred) authString
   in
     credentialsAppKey cred <> ":" <> sig
diff --git a/src/Network/Pusher/Internal/HTTP.hs b/src/Network/Pusher/Internal/HTTP.hs
--- a/src/Network/Pusher/Internal/HTTP.hs
+++ b/src/Network/Pusher/Internal/HTTP.hs
@@ -13,7 +13,13 @@
 values to the typclasses we are using in this library. Non 200 responses are
 converted into MonadError errors.
 -}
-module Network.Pusher.Internal.HTTP (get, post) where
+module Network.Pusher.Internal.HTTP
+  ( RequestParams(..)
+  , RequestQueryString
+  , RequestBody
+  , get
+  , post
+  ) where
 
 import Control.Arrow (second)
 import Control.Exception (displayException)
@@ -21,20 +27,6 @@
 import Control.Monad.Trans.Except (ExceptT(ExceptT), throwE)
 import Data.Monoid ((<>))
 import Data.Text.Encoding (decodeUtf8')
-import Network.HTTP.Client
-  ( Manager
-  , Request
-  , RequestBody(RequestBodyLBS)
-  , Response
-  , httpLbs
-  , method
-  , parseUrl
-  , requestBody
-  , requestHeaders
-  , responseBody
-  , responseStatus
-  , setQueryString
-  )
 import Network.HTTP.Types.Header (hContentType)
 import Network.HTTP.Types.Method (methodPost)
 import Network.HTTP.Types.Status (statusCode, statusMessage)
@@ -43,20 +35,31 @@
 import qualified Data.ByteString.Char8 as BC
 import qualified Data.ByteString.Lazy as BL
 import qualified Data.Text as T
+import qualified Network.HTTP.Client as HTTP.Client
 
 import Network.Pusher.Error (PusherError(..))
-import Network.Pusher.Internal (PusherRequestParams(PusherRequestParams))
 import Network.Pusher.Internal.Util (show')
 
+data RequestParams = RequestParams
+  { requestEndpoint :: T.Text
+  -- ^The API endpoint, for example http://api.pusherapp.com/apps/123/events
+  , requestQueryString :: RequestQueryString
+  -- ^List of query string parameters as key-value tuples
+  }
+
+type RequestQueryString = [(B.ByteString, B.ByteString)]
+
+type RequestBody = A.Value
+
 -- |Issue an HTTP GET request. On a 200 response, the response body is returned.
 -- On failure, an error will be thrown into the MonadError instance.
 get
   :: A.FromJSON a
-  => Manager
-  -> PusherRequestParams
+  => HTTP.Client.Manager
+  -> RequestParams
   -> ExceptT PusherError IO a
   -- ^The body of the response
-get connManager (PusherRequestParams ep qs) = do
+get connManager (RequestParams ep qs) = do
   req <- ExceptT $ return $ mkRequest ep qs
   resp <- doReqest connManager req
   either
@@ -67,38 +70,41 @@
 -- |Issue an HTTP POST request.
 post
   :: A.ToJSON a
-  => Manager
-  -> PusherRequestParams
+  => HTTP.Client.Manager
+  -> RequestParams
   -> a
   -> ExceptT PusherError IO ()
-post connManager (PusherRequestParams ep qs) body = do
+post connManager (RequestParams ep qs) body = do
   req <- ExceptT $ return $ mkPost (A.encode body) <$> mkRequest ep qs
   _ <- doReqest connManager req
   return ()
 
 mkRequest
   :: T.Text
-  -> [(B.ByteString, B.ByteString)]
-  -> Either PusherError Request
+  -> RequestQueryString
+  -> Either PusherError HTTP.Client.Request
 mkRequest ep qs =
-  case parseUrl $ T.unpack ep of
+  case HTTP.Client.parseRequest $ T.unpack ep of
     Nothing -> Left $ PusherArgumentError $ "failed to parse url: " <> ep
-    Just req -> Right $ setQueryString (map (second Just) qs) req
+    Just req -> Right $ HTTP.Client.setQueryString (map (second Just) qs) req
 
-mkPost :: BL.ByteString -> Request -> Request
+mkPost :: BL.ByteString -> HTTP.Client.Request -> HTTP.Client.Request
 mkPost body req =
   req
-    { method = methodPost
-    , requestHeaders = [(hContentType, "application/json")]
-    , requestBody = RequestBodyLBS body
+    { HTTP.Client.method = methodPost
+    , HTTP.Client.requestHeaders = [(hContentType, "application/json")]
+    , HTTP.Client.requestBody = HTTP.Client.RequestBodyLBS body
     }
 
-doReqest :: Manager -> Request -> ExceptT PusherError IO BL.ByteString
+doReqest
+  :: HTTP.Client.Manager
+  -> HTTP.Client.Request
+  -> ExceptT PusherError IO BL.ByteString
 doReqest connManager req = do
-  response <- liftIO $ httpLbs req connManager
-  let status = responseStatus response
+  response <- liftIO $ HTTP.Client.httpLbs req connManager
+  let status = HTTP.Client.responseStatus response
   if statusCode status == 200 then
-    return $ responseBody response
+    return $ HTTP.Client.responseBody response
   else
     let decoded = decodeUtf8' $ statusMessage status in
     throwE $
diff --git a/src/Network/Pusher/Protocol.hs b/src/Network/Pusher/Protocol.hs
--- a/src/Network/Pusher/Protocol.hs
+++ b/src/Network/Pusher/Protocol.hs
@@ -15,20 +15,16 @@
 There are also types for query string parameters.
 -}
 module Network.Pusher.Protocol
-  ( Channel(..)
-  , ChannelInfo(..)
+  ( ChannelInfo(..)
   , ChannelInfoAttributes(..)
   , ChannelInfoQuery(..)
   , ChannelsInfo(..)
   , ChannelsInfoQuery(..)
   , ChannelsInfoAttributes(..)
-  , ChannelType(..)
   , FullChannelInfo(..)
   , User(..)
   , Users(..)
-  , parseChannel
-  , renderChannel
-  , renderChannelPrefix
+  , ToURLParam
   , toURLParam
   ) where
 
@@ -46,49 +42,7 @@
 import qualified Data.Text as T
 
 import Network.Pusher.Internal.Util (failExpectObj)
-
--- |The possible types of Pusher channe.
-data ChannelType = Public | Private | Presence deriving (Eq, Generic, Show)
-
-instance Hashable ChannelType
-
-instance Arbitrary ChannelType where
-  arbitrary = elements [Public, Private, Presence]
-
-renderChannelPrefix :: ChannelType -> T.Text
-renderChannelPrefix Public = ""
-renderChannelPrefix Private = "private-"
-renderChannelPrefix Presence = "presence-"
-
--- |The channel name (not including the channel type prefix) and its type.
-data Channel = Channel
-  { channelType :: ChannelType
-  , channelName :: T.Text
-  } deriving (Eq, Generic, Show)
-
-instance Hashable Channel
-
-instance Arbitrary Channel where
-  arbitrary = Channel <$> arbitrary <*> (T.pack <$> arbitrary)
-
-renderChannel :: Channel -> T.Text
-renderChannel (Channel cType cName) = renderChannelPrefix cType <> cName
-
--- |Convert string representation, e.g. private-chan into the datatype
-parseChannel :: T.Text -> Channel
-parseChannel chan =
-  -- Attempt to parse it as a private or presence channel; default to public
-  fromMaybe
-    (Channel Public chan)
-    (asum [parseChanAs Private,  parseChanAs Presence])
- where
-  parseChanAs chanType =
-    let split = T.splitOn (renderChannelPrefix chanType) chan in
-    -- If the prefix appears at the start, then the first element will be empty
-    if length split > 1 && T.null (head split) then
-      Just $ Channel chanType (T.concat $ tail split)
-    else
-      Nothing
+import Network.Pusher.Data (Channel, parseChannel)
 
 -- |Types that can be serialised to a querystring parameter value.
 class ToURLParam a where
diff --git a/test/Auth.hs b/test/Auth.hs
--- a/test/Auth.hs
+++ b/test/Auth.hs
@@ -2,7 +2,11 @@
 
 import Test.Hspec (Spec, describe, it, shouldBe)
 
-import Network.Pusher (Credentials(..))
+import Network.Pusher
+  ( Channel(..)
+  , ChannelType(Private, Presence)
+  , Credentials(..)
+  )
 import Network.Pusher.Internal.Auth
   ( authenticatePrivate
   , authenticatePresenceWithEncoder
@@ -29,7 +33,7 @@
   describe "Auth.authenticatePrivate" $
     it "works" $
       -- Data from https://pusher.com/docs/auth_signatures#worked-example
-      authenticatePrivate credentials "1234.1234" "private-foobar"
+      authenticatePrivate credentials "1234.1234" (Channel Private "foobar")
       `shouldBe` "278d425bdf160c739803:58df8b0c36d6982b82c3ecf6b4662e34fe8c25bba48f5369f135bf843651c3a4"
 
   describe "Auth.authenticatePresenceWithEncoder" $
@@ -42,7 +46,7 @@
           (const userData)
           credentials
           "1234.1234"
-          "presence-foobar"
+          (Channel Presence "foobar")
           ("doesn't matter" :: String)
         `shouldBe` "278d425bdf160c739803:afaed3695da2ffd16931f457e338e6c9f2921fa133ce7dac49f529792be6304c"
 
diff --git a/test/Protocol.hs b/test/Protocol.hs
--- a/test/Protocol.hs
+++ b/test/Protocol.hs
@@ -7,16 +7,18 @@
 import qualified Data.HashSet as HS
 import qualified Data.Text as T
 
-import Network.Pusher.Protocol
+import Network.Pusher
   ( Channel(..)
-  , ChannelInfo(..)
-  , ChannelsInfo(..)
   , ChannelType(Public, Presence, Private)
+  , parseChannel
+  , renderChannel
+  )
+import Network.Pusher.Protocol
+  ( ChannelInfo(..)
+  , ChannelsInfo(..)
   , FullChannelInfo(..)
   , User(..)
   , Users(..)
-  , parseChannel
-  , renderChannel
   )
 
 test :: Spec
