diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,13 @@
+## 4.0.0 (19 Sep 2017)
+
+* Use the latest Stack resolver 9.5
+* Add userID fields to event sources
+* Add 'Get group/room member profile' APIs
+* Add 'image carousel' template message
+* Add 'datetimepicker' template action type
+* Implement 'Get group/room member IDs' APIs
+* Use DuplicateRecordFields to simplify field names
+
 ## 3.1.0 (26 May 2017)
 
 * Add support for file message
diff --git a/line.cabal b/line.cabal
--- a/line.cabal
+++ b/line.cabal
@@ -1,5 +1,5 @@
 name:                line
-version:             3.1.0
+version:             4.0.0
 synopsis:            Haskell SDK for the LINE API
 homepage:            https://github.com/noraesae/line
 license:             BSD3
diff --git a/src/Line/Messaging/API.hs b/src/Line/Messaging/API.hs
--- a/src/Line/Messaging/API.hs
+++ b/src/Line/Messaging/API.hs
@@ -21,6 +21,10 @@
   reply,
   getContent,
   getProfile,
+  getGroupMemberProfile,
+  getRoomMemberProfile,
+  getGroupMemberIDs,
+  getRoomMemberIDs,
   leaveRoom,
   leaveGroup,
   ) where
@@ -29,7 +33,8 @@
 import Control.Monad.Trans.Class (lift)
 import Control.Monad.Trans.Reader (runReaderT, ReaderT, ask)
 import Control.Monad.Trans.Except (runExceptT, ExceptT, throwE, catchE)
-import Data.Aeson (ToJSON(..), (.=), object, decode', eitherDecode')
+import Data.Aeson
+import Data.Maybe (fromMaybe)
 import Data.Text.Encoding (encodeUtf8)
 import Line.Messaging.API.Types
 import Line.Messaging.Types (ReplyToken)
@@ -193,6 +198,64 @@
   case eitherDecode' bs of
     Right profile -> return profile
     Left errStr -> lift . throwE . JSONDecodeError $ errStr
+
+-- | Get a profile of a user in a group, specified by the group ID and the user ID.
+--
+-- Please refer to <https://devdocs.line.me/en/#get-group-room-member-profile its API reference>
+-- for the difference between this API and 'getProfile'.
+getGroupMemberProfile :: ID -> ID -> APIIO Profile
+getGroupMemberProfile groupId userId = do
+  let url = "https://api.line.me/v2/bot/group/" ++ T.unpack groupId ++ "/member/" ++ T.unpack userId
+  bs <- get url
+  case eitherDecode' bs of
+    Right profile -> return profile
+    Left errStr -> lift . throwE . JSONDecodeError $ errStr
+
+-- | Get a profile of a user in a room, specified by the room ID and the user ID.
+--
+-- Please refer to <https://devdocs.line.me/en/#get-group-room-member-profile its API reference>
+-- for the difference between this API and 'getProfile'.
+getRoomMemberProfile :: ID -> ID -> APIIO Profile
+getRoomMemberProfile roomId userId = do
+  let url = "https://api.line.me/v2/bot/room/" ++ T.unpack roomId ++ "/member/" ++ T.unpack userId
+  bs <- get url
+  case eitherDecode' bs of
+    Right profile -> return profile
+    Left errStr -> lift . throwE . JSONDecodeError $ errStr
+
+data MemberIDs = MemberIDs [ID] (Maybe ContinuationToken)
+type ContinuationToken = T.Text
+
+instance FromJSON MemberIDs where
+  parseJSON (Object v) = MemberIDs <$> v .: "memberIds" <*> v .:? "next"
+  parseJSON _ = fail "ContList"
+
+getMemberIDs :: String -> Maybe T.Text -> ID -> APIIO [ID]
+getMemberIDs base token id' = do
+  let url = base ++ T.unpack id' ++ "/members/ids" ++ fromMaybe "" (("?start=" ++) . T.unpack <$> token)
+  bs <- get url
+  case eitherDecode' bs of
+    Right (MemberIDs ids Nothing) -> return ids
+    Right (MemberIDs ids token') -> (ids ++) <$> getMemberIDs base token' id'
+    Left errStr -> lift . throwE . JSONDecodeError $ errStr
+
+-- | Gets the user profile of a member of a group that the bot is in.
+--
+-- FYI: This feature is only available for LINE@ Approved accounts or official accounts.
+--
+-- For more information, please refer to
+-- <https://devdocs.line.me/en/#get-group-room-member-ids its API reference>.
+getGroupMemberIDs :: ID -> APIIO [ID]
+getGroupMemberIDs = getMemberIDs "https://api.line.me/v2/bot/group/" Nothing
+
+-- | Gets the user profile of a member of a room that the bot is in.
+--
+-- FYI: This feature is only available for LINE@ Approved accounts or official accounts.
+--
+-- For more information, please refer to
+-- <https://devdocs.line.me/en/#get-group-room-member-ids its API reference>.
+getRoomMemberIDs :: ID -> APIIO [ID]
+getRoomMemberIDs = getMemberIDs "https://api.line.me/v2/bot/room/" Nothing
 
 leave :: String -> ID -> APIIO ()
 leave type' id' = do
diff --git a/src/Line/Messaging/API/Types.hs b/src/Line/Messaging/API/Types.hs
--- a/src/Line/Messaging/API/Types.hs
+++ b/src/Line/Messaging/API/Types.hs
@@ -2,6 +2,7 @@
 This module provides types to be used with "Line.Messaging.API".
 -}
 
