diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,26 @@
+Copyright (c)2011-2014, Takahiro Himura
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,3 @@
+#!/usr/bin/env runhaskell
+import Distribution.Simple
+main = defaultMain
diff --git a/Web/Twitter/Conduit.hs b/Web/Twitter/Conduit.hs
new file mode 100644
--- /dev/null
+++ b/Web/Twitter/Conduit.hs
@@ -0,0 +1,12 @@
+module Web.Twitter.Conduit
+       ( module Export
+       ) where
+
+import Web.Twitter.Conduit.Base as Export
+import Web.Twitter.Conduit.Api as Export
+import Web.Twitter.Conduit.Status as Export
+import Web.Twitter.Conduit.Monad as Export
+import Web.Twitter.Conduit.Stream as Export
+import Web.Twitter.Conduit.Request as Export
+import Web.Twitter.Conduit.Parameters as Export
+import Web.Twitter.Types.Lens as Export
diff --git a/Web/Twitter/Conduit/Api.hs b/Web/Twitter/Conduit/Api.hs
new file mode 100644
--- /dev/null
+++ b/Web/Twitter/Conduit/Api.hs
@@ -0,0 +1,442 @@
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE EmptyDataDecls #-}
+{-# LANGUAGE TemplateHaskell #-}
+{-# LANGUAGE QuasiQuotes #-}
+{-# LANGUAGE CPP #-}
+#if __GLASGOW_HASKELL__ >= 704
+{-# LANGUAGE ConstraintKinds #-}
+#endif
+
+module Web.Twitter.Conduit.Api
+       (
+       -- * Search
+         Search
+       , search
+
+       -- * Direct Messages
+       , DirectMessages
+       , directMessages
+       , DirectMessagesSent
+       , directMessagesSent
+       , DirectMessagesShow
+       , directMessagesShow
+       , DirectMessagesDestroy
+       , directMessagesDestroy
+       , DirectMessagesNew
+       , directMessagesNew
+
+       -- * Friends & Followers
+       -- , friendshipsNoRetweetsIds
+       , FriendsIds
+       , friendsIds
+       , FollowersIds
+       , followersIds
+       -- , friendshipsLookup
+       -- , friendshipsIncoming
+       -- , friendshipsOutgoing
+       , FriendshipsCreate
+       , friendshipsCreate
+       -- , friendshipsDestroy
+       -- , friendshipsUpdate
+       -- , friendshipsShow
+       , FriendsList
+       , friendsList
+       -- , followersList
+
+       -- * Users
+       -- , accountSettings
+       , AccountVerifyCredentials
+       , accountVerifyCredentials
+       -- , accountSettingsUpdate
+       -- , accountUpdateDeliveryDevice
+       -- , accountUpdateProfile
+       -- , accountUpdateProfileBackgroundImage
+       -- , accountUpdateProfileColors
+       -- , accoutUpdateProfileImage
+       -- , blocksList
+       -- , blocksIds
+       -- , blocksCreate
+       -- , blocksDestroy
+
+       , UsersLookup
+       , usersLookup
+       , UsersShow
+       , usersShow
+       -- , usersSearch
+       -- , usersContributees
+       -- , usersContributors
+       -- , accuntRemoveProfileBanner
+       -- , accuntUpdateProfileBanner
+       -- , accuntProfileBanner
+
+       -- * Suggested Users
+       -- , usersSuggestionsSlug
+       -- , usersSuggestions
+       -- , usersSuggestionsSlugMembers
+
+       -- * Favorites
+       -- , favoritesList
+       , FavoritesDestroy
+       , favoritesDestroy
+       , FavoritesCreate
+       , favoritesCreate
+
+       -- * Lists
+       -- , listsStatuses
+       -- , listsMemberships
+       -- , listsSubscribers
+       -- , listsSubscribersShow
+       -- , listsMembersShow
+       , ListsMembers
+       , listsMembers
+       -- , lists
+       -- , listsShow
+       -- , listsSubscriptions
+       ) where
+
+import Web.Twitter.Types
+import Web.Twitter.Conduit.Parameters
+import Web.Twitter.Conduit.Parameters.TH
+import Web.Twitter.Conduit.Base
+import Web.Twitter.Conduit.Request
+import Web.Twitter.Conduit.Cursor
+
+import qualified Data.Text as T
+import qualified Data.Text.Encoding as T
+import Data.Default
+
+-- $setup
+-- >>> :set -XOverloadedStrings
+-- >>> import Control.Lens
+
+data Search
+-- | Returns search query.
+--
+-- You can perform a search query using 'call':
+--
+-- @
+-- res <- 'call' ('search' \"search text\")
+-- 'liftIO' . 'print' $ res ^. 'searchResultStatuses'
+-- @
+--
+-- >>> search "search text"
+-- APIRequestGet "https://api.twitter.com/1.1/search/tweets.json" [("q","search text")]
+-- >>> search "search text" & lang ?~ "ja" & count ?~ 100
+-- APIRequestGet "https://api.twitter.com/1.1/search/tweets.json" [("count","100"),("lang","ja"),("q","search text")]
+search :: T.Text -- ^ search string
+       -> APIRequest Search (SearchResult [SearchStatus])
+search q = APIRequestGet (endpoint ++ "search/tweets.json") [("q", T.encodeUtf8 q)]
+deriveHasParamInstances ''Search
+    [ "lang"
+    , "locale"
+    -- , "result_type"
+    , "count"
+    , "until"
+    , "since_id"
+    , "max_id"
+    , "include_entities"
+    -- , "callback"  (needless)
+    ]
+
+data DirectMessages
+-- | Returns query data which asks recent direct messages sent to the authenticating user.
+--
+-- You can perform a query using 'call':
+--
+-- @
+-- res <- 'call' '$' 'directMessages' '&' 'count' '?~' 100
+-- @
+--
+-- >>> directMessages
+-- APIRequestGet "https://api.twitter.com/1.1/direct_messages.json" []
+-- >>> directMessages & count ?~ 100
+-- APIRequestGet "https://api.twitter.com/1.1/direct_messages.json" [("count","100")]
+directMessages :: APIRequest DirectMessages [DirectMessage]
+directMessages = APIRequestGet (endpoint ++ "direct_messages.json") def
+deriveHasParamInstances ''DirectMessages
+    [ "since_id"
+    , "max_id"
+    , "count"
+    , "include_entities"
+    , "skip_status"
+    ]
+
+data DirectMessagesSent
+-- | Returns query data which asks recent direct messages sent by the authenticating user.
+--
+-- You can perform a query using 'call':
+--
+-- @
+-- res <- 'call' '$' 'directMessagesSent' '&' 'count' '?~' 100
+-- @
+--
+-- >>> directMessagesSent
+-- APIRequestGet "https://api.twitter.com/1.1/direct_messages/sent.json" []
+-- >>> directMessagesSent & count ?~ 100
+-- APIRequestGet "https://api.twitter.com/1.1/direct_messages/sent.json" [("count","100")]
+directMessagesSent :: APIRequest DirectMessagesSent [DirectMessage]
+directMessagesSent = APIRequestGet (endpoint ++ "direct_messages/sent.json") def
+deriveHasParamInstances ''DirectMessagesSent
+    [ "since_id"
+    , "max_id"
+    , "count"
+    , "include_entities"
+    , "page"
+    , "skip_status"
+    ]
+
+data DirectMessagesShow
+-- | Returns query data which asks a single direct message, specified by an id parameter.
+--
+-- You can perform a query using 'call':
+--
+-- @
+-- res <- 'call' '$' 'directMessagesShow' 1234567890
+-- @
+--
+-- >>> directMessagesShow 1234567890
+-- APIRequestGet "https://api.twitter.com/1.1/direct_messages/show.json" [("id","1234567890")]
+directMessagesShow :: StatusId -> APIRequest DirectMessagesShow DirectMessage
+directMessagesShow sId = APIRequestGet (endpoint ++ "direct_messages/show.json") [("id", showBS sId)]
+
+data DirectMessagesDestroy
+-- | Returns post data which destroys the direct message specified in the required ID parameter.
+--
+-- You can perform a query using 'call':
+--
+-- @
+-- res <- 'call' '$' 'directMessagesDestroy' 1234567890
+-- @
+--
+-- >>> directMessagesDestroy 1234567890
+-- APIRequestPost "https://api.twitter.com/1.1/direct_messages/destroy.json" [("id","1234567890")]
+directMessagesDestroy :: StatusId -> APIRequest DirectMessagesDestroy DirectMessage
+directMessagesDestroy sId = APIRequestPost (endpoint ++ "direct_messages/destroy.json") [("id", showBS sId)]
+deriveHasParamInstances ''DirectMessagesDestroy
+    [ "include_entities"
+    ]
+
+data DirectMessagesNew
+-- | Returns post data which sends a new direct message to the specified user from the authenticating user.
+--
+-- You can perform a post using 'call':
+--
+-- @
+-- res <- 'call' '$' 'directMessagesNew' (ScreenNameParam \"thimura\") \"Hello DM\"
+-- @
+--
+-- >>> directMessagesNew (ScreenNameParam "thimura") "Hello DM"
+-- APIRequestPost "https://api.twitter.com/1.1/direct_messages/new.json" [("text","Hello DM"),("screen_name","thimura")]
+-- >>> directMessagesNew (UserIdParam 69179963) "Hello thimura! by UserId"
+-- APIRequestPost "https://api.twitter.com/1.1/direct_messages/new.json" [("text","Hello thimura! by UserId"),("user_id","69179963")]
+directMessagesNew :: UserParam -> T.Text -> APIRequest DirectMessagesNew DirectMessage
+directMessagesNew q msg = APIRequestPost (endpoint ++ "direct_messages/new.json") (("text", T.encodeUtf8 msg):mkUserParam q)
+
+data FriendsIds
+-- | Returns query data which asks a collection of user IDs for every user the specified user is following.
+--
+-- You can perform a query using 'call':
+--
+-- @
+-- res <- 'call' '$' 'friendsIds' ('ScreenNameParam' \"thimura\")
+-- @
+--
+-- Or, you can iterate with 'sourceWithCursor':
+--
+-- @
+-- 'sourceWithCursor' ('friendsIds' ('ScreenNameParam' \"thimura\")) $$ CL.consume
+-- @
+--
+-- >>> friendsIds (ScreenNameParam "thimura")
+-- APIRequestGet "https://api.twitter.com/1.1/friends/ids.json" [("screen_name","thimura")]
+-- >>> friendsIds (ScreenNameParam "thimura") & count ?~ 5000
+-- APIRequestGet "https://api.twitter.com/1.1/friends/ids.json" [("count","5000"),("screen_name","thimura")]
+friendsIds :: UserParam -> APIRequest FriendsIds (WithCursor IdsCursorKey UserId)
+friendsIds q = APIRequestGet (endpoint ++ "friends/ids.json") (mkUserParam q)
+deriveHasParamInstances ''FriendsIds
+    [ "cursor"
+    -- , "stringify_ids" -- (needless)
+    , "count"
+    ]
+
+data FollowersIds
+-- | Returns query data which asks a collection of user IDs for every user following the specified user.
+--
+-- You can perform a query using 'call':
+--
+-- @
+-- res <- 'call' '$' 'followersIds' ('ScreenNameParam' \"thimura\")
+-- @
+--
+-- Or, you can iterate with 'sourceWithCursor':
+--
+-- @
+-- 'sourceWithCursor' ('followersIds' ('ScreenNameParam' \"thimura\")) $$ CL.consume
+-- @
+--
+-- >>> followersIds (ScreenNameParam "thimura")
+-- APIRequestGet "https://api.twitter.com/1.1/followers/ids.json" [("screen_name","thimura")]
+-- >>> followersIds (ScreenNameParam "thimura") & count ?~ 5000
+-- APIRequestGet "https://api.twitter.com/1.1/followers/ids.json" [("count","5000"),("screen_name","thimura")]
+followersIds :: UserParam -> APIRequest FollowersIds (WithCursor IdsCursorKey UserId)
+followersIds q = APIRequestGet (endpoint ++ "followers/ids.json") (mkUserParam q)
+deriveHasParamInstances ''FollowersIds
+    [ "cursor"
+    -- , "stringify_ids" -- (needless)
+    , "count"
+    ]
+
+data FriendshipsCreate
+-- | Returns post data which follows the user specified in the ID parameter.
+--
+-- You can perform request by using 'call':
+--
+-- @
+-- res <- 'call' '$' 'friendshipsCreate' ('ScreenNameParam' \"thimura\")
+-- @
+--
+-- >>> friendshipsCreate (ScreenNameParam "thimura")
+-- APIRequestPost "https://api.twitter.com/1.1/friendships/create.json" [("screen_name","thimura")]
+-- >>> friendshipsCreate (UserIdParam 69179963)
+-- APIRequestPost "https://api.twitter.com/1.1/friendships/create.json" [("user_id","69179963")]
+friendshipsCreate :: UserParam -> APIRequest FriendshipsCreate User
+friendshipsCreate user = APIRequestPost (endpoint ++ "friendships/create.json") (mkUserParam user)
+deriveHasParamInstances ''FriendshipsCreate
+    [ "follow"
+    ]
+
+data FriendsList
+-- | Returns query data which asks a cursored collection of user objects for every user the specified users is following.
+--
+-- You can perform request by using 'call':
+--
+-- @
+-- res <- 'call' '$' 'friendsList' ('ScreenNameParam' \"thimura\")
+-- @
+--
+-- Or, you can iterate with 'sourceWithCursor':
+--
+-- @
+-- 'sourceWithCursor' ('friendsList' ('ScreenNameParam' \"thimura\")) $$ CL.consume
+-- @
+--
+-- >>> friendsList (ScreenNameParam "thimura")
+-- APIRequestGet "https://api.twitter.com/1.1/friends/list.json" [("screen_name","thimura")]
+-- >>> friendsList (UserIdParam 69179963)
+-- APIRequestGet "https://api.twitter.com/1.1/friends/list.json" [("user_id","69179963")]
+friendsList :: UserParam -> APIRequest FriendsList (WithCursor UsersCursorKey User)
+friendsList q = APIRequestGet (endpoint ++ "friends/list.json") (mkUserParam q)
+deriveHasParamInstances ''FriendsList
+    [ "cursor"
+    , "count"
+    , "skip_status"
+    , "include_user_entities"
+    ]
+
+data AccountVerifyCredentials
+-- | Returns query data asks that the credential is valid.
+--
+-- You can perform request by using 'call':
+--
+-- @
+-- res <- 'call' '$' 'accountVerifyCredentials'
+-- @
+--
+-- >>> accountVerifyCredentials
+-- APIRequestGet "https://api.twitter.com/1.1/account/verify_credentials.json" []
+accountVerifyCredentials :: APIRequest AccountVerifyCredentials User
+accountVerifyCredentials = APIRequestGet (endpoint ++ "account/verify_credentials.json") []
+deriveHasParamInstances ''AccountVerifyCredentials
+    [ "include_entities"
+    , "skip_status"
+    ]
+
+data UsersLookup
+-- | Returns query data asks user objects.
+--
+-- You can perform request by using 'call':
+--
+-- @
+-- res <- 'call' '$' 'usersLookup' ('ScreenNameListParam' [\"thimura\", \"twitterapi\"])
+-- @
+--
+-- >>> usersLookup (ScreenNameListParam ["thimura", "twitterapi"])
+-- APIRequestGet "https://api.twitter.com/1.1/users/lookup.json" [("screen_name","thimura,twitterapi")]
+usersLookup :: UserListParam -> APIRequest UsersLookup [User]
+usersLookup q = APIRequestGet (endpoint ++ "users/lookup.json") (mkUserListParam q)
+deriveHasParamInstances ''UsersLookup
+    [ "include_entities"
+    ]
+
+data UsersShow
+-- | Returns query data asks the user specified by user id or screen name parameter.
+--
+-- You can perform request by using 'call':
+--
+-- @
+-- res <- 'call' '$' 'usersShow' ('ScreenNameParam' \"thimura\")
+-- @
+--
+-- >>> usersShow (ScreenNameParam "thimura")
+-- APIRequestGet "https://api.twitter.com/1.1/users/show.json" [("screen_name","thimura")]
+usersShow :: UserParam -> APIRequest UsersShow User
+usersShow q = APIRequestGet (endpoint ++ "users/show.json") (mkUserParam q)
+deriveHasParamInstances ''UsersShow
+    [ "include_entities"
+    ]
+
+data FavoritesCreate
+-- | Returns post data which favorites the status specified in the ID parameter as the authenticating user.
+--
+-- You can perform request by using 'call':
+--
+-- @
+-- res <- 'call' '$' 'favoritesCreate' 1234567890
+-- @
+--
+-- >>> favoritesCreate 1234567890
+-- APIRequestPost "https://api.twitter.com/1.1/favorites/create.json" [("id","1234567890")]
+favoritesCreate :: StatusId -> APIRequest FavoritesCreate Status
+favoritesCreate sid = APIRequestPost (endpoint ++ "favorites/create.json") [("id", showBS sid)]
+deriveHasParamInstances ''FavoritesCreate
+    [ "include_entities"
+    ]
+
+data FavoritesDestroy
+-- | Returns post data unfavorites the status specified in the ID paramter as the authenticating user.
+--
+-- You can perform request by using 'call':
+--
+-- @
+-- res <- 'call' '$' 'favoritesDestroy' 1234567890
+-- @
+--
+-- >>> favoritesDestroy 1234567890
+-- APIRequestPost "https://api.twitter.com/1.1/favorites/destroy.json" [("id","1234567890")]
+favoritesDestroy :: StatusId -> APIRequest FavoritesDestroy Status
+favoritesDestroy sid = APIRequestPost (endpoint ++ "favorites/destroy.json") [("id", showBS sid)]
+deriveHasParamInstances ''FavoritesDestroy
+    [ "include_entities"
+    ]
+
+data ListsMembers
+-- | Returns query data asks the members of the specified list.
+--
+-- You can perform request by using 'call':
+--
+-- @
+-- res <- 'call' '$' 'listsMembers' ('ListNameParam' "thimura/haskell")
+-- @
+--
+-- >>> listsMembers (ListNameParam "thimura/haskell")
+-- APIRequestGet "https://api.twitter.com/1.1/lists/members.json" [("slug","haskell"),("owner_screen_name","thimura")]
+-- >>> listsMembers (ListIdParam 20849097)
+-- APIRequestGet "https://api.twitter.com/1.1/lists/members.json" [("list_id","20849097")]
+listsMembers :: ListParam -> APIRequest ListsMembers (WithCursor UsersCursorKey User)
+listsMembers q = APIRequestGet (endpoint ++ "lists/members.json") (mkListParam q)
+deriveHasParamInstances ''ListsMembers
+    [ "cursor"
+    , "skip_status"
+    ]
+
diff --git a/Web/Twitter/Conduit/Base.hs b/Web/Twitter/Conduit/Base.hs
new file mode 100644
--- /dev/null
+++ b/Web/Twitter/Conduit/Base.hs
@@ -0,0 +1,211 @@
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE TemplateHaskell #-}
+{-# LANGUAGE QuasiQuotes #-}
+#if __GLASGOW_HASKELL__ >= 704
+{-# LANGUAGE ConstraintKinds #-}
+#else
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE UndecidableInstances #-}
+#endif
+
+module Web.Twitter.Conduit.Base
+       ( api
+       , apiRequest
+       , call
+       , sourceWithMaxId
+       , sourceWithCursor
+       , TwitterBaseM
+       , endpoint
+       , makeRequest
+       , sinkJSON
+       , sinkFromJSON
+       , showBS
+       ) where
+
+import Web.Twitter.Conduit.Monad
+import Web.Twitter.Conduit.Error
+import Web.Twitter.Conduit.Parameters
+import Web.Twitter.Conduit.Request
+import Web.Twitter.Conduit.Cursor
+import Web.Twitter.Types.Lens
+
+import Network.HTTP.Conduit
+import Network.HTTP.Client.MultipartFormData
+import qualified Network.HTTP.Types as HT
+import qualified Data.Conduit as C
+import qualified Data.Conduit.List as CL
+
+import Data.Aeson
+import Data.Aeson.Lens
+import qualified Data.Conduit.Attoparsec as CA
+import qualified Data.Text.Encoding as T
+import Data.ByteString (ByteString)
+import qualified Data.ByteString.Char8 as S8
+import Control.Monad.IO.Class
+import Control.Monad.Trans.Class (lift)
+import Text.Shakespeare.Text
+import Control.Monad.Logger
+import Control.Lens
+import Unsafe.Coerce
+
+#if __GLASGOW_HASKELL__ >= 704
+type TwitterBaseM m = ( C.MonadResource m
+                      , MonadLogger m
+                      )
+#else
+class (C.MonadResource m, MonadLogger m) => TwitterBaseM m
+instance (C.MonadResource m, MonadLoger m) => TwitterBaseM m
+#endif
+
+makeRequest :: MonadIO m
+            => HT.Method -- ^ HTTP request method (GET or POST)
+            -> String -- ^ API Resource URL
+            -> HT.SimpleQuery -- ^ Query
+            -> TW m Request
+makeRequest m url query = do
+    p <- getProxy
+    req <- liftIO $ parseUrl url
+    return $ req { method = m
+                 , queryString = HT.renderSimpleQuery False query
+                 , proxy = p }
+
+api :: TwitterBaseM m
+    => HT.Method -- ^ HTTP request method (GET or POST)
+    -> String -- ^ API Resource URL
+    -> HT.SimpleQuery -- ^ Query
+    -> TW m (C.ResumableSource (TW m) ByteString)
+api m url query =
+    apiRequest =<< makeRequest m url query
+
+apiRequest :: TwitterBaseM m
+           => Request
+           -> TW m (C.ResumableSource (TW m) ByteString)
+apiRequest req = do
+    signedReq <- signOAuthTW req
+    $(logDebug) [st|Signed Request: #{show signedReq}|]
+    mgr <- getManager
+    res <- http signedReq mgr
+    $(logDebug) [st|Response Status: #{show $ responseStatus res}|]
+    $(logDebug) [st|Response Header: #{show $ responseHeaders res}|]
+    return $ responseBody res
+
+endpoint :: String
+endpoint = "https://api.twitter.com/1.1/"
+
+apiValue :: (TwitterBaseM m, FromJSON a)
+         => HT.Method -- ^ HTTP request method (GET or POST)
+         -> String -- ^ API Resource URL
+         -> HT.SimpleQuery -- ^ Query
+         -> TW m a
+apiValue m url query = do
+    src <- api m url query
+    src C.$$+- sinkFromJSON
+
+call :: (TwitterBaseM m, FromJSON responseType)
+     => APIRequest apiName responseType
+     -> TW m responseType
+call = call'
+
+call' :: (TwitterBaseM m, FromJSON value)
+      => APIRequest apiName responseType
+      -> TW m value
+call' (APIRequestGet u pa) = apiValue "GET" u pa
+call' (APIRequestPost u pa) = apiValue "POST" u pa
+call' (APIRequestPostMultipart u param prt) = do
+    req <- formDataBody body =<< makeRequest "POST" u []
+    src <- apiRequest req
+    src C.$$+- sinkFromJSON
+  where
+    body = prt ++ partParam
+    partParam = map (uncurry partBS . over _1 T.decodeUtf8) param
+
+sourceWithMaxId :: ( TwitterBaseM m
+                   , FromJSON responseType
+                   , AsStatus responseType
+                   , HasMaxIdParam (APIRequest apiName [responseType])
+                   )
+                => APIRequest apiName [responseType]
+                -> C.Source (TW m) responseType
+sourceWithMaxId = loop
+  where
+    loop req = do
+        res <- lift $ call req
+        case getMinId res of
+            Just mid -> do
+                CL.sourceList res
+                loop $ req & maxId ?~ mid - 1
+            Nothing -> CL.sourceList res
+    getMinId = minimumOf (traverse . status_id)
+
+sourceWithMaxId' :: ( TwitterBaseM m
+                    , HasMaxIdParam (APIRequest apiName [responseType])
+                    )
+                 => APIRequest apiName [responseType]
+                 -> C.Source (TW m) Value
+sourceWithMaxId' = loop
+  where
+    loop req = do
+        res <- lift $ call' req
+        case getMinId res of
+            Just mid -> do
+                CL.sourceList res
+                loop $ req & maxId ?~ mid - 1
+            Nothing -> CL.sourceList res
+    getMinId = minimumOf (traverse . key "id" . _Integer)
+
+sourceWithCursor :: ( TwitterBaseM m
+                    , FromJSON responseType
+                    , CursorKey ck
+                    , HasCursorParam (APIRequest apiName (WithCursor ck responseType))
+                    )
+                 => APIRequest apiName (WithCursor ck responseType)
+                 -> C.Source (TW m) responseType
+sourceWithCursor req = loop (-1)
+  where
+    loop 0 = CL.sourceNull
+    loop cur = do
+        res <- lift $ call $ req & cursor ?~ cur
+        CL.sourceList $ contents res
+        loop $ nextCursor res
+
+sourceWithCursor' :: ( TwitterBaseM m
+                     , FromJSON responseType
+                     , CursorKey ck
+                     , HasCursorParam (APIRequest apiName (WithCursor ck responseType))
+                     )
+                  => APIRequest apiName (WithCursor ck responseType)
+                  -> C.Source (TW m) Value
+sourceWithCursor' req = loop (-1)
+  where
+    relax :: FromJSON value
+          => APIRequest apiName (WithCursor ck responseType)
+          -> APIRequest apiName (WithCursor ck value)
+    relax = unsafeCoerce
+    loop 0 = CL.sourceNull
+    loop cur = do
+        res <- lift $ call $ relax $ req & cursor ?~ cur
+        CL.sourceList $ contents res
+        loop $ nextCursor res
+
+sinkJSON :: ( C.MonadThrow m
+            , MonadLogger m
+            ) => C.Consumer ByteString m Value
+sinkJSON = do
+    js <- CA.sinkParser json
+    $(logDebug) [st|Response JSON: #{show js}|]
+    return js
+
+sinkFromJSON :: ( FromJSON a
+                , C.MonadThrow m
+                , MonadLogger m
+                ) => C.Consumer ByteString m a
+sinkFromJSON = do
+    v <- sinkJSON
+    case fromJSON v of
+        Error err -> lift $ C.monadThrow $ TwitterError err
+        Success r -> return r
+
+showBS :: Show a => a -> ByteString
+showBS = S8.pack . show
diff --git a/Web/Twitter/Conduit/Cursor.hs b/Web/Twitter/Conduit/Cursor.hs
new file mode 100644
--- /dev/null
+++ b/Web/Twitter/Conduit/Cursor.hs
@@ -0,0 +1,61 @@
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE EmptyDataDecls #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+
+module Web.Twitter.Conduit.Cursor
+       ( CursorKey (..)
+       , IdsCursorKey
+       , UsersCursorKey
+       , WithCursor (..)
+       ) where
+
+import Web.Twitter.Types (checkError)
+import qualified Data.Text as T
+import Data.Aeson
+import Data.Monoid
+import Control.Applicative
+
+-- $setup
+-- >>> type UserId = Integer
+
+class CursorKey a where
+    cursorKey :: a -> T.Text
+
+-- | Phantom type to specify the key which point out the content in the response.
+data IdsCursorKey
+instance CursorKey IdsCursorKey where
+    cursorKey = const "ids"
+
+-- | Phantom type to specify the key which point out the content in the response.
+data UsersCursorKey
+instance CursorKey UsersCursorKey where
+    cursorKey = const "users"
+
+-- | A wrapper for API responses which have "next_cursor" field.
+--
+-- The first type parameter of 'WithCursor' specifies the field name of contents.
+--
+-- >>> let Just res = decode "{\"previous_cursor\": 0, \"next_cursor\": 1234567890, \"ids\": [1111111111]}" :: Maybe (WithCursor IdsCursorKey UserId)
+-- >>> nextCursor res
+-- 1234567890
+-- >>> contents res
+-- [1111111111]
+--
+-- >>> let Just res = decode "{\"previous_cursor\": 0, \"next_cursor\": 0, \"users\": [1000]}" :: Maybe (WithCursor UsersCursorKey UserId)
+-- >>> nextCursor res
+-- 0
+-- >>> contents res
+-- [1000]
+data WithCursor cursorKey wrapped = WithCursor
+    { previousCursor :: Integer
+    , nextCursor :: Integer
+    , contents :: [wrapped]
+    }
+
+instance (FromJSON wrapped, CursorKey c) =>
+         FromJSON (WithCursor c wrapped) where
+    parseJSON (Object o) = checkError o >>
+      WithCursor <$> o .:  "previous_cursor"
+                 <*> o .:  "next_cursor"
+                 <*> o .:  cursorKey (undefined :: c)
+    parseJSON _ = mempty
diff --git a/Web/Twitter/Conduit/Error.hs b/Web/Twitter/Conduit/Error.hs
new file mode 100644
--- /dev/null
+++ b/Web/Twitter/Conduit/Error.hs
@@ -0,0 +1,15 @@
+{-# LANGUAGE DeriveDataTypeable #-}
+
+module Web.Twitter.Conduit.Error
+       ( TwitterError (..)
+       ) where
+
+import Control.Exception
+import Data.Data
+
+data TwitterError
+  = TwitterError String
+  deriving (Show, Data, Typeable)
+
+instance Exception TwitterError
+
diff --git a/Web/Twitter/Conduit/Monad.hs b/Web/Twitter/Conduit/Monad.hs
new file mode 100644
--- /dev/null
+++ b/Web/Twitter/Conduit/Monad.hs
@@ -0,0 +1,109 @@
+{-# LANGUAGE GADTs #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE CPP #-}
+
+module Web.Twitter.Conduit.Monad
+       ( TW
+       , TWToken (..)
+       , TWInfo (..)
+       , setCredential
+       , runTW
+       , runTWManager
+       , getProxy
+       , getManager
+       , signOAuthTW
+       , twitterOAuth
+       )
+       where
+
+import Web.Authenticate.OAuth
+import Network.HTTP.Conduit
+import Data.Default
+import Control.Monad.IO.Class
+import Control.Monad.Trans.Reader
+import Control.Monad.Trans.Resource
+
+-- $setup
+-- >>> :set -XOverloadedStrings
+
+type TW m = ReaderT TWEnv m
+
+data TWToken = TWToken
+    { twOAuth :: OAuth
+    , twCredential :: Credential
+    }
+instance Default TWToken where
+    def = TWToken twitterOAuth (Credential [])
+
+data TWInfo = TWInfo
+    { twToken :: TWToken
+    , twProxy :: Maybe Proxy
+    }
+instance Default TWInfo where
+    def = TWInfo
+        { twToken = def
+        , twProxy = Nothing
+        }
+
+twitterOAuth :: OAuth
+twitterOAuth =
+    def { oauthServerName = "twitter"
+        , oauthRequestUri = "https://api.twitter.com/oauth/request_token"
+        , oauthAccessTokenUri = "https://api.twitter.com/oauth/access_token"
+        , oauthAuthorizeUri = "https://api.twitter.com/oauth/authorize"
+        , oauthConsumerKey = error "You MUST specify oauthConsumerKey parameter."
+        , oauthConsumerSecret = error "You MUST specify oauthConsumerSecret parameter."
+        , oauthSignatureMethod = HMACSHA1
+        , oauthCallback = Nothing
+        }
+
+data TWEnv = TWEnv
+    { twInfo :: TWInfo
+    , twManager :: Manager
+    }
+
+-- | set OAuth keys and Credentials to TWInfo.
+--
+-- >>> let proxy = Proxy "localhost" 8080
+-- >>> let twinfo = def { twProxy = Just proxy }
+-- >>> let oauth = twitterOAuth { oauthConsumerKey = "consumer_key", oauthConsumerSecret = "consumer_secret" }
+-- >>> let credential = Credential [("oauth_token","...")]
+-- >>> let twinfo2 = setCredential oauth credential twinfo
+-- >>> oauthConsumerKey . twOAuth . twToken $ twinfo2
+-- "consumer_key"
+-- >>> twProxy twinfo2 == Just proxy
+-- True
+setCredential :: OAuth -> Credential -> TWInfo -> TWInfo
+setCredential oa cred env
+  = TWInfo
+    { twToken = TWToken oa cred
+    , twProxy = twProxy env
+    }
+
+-- | create a new http-conduit manager and run TW monad.
+--
+-- >>> runTW def getProxy
+-- Nothing
+-- >>> runTW def $ asks (twCredential . twToken . twInfo)
+-- Credential {unCredential = []}
+runTW :: ( MonadBaseControl IO m
+         , MonadIO m
+         ) => TWInfo -> TW (ResourceT m) a -> m a
+runTW info st = withManager $ \mgr -> runTWManager info mgr st
+
+runTWManager :: MonadBaseControl IO m => TWInfo -> Manager -> TW (ResourceT m) a -> ResourceT m a
+runTWManager info mgr st = runReaderT st $ TWEnv info mgr
+
+getProxy ::Monad m => TW m (Maybe Proxy)
+getProxy = asks (twProxy . twInfo)
+
+getManager :: Monad m => TW m Manager
+getManager = asks twManager
+
+signOAuthTW :: MonadUnsafeIO m
+            => Request
+            -> TW m Request
+signOAuthTW req = do
+    TWToken oa cred <- asks (twToken . twInfo)
+    signOAuth oa cred req
diff --git a/Web/Twitter/Conduit/Parameters.hs b/Web/Twitter/Conduit/Parameters.hs
new file mode 100644
--- /dev/null
+++ b/Web/Twitter/Conduit/Parameters.hs
@@ -0,0 +1,110 @@
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE TemplateHaskell #-}
+
+module Web.Twitter.Conduit.Parameters
+       ( Parameters (..)
+       , HasSinceIdParam (..)
+       , HasCountParam (..)
+       , HasMaxIdParam (..)
+       , HasPageParam (..)
+       , HasCursorParam (..)
+       , HasTrimUserParam (..)
+       , HasExcludeRepliesParam (..)
+       , HasContributorDetailsParam (..)
+       , HasIncludeEntitiesParam (..)
+       , HasIncludeUserEntitiesParam (..)
+       , HasIncludeRtsParam (..)
+       , HasIncludeMyRetweetParam (..)
+       , HasInReplyToStatusIdParam (..)
+       , HasDisplayCoordinatesParam (..)
+       , HasPossiblySensitiveParam (..)
+       , HasLangParam (..)
+       , HasLocaleParam (..)
+       , HasUntilParam (..)
+       , HasSkipStatusParam (..)
+       , HasFollowParam (..)
+
+       , UserParam(..)
+       , UserListParam(..)
+       , ListParam(..)
+       , mkUserParam
+       , mkUserListParam
+       , mkListParam
+       ) where
+
+import Web.Twitter.Conduit.Parameters.Internal
+import Web.Twitter.Conduit.Parameters.TH
+import Web.Twitter.Types
+import Data.Time.Calendar (Day)
+import Data.Text.Strict.Lens
+import Data.Text (Text)
+import Control.Lens
+
+import qualified Network.HTTP.Types as HT
+import qualified Data.ByteString.Char8 as S8
+
+data UserParam = UserIdParam UserId | ScreenNameParam String
+               deriving (Show, Eq)
+data UserListParam = UserIdListParam [UserId] | ScreenNameListParam [String]
+                   deriving (Show, Eq)
+data ListParam = ListIdParam Integer | ListNameParam String
+               deriving (Show, Eq)
+
+defineHasParamClass "count" ''Integer 'readShow
+defineHasParamClass "since_id" ''Integer 'readShow
+defineHasParamClass "max_id" ''Integer 'readShow
+defineHasParamClass "page" ''Integer 'readShow
+defineHasParamClass "cursor" ''Integer 'readShow
+defineHasParamClass "trim_user" ''Bool 'booleanQuery
+defineHasParamClass "exclude_replies" ''Bool 'booleanQuery
+defineHasParamClass "contributor_details" ''Bool 'booleanQuery
+defineHasParamClass "include_entities" ''Bool 'booleanQuery
+defineHasParamClass "include_user_entities" ''Bool 'booleanQuery
+defineHasParamClass "include_rts" ''Bool 'booleanQuery
+defineHasParamClass "include_my_retweet" ''Bool 'booleanQuery
+defineHasParamClass "in_reply_to_status_id" ''StatusId 'readShow
+defineHasParamClass "display_coordinates" ''Bool 'booleanQuery
+defineHasParamClass "possibly_sensitive" ''Bool 'booleanQuery
+defineHasParamClass "lang" ''Text 'utf8
+defineHasParamClass "locale" ''Text 'utf8
+defineHasParamClass "until" ''Day 'readShow
+defineHasParamClass "skip_status" ''Bool 'booleanQuery
+defineHasParamClass "follow" ''Bool 'booleanQuery
+
+-- | converts 'UserParam' to 'HT.SimpleQuery'.
+--
+-- >>> mkUserParam $ UserIdParam 123456
+-- [("user_id","123456")]
+-- >>> mkUserParam $ ScreenNameParam "thimura"
+-- [("screen_name","thimura")]
+mkUserParam :: UserParam -> HT.SimpleQuery
+mkUserParam (UserIdParam uid) =  [("user_id", readShow # uid)]
+mkUserParam (ScreenNameParam sn) = [("screen_name", S8.pack sn)]
+
+-- | converts 'UserListParam' to 'HT.SimpleQuery'.
+--
+-- >>> mkUserListParam $ UserIdListParam [123456]
+-- [("user_id","123456")]
+-- >>> mkUserListParam $ UserIdListParam [123456, 654321]
+-- [("user_id","123456,654321")]
+-- >>> mkUserListParam $ ScreenNameListParam ["thimura", "NikaidouShinku"]
+-- [("screen_name","thimura,NikaidouShinku")]
+mkUserListParam :: UserListParam -> HT.SimpleQuery
+mkUserListParam (UserIdListParam uids) =  [("user_id", uids ^.. traversed . re readShow & S8.intercalate ",")]
+mkUserListParam (ScreenNameListParam sns) = [("screen_name", S8.intercalate "," . map S8.pack $ sns)]
+
+-- | converts 'ListParam' to 'HT.SimpleQuery'.
+--
+-- >>> mkListParam $ ListIdParam 123123
+-- [("list_id","123123")]
+-- >>> mkListParam $ ListNameParam "thimura/haskell"
+-- [("slug","haskell"),("owner_screen_name","thimura")]
+mkListParam :: ListParam -> HT.SimpleQuery
+mkListParam (ListIdParam lid) =  [("list_id", readShow # lid)]
+mkListParam (ListNameParam listname) =
+    [("slug", S8.pack lstName),
+     ("owner_screen_name", S8.pack screenName)]
+  where
+    (screenName, ln) = span (/= '/') listname
+    lstName = drop 1 ln
+
diff --git a/Web/Twitter/Conduit/Parameters/Internal.hs b/Web/Twitter/Conduit/Parameters/Internal.hs
new file mode 100644
--- /dev/null
+++ b/Web/Twitter/Conduit/Parameters/Internal.hs
@@ -0,0 +1,63 @@
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE Rank2Types #-}
+
+module Web.Twitter.Conduit.Parameters.Internal
+       ( Parameters(..)
+       , readShow
+       , booleanQuery
+       , wrappedParam
+       ) where
+
+import qualified Network.HTTP.Types as HT
+import qualified Data.ByteString as S
+import qualified Data.ByteString.Char8 as S8
+import Control.Lens
+
+class Parameters a where
+    params :: Lens' a HT.SimpleQuery
+
+-- | This 'Prism' convert from a 'ByteString' to some value based on 'Read' and 'Show'
+--
+-- >>> readShow # 2
+-- "2"
+-- >>> "1024" ^? readShow :: Maybe Integer
+-- Just 1024
+readShow :: (Read a, Show a) => Prism' S.ByteString a
+readShow = prism' (S8.pack . show) (readMaybe . S8.unpack)
+  where
+    readMaybe str = case [x | (x, t) <- reads str, ("", "") <- lex t] of
+        [x] -> Just x
+        _ -> Nothing
+
+-- | This 'Prism' convert from a 'ByteString' to 'Bool' value.
+--
+-- >>> booleanQuery # True
+-- "true"
+-- >>> booleanQuery # False
+-- "false"
+-- >>> "true" ^? booleanQuery
+-- Just True
+-- >>> "1" ^? booleanQuery
+-- Just True
+-- >>> "t" ^? booleanQuery
+-- Just True
+-- >>> "test" ^? booleanQuery
+-- Just False
+booleanQuery :: Prism' S.ByteString Bool
+booleanQuery = prism' bs sb
+  where
+    bs True = "true"
+    bs False = "false"
+    sb "true" = Just True
+    sb "1" = Just True
+    sb "t" = Just True
+    sb _ = Just False
+
+wrappedParam :: Parameters p => S.ByteString -> Prism' S.ByteString a -> Lens' p (Maybe a)
+wrappedParam key aSBS = lens getter setter
+   where
+     getter = preview $ params . to (lookup key) . _Just . aSBS
+     setter = flip (over params . replace key)
+     replace k (Just v) = ((k, aSBS # v):) . dropAssoc k
+     replace k Nothing = dropAssoc k
+     dropAssoc k = filter ((/= k) . fst)
diff --git a/Web/Twitter/Conduit/Parameters/TH.hs b/Web/Twitter/Conduit/Parameters/TH.hs
new file mode 100644
--- /dev/null
+++ b/Web/Twitter/Conduit/Parameters/TH.hs
@@ -0,0 +1,59 @@
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE Rank2Types #-}
+{-# LANGUAGE TemplateHaskell #-}
+
+module Web.Twitter.Conduit.Parameters.TH where
+
+import Web.Twitter.Conduit.Parameters.Internal
+import Language.Haskell.TH
+import Control.Lens
+import Data.Char
+
+snakeToLowerCamel :: String -> String
+snakeToLowerCamel [] = []
+snakeToLowerCamel ('_':[]) = []
+snakeToLowerCamel ('_':x:xs) = toUpper x : snakeToLowerCamel xs
+snakeToLowerCamel str = f ++ snakeToLowerCamel next
+  where (f, next) = span (/= '_') str
+
+snakeToUpperCamel :: String -> String
+snakeToUpperCamel = upcase . snakeToLowerCamel
+  where
+    upcase [] = []
+    upcase (x:xs) = toUpper x : xs
+
+paramNameToClassName :: String -> String
+paramNameToClassName paramName = "Has" ++ snakeToUpperCamel paramName ++ "Param"
+
+defineHasParamClass :: String -- ^ parameter name
+                    -> Name -- ^ parameter type
+                    -> Name -- ^ a Prism
+                    -> Q [Dec]
+defineHasParamClass paramName typeN prismN =
+    defineHasParamClass' cNameS fNameS paramName typeN prismN
+  where
+    cNameS = paramNameToClassName paramName
+    fNameS = snakeToLowerCamel paramName
+
+defineHasParamClass' :: String -> String -> String -> Name -> Name -> Q [Dec]
+defineHasParamClass' cNameS fNameS paramName typeN prismN = do
+    a <- newName "a"
+    cName <- newName cNameS
+    fName <- newName fNameS
+    let cCxt = cxt [classP ''Parameters [varT a]]
+        tySig = sigD fName (appT (appT (conT ''Lens') (varT a)) (appT (conT ''Maybe) (conT typeN)))
+        valDef = valD (varP fName) (normalB (appE (appE (varE 'wrappedParam) (litE (stringL paramName))) (varE prismN))) []
+    dec <- classD cCxt cName [PlainTV a] [] [tySig, valDef]
+    return [dec]
+
+deriveHasParamInstances :: Name -- ^ target data type name
+                        -> [String] -- ^ parameter name
+                        -> Q [Dec]
+deriveHasParamInstances typName paramNameList =
+    mapM mkInstance cNameStrList
+  where
+    cNameStrList = map paramNameToClassName paramNameList
+    mkInstance cn = instanceD (return []) (appT (conT (mkName cn)) targetType) []
+    targetType = do
+        a <- newName "a"
+        appT (appT (conT (mkName "APIRequest")) (conT typName)) (varT a)
diff --git a/Web/Twitter/Conduit/Request.hs b/Web/Twitter/Conduit/Request.hs
new file mode 100644
--- /dev/null
+++ b/Web/Twitter/Conduit/Request.hs
@@ -0,0 +1,72 @@
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE Rank2Types #-}
+{-# LANGUAGE FlexibleInstances #-}
+
+module Web.Twitter.Conduit.Request
+       ( APIRequest(..)
+       ) where
+
+import Web.Twitter.Conduit.Parameters
+
+import Network.HTTP.Client.MultipartFormData
+import qualified Network.HTTP.Types as HT
+import Control.Applicative
+
+-- $setup
+-- >>> :set -XOverloadedStrings -XRank2Types -XEmptyDataDecls -XFlexibleInstances
+-- >>> import Control.Lens
+-- >>> import Data.Default
+-- >>> data SampleApi
+-- >>> type SampleId = Integer
+-- >>> instance HasCountParam (APIRequest SampleApi [SampleId])
+-- >>> instance HasMaxIdParam (APIRequest SampleApi [SampleId])
+-- >>> let sampleApiRequest :: APIRequest SampleApi [SampleId]; sampleApiRequest = APIRequestGet "https://api.twitter.com/sample/api.json" def
+
+-- | API request. You should use specific builder functions instead of building this directly.
+--
+-- For example, if there were a @SampleApi@ type and a builder function which named @sampleApiRequest@.
+-- In addition, @'APIRequest' SampleApi [SampleId]@ is a instance of both of 'HasCountParam' and 'HasMaxIdParam'.
+--
+-- @
+-- data 'SampleApi'
+-- type 'SampleId' = 'Integer'
+-- instance 'HasCountParam' ('APIRequest' 'SampleApi' ['SampleId'])
+-- instance 'HasMaxIdParam' ('APIRequest' 'SampleApi' ['SampleId'])
+-- 'sampleApiRequest' :: 'APIRequest' 'SampleApi' ['SampleId']
+-- 'sampleApiRequest' = 'APIRequestGet' \"https:\/\/api.twitter.com\/sample\/api.json\" 'def'
+-- @
+--
+-- We can obtain request params from @'APIRequest' SampleApi [SampleId]@ :
+--
+-- >>> sampleApiRequest ^. params
+-- []
+--
+-- And update request parameters.
+--
+-- >>> (sampleApiRequest & count ?~ 100 & maxId ?~ 1234567890) ^. params
+-- [("max_id","1234567890"),("count","100")]
+-- >>> (sampleApiRequest & count ?~ 100 & maxId ?~ 1234567890 & count .~ Nothing) ^. params
+-- [("max_id","1234567890")]
+data APIRequest apiName responseType
+    = APIRequestGet
+      { _url :: String
+      , _params :: HT.SimpleQuery
+      }
+    | APIRequestPost
+      { _url :: String
+      , _params :: HT.SimpleQuery
+      }
+    | APIRequestPostMultipart
+      { _url :: String
+      , _params :: HT.SimpleQuery
+      , _part :: [Part]
+      }
+instance Parameters (APIRequest apiName responseType) where
+    params f (APIRequestGet u pa) = APIRequestGet u <$> f pa
+    params f (APIRequestPost u pa) = APIRequestPost u <$> f pa
+    params f (APIRequestPostMultipart u pa prt) =
+        (\p -> APIRequestPostMultipart u p prt) <$> f pa
+instance Show (APIRequest apiName responseType) where
+    show (APIRequestGet u p) = "APIRequestGet " ++ show u ++ " " ++ show p
+    show (APIRequestPost u p) = "APIRequestPost " ++ show u ++ " " ++ show p
+    show (APIRequestPostMultipart u p _) = "APIRequestPostMultipart " ++ show u ++ " " ++ show p
diff --git a/Web/Twitter/Conduit/Status.hs b/Web/Twitter/Conduit/Status.hs
new file mode 100644
--- /dev/null
+++ b/Web/Twitter/Conduit/Status.hs
@@ -0,0 +1,290 @@
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE TemplateHaskell #-}
+{-# LANGUAGE QuasiQuotes #-}
+{-# LANGUAGE EmptyDataDecls #-}
+#if __GLASGOW_HASKELL__ >= 704
+{-# LANGUAGE ConstraintKinds #-}
+#endif
+
+module Web.Twitter.Conduit.Status
+       (
+       -- * Timelines
+         StatusesMentionsTimeline
+       , mentionsTimeline
+       , StatusesUserTimeline
+       , userTimeline
+       , StatusesHomeTimeline
+       , homeTimeline
+       , StatusesRetweetsOfMe
+       , retweetsOfMe
+       -- * Tweets
+       , StatusesRetweetsId
+       , retweetsId
+       , StatusesShowId
+       , showId
+       , StatusesDestroyId
+       , destroyId
+       , StatusesUpdate
+       , update
+       , StatusesRetweetId
+       , retweetId
+       , MediaData (..)
+       , StatusesUpdateWithMedia
+       , updateWithMedia
+       -- , oembed
+       -- , retweetersIds
+       ) where
+
+import Web.Twitter.Conduit.Base
+import Web.Twitter.Conduit.Request
+import Web.Twitter.Conduit.Parameters
+import Web.Twitter.Conduit.Parameters.TH
+import Web.Twitter.Types
+
+import qualified Data.Text as T
+import qualified Data.Text.Encoding as T
+import Network.HTTP.Client.MultipartFormData
+import Network.HTTP.Conduit
+import Data.Default
+
+-- $setup
+-- >>> :set -XOverloadedStrings
+-- >>> import Control.Lens
+
+-- * Timelines
+
+data StatusesMentionsTimeline
+-- | Returns query data asks the most recent mentions for the authenticating user.
+--
+-- You can perform a query using 'call':
+--
+-- @
+-- res <- 'call' 'mentionsTimeline'
+-- @
+--
+-- >>> mentionsTimeline
+-- APIRequestGet "https://api.twitter.com/1.1/statuses/mentions_timeline.json" []
+mentionsTimeline :: APIRequest StatusesMentionsTimeline [Status]
+mentionsTimeline = APIRequestGet (endpoint ++ "statuses/mentions_timeline.json") def
+deriveHasParamInstances ''StatusesMentionsTimeline
+    [ "count"
+    , "since_id"
+    , "max_id"
+    , "trim_user"
+    , "contributor_details"
+    , "include_entities"
+    ]
+
+data StatusesUserTimeline
+-- | Returns query data asks a collection of the most recent Tweets posted by the user indicated by the screen_name or user_id parameters.
+--
+-- You can perform a search query using 'call':
+--
+-- @
+-- res <- 'call' $ 'userTimeline' ('ScreenNameParam' \"thimura\")
+-- @
+--
+-- >>> userTimeline (ScreenNameParam "thimura")
+-- APIRequestGet "https://api.twitter.com/1.1/statuses/user_timeline.json" [("screen_name","thimura")]
+-- >>> userTimeline (ScreenNameParam "thimura") & includeRts ?~ True & count ?~ 200
+-- APIRequestGet "https://api.twitter.com/1.1/statuses/user_timeline.json" [("count","200"),("include_rts","true"),("screen_name","thimura")]
+userTimeline :: UserParam -> APIRequest StatusesUserTimeline [Status]
+userTimeline q = APIRequestGet (endpoint ++ "statuses/user_timeline.json") (mkUserParam q)
+deriveHasParamInstances ''StatusesUserTimeline
+    [ "count"
+    , "since_id"
+    , "max_id"
+    , "trim_user"
+    , "exclude_replies"
+    , "contributor_details"
+    , "include_rts"
+    ]
+
+data StatusesHomeTimeline
+-- | Returns query data asks a collection of the most recentTweets and retweets posted by the authenticating user and the users they follow.
+--
+-- You can perform a search query using 'call':
+--
+-- @
+-- res <- 'call' 'homeTimeline'
+-- @
+--
+-- >>> homeTimeline
+-- APIRequestGet "https://api.twitter.com/1.1/statuses/home_timeline.json" []
+-- >>> homeTimeline & count ?~ 200
+-- APIRequestGet "https://api.twitter.com/1.1/statuses/home_timeline.json" [("count","200")]
+homeTimeline :: APIRequest StatusesHomeTimeline [Status]
+homeTimeline = APIRequestGet (endpoint ++ "statuses/home_timeline.json") def
+deriveHasParamInstances ''StatusesHomeTimeline
+    [ "count"
+    , "since_id"
+    , "max_id"
+    , "trim_user"
+    , "exclude_replies"
+    , "contributor_details"
+    , "include_entities"
+    ]
+
+data StatusesRetweetsOfMe
+-- | Returns query data asks the most recent tweets authored by the authenticating user that have been retweeted by others.
+--
+-- You can perform a search query using 'call':
+--
+-- @
+-- res <- 'call' 'retweetsOfMe'
+-- @
+--
+-- >>> retweetsOfMe
+-- APIRequestGet "https://api.twitter.com/1.1/statuses/retweets_of_me.json" []
+-- >>> retweetsOfMe & count ?~ 100
+-- APIRequestGet "https://api.twitter.com/1.1/statuses/retweets_of_me.json" [("count","100")]
+retweetsOfMe :: APIRequest StatusesRetweetsOfMe [Status]
+retweetsOfMe = APIRequestGet (endpoint ++ "statuses/retweets_of_me.json") def
+deriveHasParamInstances ''StatusesRetweetsOfMe
+    [ "count"
+    , "since_id"
+    , "max_id"
+    , "trim_user"
+    , "include_entities"
+    , "include_user_entities"
+    ]
+
+-- * Tweets
+
+data StatusesRetweetsId
+-- | Returns query data asks the most recent tweets authored by the authenticating user that have been retweeted by others.
+--
+-- You can perform a search query using 'call':
+--
+-- @
+-- res <- 'call' '$' 'retweetsId' 1234567890
+-- @
+--
+-- >>> retweetsId 1234567890
+-- APIRequestGet "https://api.twitter.com/1.1/statuses/retweets/1234567890.json" []
+-- >>> retweetsId 1234567890 & count ?~ 100
+-- APIRequestGet "https://api.twitter.com/1.1/statuses/retweets/1234567890.json" [("count","100")]
+retweetsId :: StatusId -> APIRequest StatusesRetweetsId [RetweetedStatus]
+retweetsId status_id = APIRequestGet uri def
+  where uri = endpoint ++ "statuses/retweets/" ++ show status_id ++ ".json"
+deriveHasParamInstances ''StatusesRetweetsId
+    [ "count"
+    , "trim_user"
+    ]
+
+data StatusesShowId
+-- | Returns query data asks a single Tweet, specified by the id parameter.
+--
+-- You can perform a search query using 'call':
+--
+-- @
+-- res <- 'call' '$' 'showId' 1234567890
+-- @
+--
+-- >>> showId 1234567890
+-- APIRequestGet "https://api.twitter.com/1.1/statuses/show/1234567890.json" []
+-- >>> showId 1234567890 & includeMyRetweet ?~ True
+-- APIRequestGet "https://api.twitter.com/1.1/statuses/show/1234567890.json" [("include_my_retweet","true")]
+showId :: StatusId -> APIRequest StatusesShowId Status
+showId status_id = APIRequestGet uri def
+  where uri = endpoint ++ "statuses/show/" ++ show status_id ++ ".json"
+deriveHasParamInstances ''StatusesShowId
+    [ "trim_user"
+    , "include_my_retweet"
+    , "include_entities"
+    ]
+
+data StatusesDestroyId
+-- | Returns post data which destroys the status specified by the require ID parameter.
+--
+-- You can perform a search query using 'call':
+--
+-- @
+-- res <- 'call' '$' 'destroyId' 1234567890
+-- @
+--
+-- >>> destroyId 1234567890
+-- APIRequestPost "https://api.twitter.com/1.1/statuses/destroy/1234567890.json" []
+destroyId :: StatusId -> APIRequest StatusesDestroyId Status
+destroyId status_id = APIRequestPost uri def
+  where uri = endpoint ++ "statuses/destroy/" ++ show status_id ++ ".json"
+deriveHasParamInstances ''StatusesDestroyId
+    [ "trim_user"
+    ]
+
+data StatusesUpdate
+-- | Returns post data which updates the authenticating user's current status.
+-- To upload an image to accompany the tweet, use 'updateWithMedia'.
+--
+-- You can perform a search query using 'call':
+--
+-- @
+-- res <- 'call' '$' 'update' \"Hello World\"
+-- @
+--
+-- >>> update "Hello World"
+-- APIRequestPost "https://api.twitter.com/1.1/statuses/update.json" [("status","Hello World")]
+-- >>> update "Hello World" & inReplyToStatusId ?~ 1234567890
+-- APIRequestPost "https://api.twitter.com/1.1/statuses/update.json" [("in_reply_to_status_id","1234567890"),("status","Hello World")]
+update :: T.Text -> APIRequest StatusesUpdate Status
+update status = APIRequestPost uri [("status", T.encodeUtf8 status)]
+  where uri = endpoint ++ "statuses/update.json"
+deriveHasParamInstances ''StatusesUpdate
+    [ "in_reply_to_status_id"
+    -- , "lat_long"
+    -- , "place_id"
+    , "display_coordinates"
+    , "trim_user"
+    ]
+
+data StatusesRetweetId
+-- | Returns post data which retweets a tweet, specified by ID.
+--
+-- You can perform a search query using 'call':
+--
+-- @
+-- res <- 'call' '$' 'retweetId' 1234567890
+-- @
+--
+-- >>> retweetId 1234567890
+-- APIRequestPost "https://api.twitter.com/1.1/statuses/retweet/1234567890.json" []
+retweetId :: StatusId -> APIRequest StatusesRetweetId RetweetedStatus
+retweetId status_id = APIRequestPost uri def
+  where uri = endpoint ++ "statuses/retweet/" ++ show status_id ++ ".json"
+deriveHasParamInstances ''StatusesRetweetId
+    [ "trim_user"
+    ]
+
+data MediaData = MediaFromFile FilePath
+               | MediaRequestBody FilePath RequestBody
+
+data StatusesUpdateWithMedia
+-- | Returns post data which updates the authenticating user's current status and attaches media for upload.
+--
+-- You can perform a search query using 'call':
+--
+-- @
+-- res <- 'call' '$' 'updateWithMedia' \"Hello World\" ('MediaFromFile' \"/home/thimura/test.jpeg\")
+-- @
+--
+-- >>> updateWithMedia "Hello World" (MediaFromFile "/home/fuga/test.jpeg")
+-- APIRequestPostMultipart "https://api.twitter.com/1.1/statuses/update_with_media.json" [("status","Hello World")]
+updateWithMedia :: T.Text
+                -> MediaData
+                -> APIRequest StatusesUpdateWithMedia Status
+updateWithMedia tweet mediaData =
+    APIRequestPostMultipart uri [("status", T.encodeUtf8 tweet)] [mediaBody mediaData]
+  where
+    uri = endpoint ++ "statuses/update_with_media.json"
+    mediaBody (MediaFromFile fp) = partFileSource "media[]" fp
+    mediaBody (MediaRequestBody filename filebody) = partFileRequestBody "media[]" filename filebody
+deriveHasParamInstances ''StatusesUpdateWithMedia
+    [ "possibly_sensitive"
+    , "in_reply_to_status_id"
+    -- , "lat_long"
+    -- , "place_id"
+    , "display_coordinates"
+    ]
diff --git a/Web/Twitter/Conduit/Stream.hs b/Web/Twitter/Conduit/Stream.hs
new file mode 100644
--- /dev/null
+++ b/Web/Twitter/Conduit/Stream.hs
@@ -0,0 +1,77 @@
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE EmptyDataDecls #-}
+{-# LANGUAGE CPP #-}
+#if __GLASGOW_HASKELL__ >= 704
+{-# LANGUAGE ConstraintKinds #-}
+#endif
+
+module Web.Twitter.Conduit.Stream
+       (
+       -- * StreamingAPI
+         userstream
+       , statusesFilterByFollow
+       , statusesFilterByTrack
+       -- , statusesFilterByLocation
+       -- , statusesSample
+       -- , statusesFirehose
+       -- , sitestream
+       -- , sitestream'
+       , stream
+  ) where
+
+import Web.Twitter.Conduit.Base
+import Web.Twitter.Conduit.Monad
+import Web.Twitter.Types
+import Web.Twitter.Conduit.Request
+
+import qualified Data.Conduit as C
+import qualified Data.Conduit.List as CL
+import qualified Data.Conduit.Internal as CI
+import qualified Data.Text as T
+import qualified Data.Text.Encoding as T
+import qualified Data.ByteString as S
+import Control.Monad.IO.Class
+import Data.Aeson
+
+($=+) :: MonadIO m
+      => CI.ResumableSource m a
+      -> CI.Conduit a m o
+      -> m (CI.ResumableSource m o)
+rsrc $=+ cndt = do
+    (src, finalizer) <- C.unwrapResumable rsrc
+    return $ CI.ResumableSource (src C.$= cndt) finalizer
+
+stream :: (TwitterBaseM m, FromJSON responseType)
+       => APIRequest apiName responseType
+       -> TW m (C.ResumableSource (TW m) responseType)
+stream = stream'
+
+stream' :: (TwitterBaseM m, FromJSON value)
+        => APIRequest apiName responseType
+        -> TW m (C.ResumableSource (TW m) value)
+stream' (APIRequestGet u pa) = do
+    rsrc <- api "GET" u pa
+    rsrc $=+ CL.sequence sinkFromJSON
+stream' (APIRequestPost u pa) = do
+    rsrc <- api "POST" u pa
+    rsrc $=+ CL.sequence sinkFromJSON
+stream' APIRequestPostMultipart {} =
+    error "APIRequestPostMultipart is not supported by stream function."
+
+data Userstream
+userstream :: APIRequest Userstream StreamingAPI
+userstream = APIRequestGet "https://userstream.twitter.com/1.1/user.json" []
+
+statusesFilterEndpoint :: String
+statusesFilterEndpoint = "https://stream.twitter.com/1.1/statuses/filter.json"
+
+data StatusesFilter
+statusesFilterByFollow :: [UserId] -> APIRequest StatusesFilter StreamingAPI
+statusesFilterByFollow userIds =
+    APIRequestPost statusesFilterEndpoint [("follow", S.intercalate "," . map showBS $ userIds)]
+
+statusesFilterByTrack :: T.Text -- ^ keyword
+                      -> APIRequest StatusesFilter StreamingAPI
+statusesFilterByTrack keyword =
+    APIRequestPost statusesFilterEndpoint [("track", T.encodeUtf8 keyword)]
diff --git a/sample/oauth_callback.hs b/sample/oauth_callback.hs
new file mode 100644
--- /dev/null
+++ b/sample/oauth_callback.hs
@@ -0,0 +1,99 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+-- Example:
+--   $ export OAUTH_CONSUMER_KEY="your consumer key"
+--   $ export OAUTH_CONSUMER_SECRET="your consumer secret"
+--   $ runhaskell oauth_callback.hs
+
+module Main where
+
+import Web.Scotty
+import qualified Network.HTTP.Types as HT
+import Web.Twitter.Conduit hiding (text)
+import Web.Authenticate.OAuth (OAuth(..), Credential(..))
+import qualified Web.Authenticate.OAuth as OA
+import qualified Network.HTTP.Conduit as HTTP
+import qualified Data.Text.Lazy as LT
+import qualified Data.ByteString as S
+import qualified Data.ByteString.Char8 as S8
+import qualified Data.Map as M
+import Data.Maybe
+import Data.Monoid
+import Data.IORef
+import Control.Monad.IO.Class
+import System.Environment
+import System.IO.Unsafe
+
+callback :: String
+callback = "http://localhost:3000/callback"
+
+getTokens :: IO OAuth
+getTokens = do
+    consumerKey <- getEnv "OAUTH_CONSUMER_KEY"
+    consumerSecret <- getEnv "OAUTH_CONSUMER_SECRET"
+    return $
+        twitterOAuth
+        { oauthConsumerKey = S8.pack consumerKey
+        , oauthConsumerSecret = S8.pack consumerSecret
+        , oauthCallback = Just $ S8.pack callback
+        }
+
+type OAuthToken = S.ByteString
+
+usersToken :: IORef (M.Map OAuthToken Credential)
+usersToken = unsafePerformIO $ newIORef M.empty
+
+takeCredential :: OAuthToken -> IORef (M.Map OAuthToken Credential) -> IO (Maybe Credential)
+takeCredential k ioref =
+    atomicModifyIORef ioref $ \m ->
+        let (res, newm) = M.updateLookupWithKey (\_ _ -> Nothing) k m in
+        (newm, res)
+
+storeCredential :: OAuthToken -> Credential -> IORef (M.Map OAuthToken Credential) -> IO ()
+storeCredential k cred ioref =
+    atomicModifyIORef ioref $ \m -> (M.insert k cred m, ())
+
+main :: IO ()
+main = do
+    tokens <- getTokens
+    putStrLn $ "browse URL: http://localhost:3000/signIn"
+    scotty 3000 $ app tokens
+
+makeMessage :: OAuth -> Credential -> S.ByteString
+makeMessage tokens (Credential cred) =
+    S8.intercalate "\n"
+        [ "export OAUTH_CONSUMER_KEY=\"" <> oauthConsumerKey tokens <> "\""
+        , "export OAUTH_CONSUMER_SECRET=\"" <> oauthConsumerSecret tokens <> "\""
+        , "export OAUTH_ACCESS_TOKEN=\"" <> fromMaybe "" (lookup "oauth_token" cred) <> "\""
+        , "export OAUTH_ACCESS_SECRET=\"" <> fromMaybe "" (lookup "oauth_token_secret" cred) <> "\""
+        ]
+
+app :: OAuth -> ScottyM ()
+app tokens = do
+    get "/callback" $ do
+        temporaryToken <- param "oauth_token"
+        oauthVerifier <- param "oauth_verifier"
+        mcred <- liftIO $ takeCredential temporaryToken usersToken
+        case mcred of
+            Just cred -> do
+                accessTokens <- liftIO $ HTTP.withManager $ OA.getAccessToken tokens (OA.insert "oauth_verifier" oauthVerifier cred)
+                liftIO $ print accessTokens
+
+                let message = makeMessage tokens accessTokens
+                liftIO . S8.putStrLn $ message
+                text . LT.pack . S8.unpack $ message
+
+            Nothing -> do
+                status HT.status404
+                text "temporary token is not found"
+
+    get "/signIn" $ do
+        cred <- liftIO $ HTTP.withManager $ OA.getTemporaryCredential tokens
+        case lookup "oauth_token" $ unCredential cred of
+            Just temporaryToken -> do
+                liftIO $ storeCredential temporaryToken cred usersToken
+                let url = OA.authorizeUrl tokens cred
+                redirect $ LT.pack url
+            Nothing -> do
+                status HT.status500
+                text "Failed to obtain the temporary token."
diff --git a/sample/oauth_pin.hs b/sample/oauth_pin.hs
new file mode 100644
--- /dev/null
+++ b/sample/oauth_pin.hs
@@ -0,0 +1,61 @@
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE FlexibleContexts #-}
+
+-- Example:
+--   $ export OAUTH_CONSUMER_KEY="your consumer key"
+--   $ export OAUTH_CONSUMER_SECRET="your consumer secret"
+--   $ runhaskell oauth_pin.hs
+
+module Main where
+
+import Web.Twitter.Conduit
+import Web.Authenticate.OAuth as OA
+import Network.HTTP.Conduit
+import qualified Data.Conduit as C
+import qualified Data.ByteString.Char8 as S8
+import Data.Maybe
+import Data.Monoid
+import Control.Monad.Trans.Control
+import Control.Monad.IO.Class
+import System.Environment
+import System.IO (hFlush, stdout)
+
+getTokens :: IO OAuth
+getTokens = do
+    consumerKey <- getEnv "OAUTH_CONSUMER_KEY"
+    consumerSecret <- getEnv "OAUTH_CONSUMER_SECRET"
+    return $
+        twitterOAuth
+        { oauthConsumerKey = S8.pack consumerKey
+        , oauthConsumerSecret = S8.pack consumerSecret
+        , oauthCallback = Just "oob"
+        }
+
+authorize :: (MonadBaseControl IO m, C.MonadResource m)
+          => OAuth -- ^ OAuth Consumer key and secret
+          -> Manager
+          -> m Credential
+authorize oauth mgr = do
+    cred <- OA.getTemporaryCredential oauth mgr
+    let url = OA.authorizeUrl oauth cred
+    pin <- getPIN url
+    OA.getAccessToken oauth (OA.insert "oauth_verifier" pin cred) mgr
+  where
+    getPIN url = liftIO $ do
+        putStrLn $ "browse URL: " ++ url
+        putStr "> what was the PIN twitter provided you with? "
+        hFlush stdout
+        S8.getLine
+
+main :: IO ()
+main = do
+    tokens <- getTokens
+    Credential cred <- liftIO $ withManager $ authorize tokens
+    print cred
+
+    S8.putStrLn . S8.intercalate "\n" $
+        [ "export OAUTH_CONSUMER_KEY=\"" <> oauthConsumerKey tokens <> "\""
+        , "export OAUTH_CONSUMER_SECRET=\"" <> oauthConsumerSecret tokens <> "\""
+        , "export OAUTH_ACCESS_TOKEN=\"" <> fromMaybe "" (lookup "oauth_token" cred) <> "\""
+        , "export OAUTH_ACCESS_SECRET=\"" <> fromMaybe "" (lookup "oauth_token_secret" cred) <> "\""
+        ]
diff --git a/sample/simple.hs b/sample/simple.hs
new file mode 100644
--- /dev/null
+++ b/sample/simple.hs
@@ -0,0 +1,63 @@
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE FlexibleContexts #-}
+
+module Main where
+
+import Web.Twitter.Conduit
+import Control.Lens
+import Web.Authenticate.OAuth (OAuth(..), Credential(..))
+import qualified Web.Authenticate.OAuth as OA
+import Network.HTTP.Conduit
+import qualified Data.Conduit as C
+import qualified Data.Conduit.List as CL
+import qualified Data.Text as T
+import qualified Data.Text.IO as T
+import qualified Data.ByteString.Char8 as B8
+import Data.Default
+import Control.Monad.Logger
+import Control.Monad.Trans.Control
+import Control.Monad.Trans.Resource
+import Control.Monad.IO.Class
+import System.IO (hFlush, stdout)
+
+tokens :: OAuth
+tokens = twitterOAuth
+    { oauthConsumerKey = error "You MUST specify oauthConsumerKey parameter."
+    , oauthConsumerSecret = error "You MUST specify oauthConsumerSecret parameter."
+    }
+
+authorize :: (MonadBaseControl IO m, C.MonadResource m)
+          => OAuth -- ^ OAuth Consumer key and secret
+          -> (String -> m String) -- ^ PIN prompt
+          -> Manager
+          -> m Credential
+authorize oauth getPIN mgr = do
+    cred <- OA.getTemporaryCredential oauth mgr
+    let url = OA.authorizeUrl oauth cred
+    pin <- getPIN url
+    OA.getAccessToken oauth (OA.insert "oauth_verifier" (B8.pack pin) cred) mgr
+
+withCredential :: (MonadLogger m, MonadBaseControl IO m, MonadIO m) => TW (ResourceT m) a -> m a
+withCredential task = do
+    cred <- liftIO $ withManager $ \mgr -> authorize tokens getPIN mgr
+    let env = setCredential tokens cred def
+    runTW env task
+  where
+    getPIN url = liftIO $ do
+        putStrLn $ "browse URL: " ++ url
+        putStr "> what was the PIN twitter provided you with? "
+        hFlush stdout
+        getLine
+
+main :: IO ()
+main = runNoLoggingT . withCredential $ do
+    liftIO . putStrLn $ "# your home timeline (up to 100 tweets):"
+    sourceWithMaxId homeTimeline
+        C.$= CL.isolate 100
+        C.$$ CL.mapM_ $ \status -> liftIO $ do
+            T.putStrLn $ T.concat [ T.pack . show $ status ^. statusId
+                                  , ": "
+                                  , status ^. statusUser . userScreenName
+                                  , ": "
+                                  , status ^. statusText
+                                  ]
diff --git a/sample/userstream.hs b/sample/userstream.hs
new file mode 100644
--- /dev/null
+++ b/sample/userstream.hs
@@ -0,0 +1,82 @@
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE RecordWildCards #-}
+{-# LANGUAGE PatternGuards #-}
+
+import qualified Data.Conduit as C
+import qualified Data.Conduit.List as CL
+import qualified Data.Text.IO as T
+import qualified Data.Text as T
+import System.Process
+import Control.Monad
+import Control.Monad.IO.Class
+import Control.Applicative
+import System.FilePath
+import System.Directory
+import Data.Conduit
+import qualified Data.Conduit.Binary as CB
+import Network.HTTP.Conduit
+
+import Web.Twitter.Conduit
+import Common
+import Control.Lens
+
+ensureDirectoryExist :: FilePath -> IO FilePath
+ensureDirectoryExist dir = do
+    createDirectoryIfMissing True dir
+    return dir
+
+confdir :: IO FilePath
+confdir = fmap (</> ".twitter-conduit") getHomeDirectory >>= ensureDirectoryExist
+
+iconPath :: IO FilePath
+iconPath = (</> "icons") <$> confdir >>= ensureDirectoryExist
+
+main :: IO ()
+main = runTwitterFromEnv' $ do
+    src <- stream userstream
+    src C.$$+- CL.mapM_ (^! act (liftIO . printTL))
+
+showStatus :: AsStatus s => s -> T.Text
+showStatus s = T.concat [ s ^. user . userScreenName
+                        , ":"
+                        , s ^. text
+                        ]
+
+printTL :: StreamingAPI -> IO ()
+printTL (SStatus s) = T.putStrLn . showStatus $ s
+printTL (SRetweetedStatus s) = T.putStrLn $ T.concat [ s ^. user . userScreenName
+                                                     , ": RT @"
+                                                     , showStatus (s ^. rsRetweetedStatus)
+                                                     ]
+printTL (SEvent event)
+    | (event^.evEvent) == "favorite" || (event^.evEvent) == "unfavorite",
+      Just (ETStatus st) <- (event ^. evTargetObject) = do
+          let (fromUser, fromIcon) = evUserInfo (event^.evSource)
+              (toUser, _toIcon) = evUserInfo (event^.evTarget)
+              evUserInfo (ETUser u) = (u ^. userScreenName, u ^. userProfileImageURL)
+              evUserInfo _ = ("", Nothing)
+              header = T.concat [ event ^. evEvent, "[", fromUser, " -> ", toUser, "]"]
+          T.putStrLn $ T.concat [ header, " :: ", showStatus st ]
+          icon <- case fromIcon of
+              Just iconUrl -> Just <$> fetchIcon (T.unpack fromUser) (T.unpack iconUrl)
+              Nothing -> return Nothing
+          notifySend header (showStatus st) icon
+printTL s = print s
+
+notifySend :: T.Text -> T.Text -> Maybe FilePath -> IO ()
+notifySend header content icon = do
+    let ic = maybe [] (\i -> ["-i", i]) icon
+    void $ rawSystem "notify-send" $ [T.unpack header, T.unpack content] ++ ic
+
+fetchIcon :: String -- ^ screen name
+          -> String -- ^ icon url
+          -> IO String
+fetchIcon sn url = do
+    ipath <- iconPath
+    let fname = ipath </> sn ++ "__" ++ takeFileName url
+    exists <- doesFileExist fname
+    unless exists $ withManager $ \mgr -> do
+        req <- liftIO $ parseUrl url
+        body <- http req mgr
+        responseBody body $$+- CB.sinkFile fname
+    return fname
diff --git a/tests/doctests.hs b/tests/doctests.hs
new file mode 100644
--- /dev/null
+++ b/tests/doctests.hs
@@ -0,0 +1,28 @@
+module Main where
+
+import Test.DocTest
+import System.Directory
+import System.FilePath
+import Data.List
+import Control.Monad
+import Control.Applicative
+
+main = do
+  sources <- findSources "Web"
+  doctest $ args ++ sources
+  where
+    args = [ "-i."
+           , "-idist/build/autogen"
+           , "-optP-include"
+           , "-optPdist/build/autogen/cabal_macros.h"
+           ]
+
+findSources :: FilePath -> IO [FilePath]
+findSources dir = filter (isSuffixOf ".hs") <$> go dir
+  where
+    go dir = do
+      (dirs, files) <- listFiles dir
+      (files ++) . concat <$> mapM go dirs
+    listFiles dir = do
+      entries <- map (dir </>) . filter (`notElem` [".", ".."]) <$> getDirectoryContents dir
+      (,) <$> filterM doesDirectoryExist entries <*> filterM doesFileExist entries
diff --git a/tests/hlint.hs b/tests/hlint.hs
new file mode 100644
--- /dev/null
+++ b/tests/hlint.hs
@@ -0,0 +1,12 @@
+module Main where
+
+import Control.Monad
+import Language.Haskell.HLint
+import System.Environment
+import System.Exit
+
+main :: IO ()
+main = do
+  args <- getArgs
+  hints <- hlint $ ["Web", "--cpp-define=HLINT", "--cpp-ansi"] ++ args
+  unless (null hints) exitFailure
diff --git a/twitter-conduit.cabal b/twitter-conduit.cabal
new file mode 100644
--- /dev/null
+++ b/twitter-conduit.cabal
@@ -0,0 +1,194 @@
+name:              twitter-conduit
+version:           0.0.1
+license:           BSD3
+license-file:      LICENSE
+author:            HATTORI Hiroki, Hideyuki Tanaka, Takahiro HIMURA
+maintainer:        Takahiro HIMURA <taka@himura.jp>
+synopsis:          Twitter API package with conduit interface and Streaming API support.
+category:          Web, Conduit
+stability:         Experimental
+cabal-version:     >= 1.8
+build-type:        Simple
+homepage:          https://github.com/himura/twitter-conduit
+
+description:
+  This package provides bindings to Twitter's APIs (see <https://dev.twitter.com/>).
+  .
+  This package uses http-conduit package for access Twitter API (see <http://hackage.haskell.org/package/http-conduit>).
+  This package also depends to twitter-types package (see <http://hackage.haskell.org/package/twitter-types>).
+  .
+  You can find basic examples in the <https://github.com/himura/twitter-conduit/tree/master/sample> directory.
+  .
+  This package is under development. If you find something that has not been implemented yet, please send a pull request or open an issue on GitHub.
+
+source-repository head
+  type: git
+  location: git://github.com/himura/twitter-conduit.git
+
+flag build-samples
+  description: build samples
+  default: False
+
+library
+  ghc-options: -Wall
+
+  build-depends:
+      base >= 4 && < 5
+    , transformers >= 0.2.2
+    , transformers-base
+    , template-haskell
+    , lifted-base >= 0.1
+    , monad-control >= 0.3
+    , lens >= 4.0
+    , authenticate-oauth >= 1.3
+    , resourcet >= 0.4.3
+    , conduit >= 1.0
+    , failure >= 0.2
+    , monad-logger
+    , shakespeare-text
+    , http-types
+    , http-conduit >= 2.0
+    , http-client-multipart
+    , aeson >= 0.7
+    , attoparsec >= 0.10
+    , attoparsec-conduit >= 1.0
+    , data-default >= 0.3
+    , bytestring >= 0.9
+    , text >= 0.11
+    , containers
+    , time
+    , twitter-types >= 0.2
+
+  exposed-modules:
+    Web.Twitter.Conduit
+    Web.Twitter.Conduit.Base
+    Web.Twitter.Conduit.Cursor
+    Web.Twitter.Conduit.Api
+    Web.Twitter.Conduit.Error
+    Web.Twitter.Conduit.Monad
+    Web.Twitter.Conduit.Stream
+    Web.Twitter.Conduit.Status
+    Web.Twitter.Conduit.Request
+    Web.Twitter.Conduit.Parameters
+    Web.Twitter.Conduit.Parameters.Internal
+    Web.Twitter.Conduit.Parameters.TH
+
+  other-modules:
+
+test-suite hlint
+  type: exitcode-stdio-1.0
+  main-is: hlint.hs
+  hs-source-dirs: tests
+
+  build-depends:
+      base
+    , hlint >= 1.7
+
+test-suite doctests
+  type: exitcode-stdio-1.0
+  main-is: doctests.hs
+  hs-source-dirs: tests
+
+  build-depends:
+      base
+    , filepath
+    , directory
+    , doctest
+
+executable simple
+  main-is: simple.hs
+  hs-source-dirs: sample/
+
+  if !flag(build-samples)
+    buildable: False
+  else
+    build-depends:
+        base >= 4.0 && < 5
+      , transformers-base
+      , transformers
+      , monad-control
+      , lens
+      , bytestring
+      , text
+      , data-default
+      , resourcet
+      , conduit
+      , http-conduit
+      , monad-logger
+      , authenticate-oauth
+      , twitter-conduit
+
+executable userstream
+  main-is: userstream.hs
+  hs-source-dirs: sample/
+
+  if !flag(build-samples)
+    buildable: False
+  else
+    build-depends:
+        base >= 4.0 && < 5
+      , containers
+      , transformers-base
+      , transformers
+      , monad-control
+      , bytestring
+      , text
+      , filepath
+      , directory
+      , network
+      , process
+      , case-insensitive
+      , lens
+      , aeson
+      , data-default
+      , resourcet
+      , conduit
+      , http-conduit
+      , monad-logger
+      , authenticate-oauth
+      , twitter-conduit
+
+executable oauth_callback
+  main-is: oauth_callback.hs
+  hs-source-dirs: sample/
+
+  if !flag(build-samples)
+    buildable: False
+  else
+    build-depends:
+        base >= 4.0 && < 5
+      , containers
+      , transformers-base
+      , transformers
+      , monad-control
+      , bytestring
+      , text
+      , resourcet
+      , conduit
+      , http-types
+      , http-conduit
+      , authenticate-oauth
+      , twitter-conduit
+      , scotty >= 0.7
+
+executable oauth_pin
+  main-is: oauth_pin.hs
+  hs-source-dirs: sample/
+
+  if !flag(build-samples)
+    buildable: False
+  else
+    build-depends:
+        base >= 4.0 && < 5
+      , containers
+      , transformers-base
+      , transformers
+      , monad-control
+      , bytestring
+      , text
+      , resourcet
+      , conduit
+      , http-types
+      , http-conduit
+      , authenticate-oauth
+      , twitter-conduit