+{-# LANGUAGE DuplicateRecordFields #-}
 {-# LANGUAGE ExistentialQuantification #-}
 {-# LANGUAGE FlexibleInstances #-}
 {-# LANGUAGE StandaloneDeriving #-}
@@ -34,9 +35,12 @@
   Buttons (..),
   Confirm (..),
   Carousel (..),
+  ImageCarousel (..),
   Column (..),
+  ImageColumn (..),
   Label,
   TemplateAction (..),
+  DatetimeMode (..),
   -- * Profile
   Profile (..),
   -- * Error types
@@ -115,8 +119,8 @@
 --
 -- It contains URLs of an original image and its preview. Its corresponding JSON
 -- spec is described <https://devdocs.line.me/en/#image here>.
-data Image = Image { getImageURL :: URL
-                   , getImagePreviewURL :: URL
+data Image = Image { getURL :: URL
+                   , getPreviewURL :: URL
                    }
              deriving (Eq, Show)
 
@@ -130,8 +134,8 @@
 --
 -- It contains URLs of an original video and its preview. Its corresponding JSON
 -- spec is described <https://devdocs.line.me/en/#video here>.
-data Video = Video { getVideoURL :: URL
-                   , getVideoPreviewURL :: URL
+data Video = Video { getURL :: URL
+                   , getPreviewURL :: URL
                    }
              deriving (Eq, Show)
 
@@ -146,8 +150,8 @@
 -- It contains a URL of an audio, and its duration in milliseconds. Its
 -- corresponding JSON spec is described
 -- <https://devdocs.line.me/en/#audio here>.
-data Audio = Audio { getAudioURL :: URL
-                   , getAudioDuration :: Integer
+data Audio = Audio { getURL :: URL
+                   , getDuration :: Integer
                    }
              deriving (Eq, Show)
 
@@ -167,7 +171,7 @@
 -- About the webhook usage, please refer to
 -- <./Line-Messaging-Webhook-Types.html#t:EventMessage EventMessage> in
 -- "Line.Messaging.Webhook.Types".
-data Location = Location { getLocationTitle :: T.Text
+data Location = Location { getTitle :: T.Text
                          , getAddress :: T.Text
                          , getLatitude :: Double
                          , getLongitude :: Double
@@ -221,13 +225,13 @@
 -- <https://devdocs.line.me/en/#imagemap-message image map message spec>.
 data ImageMap = ImageMap { getBaseImageURL :: URL
                            -- ^ <https://devdocs.line.me/en/#base-url Base URL> of images
-                         , getIMAltText :: T.Text
+                         , getAltText :: T.Text
                            -- ^ Alt text for devices not supporting image map
                          , getBaseImageSize :: (Integer, Integer)
                            -- ^ Image size tuple, (width, height) specifically.
                            -- The width to be set to 1040, the height to be set to
                            -- the value corresponding to a width of 1040.
-                         , getIMActions :: [ImageMapAction]
+                         , getActions :: [ImageMapAction]
                            -- ^ Actions to be executed when each area is tapped
                          }
                 deriving (Eq, Show)
@@ -273,14 +277,14 @@
 --
 -- It has a type parameter @t@ which means a template content type. The type is
 -- polymolphic, but 'Messageable' instances are defined only for 'Buttons',
--- 'Confirm', and 'Carousel'.
+-- 'Confirm', 'Carousel', and 'ImageCarousel'.
 --
 -- About how to send template message and what each field means, please
 -- refer to
 -- <https://devdocs.line.me/en/#template-messages template message spec>.
-data Template t = Template { getTemplateAltText :: T.Text
+data Template t = Template { getAltText :: T.Text
                              -- ^ Alt text for devices not supporting template message
-                           , getTemplate :: t
+                           , getTemplateContent :: t
                              -- ^ Template content type
                            }
                   deriving (Eq, Show)
@@ -305,6 +309,10 @@
   toType = templateType
   toObject = templateToObject
 
+instance Messageable (Template ImageCarousel) where
+  toType = templateType
+  toObject = templateToObject
+
 -- | The buttons content type for template message.
 --
 -- <<https://devdocs.line.me/images/buttons.png Buttons template>>
@@ -312,13 +320,13 @@
 -- For more details of each field, please refer to the
 -- <https://devdocs.line.me/en/#buttons Buttons> section in the LINE
 -- documentation.
-data Buttons = Buttons { getButtonsThumbnailURL :: Maybe URL
+data Buttons = Buttons { getThumbnailURL :: Maybe URL
                        -- ^ URL for thumbnail image
-                       , getButtonsTitle :: Maybe T.Text
+                       , getTitle :: Maybe T.Text
                        -- ^ Title text
-                       , getButtonsText :: T.Text
+                       , getText :: T.Text
                        -- ^ Description text
-                       , getButtonsActions :: [TemplateAction]
+                       , getActions :: [TemplateAction]
                        -- ^ A list of template actions, each of which represents
                        -- a button (max: 4)
                        }
@@ -342,9 +350,9 @@
 -- For more details of each field, please refer to the
 -- <https://devdocs.line.me/en/#confirm Confirm> section in the LINE
 -- documentation.
-data Confirm = Confirm { getConfirmText :: T.Text
+data Confirm = Confirm { getText :: T.Text
                        -- ^ Confirm text
-                       , getConfirmActions :: [TemplateAction]
+                       , getActions :: [TemplateAction]
                        -- ^ A list of template actions, each of which represents
                        -- a button (max: 2)
                        }
@@ -377,13 +385,13 @@
 --
 -- It has the same fields as 'Buttons', except that the number of actions is
 -- up to 3.
-data Column = Column { getColumnThumbnailURL :: Maybe URL
+data Column = Column { getThumbnailURL :: Maybe URL
                      -- ^ URL for thumbnail image
-                     , getColumnTitle :: Maybe T.Text
+                     , getTitle :: Maybe T.Text
                      -- ^ Title text
-                     , getColumnText :: T.Text
+                     , getText :: T.Text
                      -- ^ Description text
-                     , getColumnActions :: [TemplateAction]
+                     , getActions :: [TemplateAction]
                      -- ^ A list of template actions, each of which represents
                      -- a button (max: 3)
                      }
@@ -399,6 +407,40 @@
       , maybeToList $ ("title" .=) <$> maybeTitle
       ]
 
+-- | The image carousel content type for template message.
+--
+-- <<https://devdocs.line.me/images/image_carousel.png Image carousel template>>
+--
+-- For more details of each field, please refer to the
+-- <https://devdocs.line.me/en/#image-carousel Image carousel> section in the LINE
+-- documentation.
+data ImageCarousel = ImageCarousel { getColumns :: [ImageColumn]
+                                   -- ^ A list of columns for an image carousel template
+                                   }
+                   deriving (Eq, Show)
+
+instance ToJSON ImageCarousel where
+  toJSON (ImageCarousel columns) = object [ "type" .= ("image_carousel" :: T.Text)
+                                          , "columns" .= toJSON columns
+                                          ]
+
+-- | Actual contents of carousel template.
+--
+-- It has the same fields as 'Buttons', except that the number of actions is
+-- up to 3.
+data ImageColumn = ImageColumn { getImageURL :: URL
+                               -- ^ URL for thumbnail image
+                               , getAction :: TemplateAction
+                               -- ^ A template action
+                               }
+                 deriving (Eq, Show)
+
+instance ToJSON ImageColumn where
+  toJSON (ImageColumn url action) =
+    object [ "imageUrl" .= url
+           , "action" .= toJSON action
+           ]
+
 -- | Just a type alias for 'T.Text', used with 'TemplateAction'.
 type Label = T.Text
 
@@ -410,21 +452,33 @@
                       -- ^ Message action. When clicked, a specified text will
                       -- be sent into the same room by a user who clicked the
                       -- button.
-                    | TplPostbackAction Label Postback (Maybe T.Text)
+                    | TplPostbackAction Label T.Text (Maybe T.Text)
                       -- ^ Postback action. When clicked, a specified text will
                       -- be sent, and postback data will be sent to webhook
                       -- server as a postback event.
                     | TplURIAction Label URL
                       -- ^ URI action. When clicked, a web page with a specified
                       -- URI will open in the in-app browser.
+                    | TplDatetimePickerAction { label' :: (Maybe Label)
+                                              , data' :: T.Text
+                                              , mode' :: DatetimeMode
+                                              , initial' :: (Maybe T.Text)
+                                              , max' :: (Maybe T.Text)
+                                              , min' :: (Maybe T.Text)
+                                              }
+                      -- ^ Datetime picker action. When clicked, a postback action
+                      -- will be sent with the date and time selected by the
+                      -- user from the date and time selection dialog. For the
+                      -- detailed information of datetime picker, please refer
+                      -- to the <https://devdocs.line.me/en/#datetime-picker-action official documentation>.
                     deriving (Eq, Show)
 
 instance ToJSON TemplateAction where
-  toJSON (TplPostbackAction label data' maybeText) =
+  toJSON (TplPostbackAction label data'' maybeText) =
     object . concat $
       [ [ "type" .= ("postback" :: T.Text)
         , "label" .= label
-        , "data" .= data'
+        , "data" .= data''
         ]
       , maybeToList $ ("text" .=) <$> maybeText
       ]
@@ -433,9 +487,26 @@
                                                 , "text" .= text
                                                 ]
   toJSON (TplURIAction label uri) = object [ "type" .= ("uri" :: T.Text)
-                                           , "label" .= label
-                                           , "uri" .= uri
-                                           ]
+                                            , "label" .= label
+                                            , "uri" .= uri
+                                            ]
+  toJSON (TplDatetimePickerAction label data'' mode initial max'' min'') =
+    object . concat $ [ [ "type" .= ("datetimepicker" :: T.Text)
+                        , "data" .= data''
+                        , "mode" .= mode
+                        ]
+                      , maybeToList $ ("label" .=) <$> label
+                      , maybeToList $ ("initial" .=) <$> initial
+                      , maybeToList $ ("max" .=) <$> max''
+                      , maybeToList $ ("min" .=) <$> min''
+                      ]
+
+data DatetimeMode = Date | Time | Datetime deriving (Eq, Show)
+
+instance ToJSON DatetimeMode where
+  toJSON Date = "date"
+  toJSON Time = "time"
+  toJSON Datetime = "datetime"
 
 -- | A type to represent a user's profile.
 --
diff --git a/src/Line/Messaging/Common/Types.hs b/src/Line/Messaging/Common/Types.hs
--- a/src/Line/Messaging/Common/Types.hs
+++ b/src/Line/Messaging/Common/Types.hs
@@ -9,7 +9,6 @@
   -- * LINE API types
   ChannelSecret,
   ChannelAccessToken,
-  Postback,
   ) where
 
 import qualified Data.Text as T
@@ -27,6 +26,3 @@
 -- | A type alias to specify a channel access token. About issueing and using
 -- the channel access token, please refer to corresponding LINE documentations.
 type ChannelAccessToken = T.Text
-
--- | A type alias for postback data.
-type Postback = T.Text
diff --git a/src/Line/Messaging/Webhook/Types.hs b/src/Line/Messaging/Webhook/Types.hs
--- a/src/Line/Messaging/Webhook/Types.hs
+++ b/src/Line/Messaging/Webhook/Types.hs
@@ -35,9 +35,11 @@
   getBeacon,
   -- *** Event source
   EventSource (..),
-  getID,
   -- *** Message event
   EventMessage (..),
+  -- *** Postback event
+  Postback (..),
+  PostbackParams (..),
   -- *** Beacon event
   BeaconData (..),
   getHWID,
@@ -175,7 +177,7 @@
       "unfollow" -> UnfollowEvent <$> (nonReplyable v <*> none)
       "join" -> JoinEvent <$> (replyable v <*> none)
       "leave" -> LeaveEvent <$> (nonReplyable v <*> none)
-      "postback" -> PostbackEvent <$> (replyable v <*> ((v .: "postback") >>= (.: "data")))
+      "postback" -> PostbackEvent <$> (replyable v <*> v .: "postback")
       "beacon" -> BeaconEvent <$> (replyable v <*> v .: "beacon")
       _ -> fail "Event"
     where
@@ -190,23 +192,17 @@
 
 -- | A source from which an event is sent. It can be retrieved from events with
 -- 'getSource'.
-data EventSource = User ID
-                 | Group ID
-                 | Room ID
+data EventSource = User { userID :: ID }
+                 | Group { groupID :: ID, groupUserId :: Maybe ID }
+                 | Room { roomID :: ID, roomUserId :: Maybe ID }
                  deriving (Eq, Show)
 
--- | Retrieve identifier from event source
-getID :: EventSource -> ID
-getID (User i) = i
-getID (Group i) = i
-getID (Room i) = i
-
 instance FromJSON EventSource where
   parseJSON (Object v) = v .: "type" >>= \ t ->
     case t :: T.Text of
       "user" -> User <$> v .: "userId"
-      "group" -> Group <$> v .: "groupId"
-      "room" -> Room <$> v .: "roomId"
+      "group" -> Group <$> v .: "groupId" <*> v .:? "userId"
+      "room" -> Room <$> v .: "roomId" <*> v .:? "userId"
       _ -> fail "EventSource"
   parseJSON _ = fail "EventSource"
 
@@ -242,6 +238,39 @@
       _ -> fail "EventMessage"
   parseJSON _ = fail "IncommingMessage"
 
+-- | Represent Postback data.
+data Postback = Postback { data' :: T.Text
+                         , params :: Maybe PostbackParams
+                         }
+              deriving (Eq, Show)
+
+
+instance FromJSON Postback where
+  parseJSON (Object v) = Postback <$> v .: "data" <*> v .:? "params"
+  parseJSON _ = fail "Postback"
+
+-- | Represent params of Postback data.
+--
+-- It's currently used only for the datetime picker action. For the detail,
+-- please refer to the <https://devdocs.line.me/en/#postback-params-object official documentation>.
+data PostbackParams = PostbackParamsDate T.Text
+                    | PostbackParamsTime T.Text
+                    | PostbackParamsDatetime T.Text
+                    | PostbackParamsUnknown
+                    deriving (Eq, Show)
+
+instance FromJSON PostbackParams where
+  parseJSON (Object v) = go [ ("date", PostbackParamsDate)
+                            , ("time", PostbackParamsTime)
+                            , ("datetime", PostbackParamsDatetime)
+                            ]
+    where
+    go ((field, constructor):xs) = v .:? field >>= \m -> case m of
+      Just str -> return $ constructor str
+      Nothing -> go xs
+    go [] = return PostbackParamsUnknown
+  parseJSON _ = fail "PostbackParams"
+
 -- | Represent beacon data.
 data BeaconData = BeaconEnter ID (Maybe T.Text)
                 | BeaconLeave ID (Maybe T.Text)
@@ -249,13 +278,13 @@
                 deriving (Eq, Show)
 
 
--- |  Get hardware ID of the beacon.
+-- | Get hardware ID of the beacon.
 getHWID :: BeaconData -> ID
 getHWID (BeaconEnter hwid _) = hwid
 getHWID (BeaconLeave hwid _) = hwid
 getHWID (BeaconBanner hwid _) = hwid
 
--- |  Get device message from the beacon, if exists.
+-- | Get device message from the beacon, if exists.
 getDeviceMessage :: BeaconData -> Maybe T.Text
 getDeviceMessage (BeaconEnter _ dm) = dm
 getDeviceMessage (BeaconLeave _ dm) = dm
diff --git a/test/Line/Messaging/API/TypesSpec.hs b/test/Line/Messaging/API/TypesSpec.hs
--- a/test/Line/Messaging/API/TypesSpec.hs
+++ b/test/Line/Messaging/API/TypesSpec.hs
@@ -68,6 +68,7 @@
        [ TplPostbackAction "Buy" "action=buy&itemid=123" Nothing
        , TplPostbackAction "Add to cart" "action=add&itemid=123" Nothing
        , TplURIAction "View detail" "http://example.com/page/123"
+       , TplDatetimePickerAction (Just "yes label") "pickpick" Datetime Nothing Nothing Nothing
        ])
       buttonsTemplateMessageableResult
 
@@ -76,6 +77,7 @@
        Confirm "Are you sure?"
        [ TplMessageAction "Yes" "yes"
        , TplMessageAction "No" "no"
+       , TplDatetimePickerAction Nothing "pickpick2" Date (Just "1990-01-01") (Just "2100-12-31") (Just "1900-01-01")
        ])
       confirmTemplateMessageableResult
 
@@ -87,6 +89,7 @@
                          [ TplPostbackAction "Buy" "action=buy&itemid=111" Nothing
                          , TplPostbackAction "Add to cart" "action=add&itemid=111" Nothing
                          , TplURIAction "View detail" "http://example.com/page/111"
+                         , TplDatetimePickerAction Nothing "pickpick3" Time Nothing (Just "23:23") (Just "11:11")
                          ]
                 , Column (Just "https://example.com/bot/images/item2.jpg")
                          (Just "this is menu")
@@ -97,6 +100,16 @@
                          ]
                 ])
       carouselTemplateMessageableResult
+
+    messageableSpec "template image carousel"
+      (Template "this is an image carousel template" $
+       ImageCarousel [ ImageColumn "https://example.com/bot/images/item1.jpg"
+                         (TplPostbackAction "Buy" "action=buy&itemid=111" Nothing)
+                     , ImageColumn "https://example.com/bot/images/item2.jpg"
+                         (TplPostbackAction "Buy" "action=buy&itemid=222" Nothing)
+                     ]
+      )
+      imageCarouselTemplateMessageableResult
 
   describe "JSON decode" $ do
     describe "profile" $ fromJSONSpec
diff --git a/test/Line/Messaging/API/TypesSpecHelper.hs b/test/Line/Messaging/API/TypesSpecHelper.hs
--- a/test/Line/Messaging/API/TypesSpecHelper.hs
+++ b/test/Line/Messaging/API/TypesSpecHelper.hs
@@ -120,6 +120,12 @@
             "type": "uri",
             "label": "View detail",
             "uri": "http://example.com/page/123"
+          },
+          {
+            "type": "datetimepicker",
+            "label": "yes label",
+            "data": "pickpick",
+            "mode": "datetime"
           }
       ]
   }
@@ -144,6 +150,14 @@
             "type": "message",
             "label": "No",
             "text": "no"
+          },
+          {
+            "type": "datetimepicker",
+            "data": "pickpick2",
+            "mode": "date",
+            "initial": "1990-01-01",
+            "max": "2100-12-31",
+            "min": "1900-01-01"
           }
       ]
   }
@@ -177,6 +191,13 @@
                     "type": "uri",
                     "label": "View detail",
                     "uri": "http://example.com/page/111"
+                },
+                {
+                  "type": "datetimepicker",
+                  "data": "pickpick3",
+                  "mode": "time",
+                  "max": "23:23",
+                  "min": "11:11"
                 }
             ]
           },
@@ -201,6 +222,35 @@
                     "uri": "http://example.com/page/222"
                 }
             ]
+          }
+      ]
+  }
+}
+|]
+
+imageCarouselTemplateMessageableResult :: BL.ByteString
+imageCarouselTemplateMessageableResult = [r|
+{
+  "type": "template",
+  "altText": "this is an image carousel template",
+  "template": {
+      "type": "image_carousel",
+      "columns": [
+          {
+              "imageUrl": "https://example.com/bot/images/item1.jpg",
+              "action": {
+                  "type": "postback",
+                  "label": "Buy",
+                  "data": "action=buy&itemid=111"
+              }
+          },
+          {
+              "imageUrl": "https://example.com/bot/images/item2.jpg",
+              "action": {
+                  "type": "postback",
+                  "label": "Buy",
+                  "data": "action=buy&itemid=222"
+              }
           }
       ]
   }
diff --git a/test/Line/Messaging/Webhook/TypesSpec.hs b/test/Line/Messaging/Webhook/TypesSpec.hs
--- a/test/Line/Messaging/Webhook/TypesSpec.hs
+++ b/test/Line/Messaging/Webhook/TypesSpec.hs
@@ -33,8 +33,10 @@
 
   describe "event source" $ fromJSONSpec
     [ ( goodUser, Just $ User "123" )
-    , ( goodGroup, Just $ Group "456" )
-    , ( goodRoom, Just $ Room "789" )
+    , ( goodGroup, Just $ Group "456" Nothing)
+    , ( goodRoom, Just $ Room "789" Nothing)
+    , ( goodGroupWithUserId, Just $ Group "456" $ Just "789")
+    , ( goodRoomWithUserId, Just $ Room "789" $ Just "456")
     , ( badSource, Nothing )
     ]
 
@@ -108,7 +110,7 @@
 
   describe "join event" $ fromJSONSpec
     [ ( goodJoin, Just $ Body $ [
-        JoinEvent ( Group "cxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+        JoinEvent ( Group "cxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" Nothing
                   , datetime 1462629479859
                   , "nHuyWiB7yP5Zw52FIkcQobQuGDXCTA"
                   , ()
@@ -119,7 +121,7 @@
 
   describe "leave event" $ fromJSONSpec
     [ ( goodLeave, Just $ Body $ [
-          LeaveEvent ( Group "cxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+          LeaveEvent ( Group "cxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" Nothing
                      , datetime 1462629479859
                      , ()
                      , ()
@@ -129,7 +131,10 @@
     ]
 
   describe "postback event" $ fromJSONSpec
-    [ ( goodPostback, replyE PostbackEvent "action=buyItem&itemId=123123&color=red" )
+    [ ( goodPostback, replyE PostbackEvent (Postback "action=buyItem&itemId=123123&color=red" Nothing) )
+    , ( goodPostbackWithDate, replyE PostbackEvent (Postback "action=buyItem&itemId=123123&color=red" (Just $ PostbackParamsDate "1990-01-01")) )
+    , ( goodPostbackWithTime, replyE PostbackEvent (Postback "action=buyItem&itemId=123123&color=red" (Just $ PostbackParamsTime "12:34")) )
+    , ( goodPostbackWithDatetime, replyE PostbackEvent (Postback "action=buyItem&itemId=123123&color=red" (Just $ PostbackParamsDatetime "1990-01-01 12:34")) )
     , ( badPostback, Nothing )
     ]
 
diff --git a/test/Line/Messaging/Webhook/TypesSpecHelper.hs b/test/Line/Messaging/Webhook/TypesSpecHelper.hs
--- a/test/Line/Messaging/Webhook/TypesSpecHelper.hs
+++ b/test/Line/Messaging/Webhook/TypesSpecHelper.hs
@@ -30,6 +30,16 @@
 { "type": "room", "roomId": "789" }
 |]
 
+goodGroupWithUserId :: BL.ByteString
+goodGroupWithUserId = [r|
+{ "type": "group", "groupId": "456", "userId": "789" }
+|]
+
+goodRoomWithUserId :: BL.ByteString
+goodRoomWithUserId = [r|
+{ "type": "room", "roomId": "789", "userId": "456" }
+|]
+
 badSource :: BL.ByteString
 badSource = [r|
 { "type": "bad", "userId": "123 }
@@ -449,6 +459,69 @@
   },
   "postback": {
     "data": "action=buyItem&itemId=123123&color=red"
+  }
+}
+] }
+|]
+
+goodPostbackWithDate :: BL.ByteString
+goodPostbackWithDate = [r|
+{ "events": [
+{
+  "replyToken": "nHuyWiB7yP5Zw52FIkcQobQuGDXCTA",
+  "type": "postback",
+  "timestamp": 1462629479859,
+  "source": {
+    "type": "user",
+    "userId": "U206d25c2ea6bd87c17655609a1c37cb8"
+  },
+  "postback": {
+    "data": "action=buyItem&itemId=123123&color=red",
+    "params": {
+      "date": "1990-01-01"
+    }
+  }
+}
+] }
+|]
+
+goodPostbackWithTime :: BL.ByteString
+goodPostbackWithTime = [r|
+{ "events": [
+{
+  "replyToken": "nHuyWiB7yP5Zw52FIkcQobQuGDXCTA",
+  "type": "postback",
+  "timestamp": 1462629479859,
+  "source": {
+    "type": "user",
+    "userId": "U206d25c2ea6bd87c17655609a1c37cb8"
+  },
+  "postback": {
+    "data": "action=buyItem&itemId=123123&color=red",
+    "params": {
+      "time": "12:34"
+    }
+  }
+}
+] }
+|]
+
+goodPostbackWithDatetime :: BL.ByteString
+goodPostbackWithDatetime = [r|
+{ "events": [
+{
+  "replyToken": "nHuyWiB7yP5Zw52FIkcQobQuGDXCTA",
+  "type": "postback",
+  "timestamp": 1462629479859,
+  "source": {
+    "type": "user",
+    "userId": "U206d25c2ea6bd87c17655609a1c37cb8"
+  },
+  "postback": {
+    "data": "action=buyItem&itemId=123123&color=red",
+    "params": {
+      "datetime": "1990-01-01 12:34"
+    }
   }
 }
 ] }
