diff --git a/LICENSE.md b/LICENSE.md
new file mode 100644
--- /dev/null
+++ b/LICENSE.md
@@ -0,0 +1,30 @@
+Copyright Greg Hale (c) 2016
+
+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.
+
+    * Neither the name of Greg Hale nor the names of other
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+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,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/exec/API.hs b/exec/API.hs
new file mode 100644
--- /dev/null
+++ b/exec/API.hs
@@ -0,0 +1,69 @@
+{-# LANGUAGE DataKinds         #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE TypeOperators     #-}
+
+module API where
+
+import           Data.Aeson
+import           Data.Aeson.Types (typeMismatch)
+import           Data.Text        (Text)
+import           Servant.API
+
+newtype Question = Question { unQuestion :: Text } deriving (Show)
+
+instance ToJSON Question where
+  toJSON (Question txt) = object ["question" .= txt]
+
+instance FromJSON Question where
+  parseJSON (Object v) = Question <$> v .: "question"
+  parseJSON x          = typeMismatch "Couldn't find key 'question'" x
+
+newtype Answer = Answer { unAnswer :: Text } deriving (Show)
+
+instance ToJSON Answer where
+  toJSON (Answer txt) = object ["answer" .= txt]
+
+instance FromJSON Answer where
+  parseJSON (Object v) = Answer <$> v .: "answer"
+  parseJSON x          = typeMismatch "Couldn't find key 'answer'" x
+
+
+-- | API spec for server, client, and docs
+type API = "getunit" :> Get '[JSON] ()
+      :<|> "getint"  :> Get '[JSON] Int
+      :<|> "sayhi"   :> QueryParam  "username" Text
+                     :> QueryParams "greetings" Text
+                     :> QueryFlag   "gusto"
+                     :> Get '[JSON] Text
+      :<|> "double" :> ReqBody '[JSON] Double
+                    :> Post '[JSON] Double
+      :<|> "a" :> "b" :> QueryFlag "gusto" :> Get '[JSON] Text
+      :<|> "qna" :> ReqBody '[JSON] Question
+                 :> Post '[JSON] Answer
+      :<|> "secret" :> BasicAuth "realm" () :> Get '[JSON] Int
+      :<|> Raw
+
+type GET = Get '[JSON] ()
+
+-- Imported the comprehensive API example for testing.
+-- https://github.com/haskell-servant/servant/blob/master/servant/src/Servant/API/Internal/Test/ComprehensiveAPI.hs
+type ComprehensiveAPI =
+  GET :<|>
+  Get '[JSON] Int :<|>
+  Capture "foo" Int :> GET :<|>
+  Header "foo" Int :> GET :<|>
+  HttpVersion :> GET :<|>
+  IsSecure :> GET :<|>
+  QueryParam "foo" Int :> GET :<|>
+  QueryParams "foo" Int :> GET :<|>
+  QueryFlag "foo" :> GET :<|>
+-- Raw :<|>
+  RemoteHost :> GET :<|>
+  ReqBody '[JSON] Int :> GET :<|>
+  Get '[JSON] (Headers '[Header "foo" Int] ()) :<|>
+  "foo" :> GET :<|>
+  Vault :> GET :<|>
+  Verb 'POST 204 '[JSON] () :<|>
+  Verb 'POST 204 '[JSON] Int
+-- This one isn't in scope
+--  :<|> WithNamedContext "foo" '[] GET
diff --git a/exec/Example.hs b/exec/Example.hs
new file mode 100644
--- /dev/null
+++ b/exec/Example.hs
@@ -0,0 +1,218 @@
+{-# LANGUAGE DataKinds           #-}
+{-# LANGUAGE FlexibleContexts    #-}
+{-# LANGUAGE GADTs               #-}
+{-# LANGUAGE OverloadedStrings   #-}
+{-# LANGUAGE RankNTypes          #-}
+{-# LANGUAGE RecursiveDo         #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+
+module Main where
+
+------------------------------------------------------------------------------
+import Data.Bool
+import Data.Maybe
+import Control.Monad.Fix (MonadFix)
+import Data.Monoid (First(..), (<>))
+import Data.Text (Text)
+import qualified Data.Text as T
+import qualified Data.Text.Encoding as T
+import GHC.TypeLits
+import Servant.API
+import API
+import Data.Proxy
+import Text.Read (readMaybe)
+import Reflex.Dom hiding (run)
+------------------------------------------------------------------------------
+import Servant.Reflex
+import Servant.Reflex.Multi
+
+
+api :: Proxy API
+api = Proxy
+
+main :: IO ()
+main = mainWidget $ do
+    divClass "example-base" run
+    divClass "example-multi" runMulti
+
+
+runMulti :: forall t m. (SupportsServantReflex t m,
+                        DomBuilder t m,
+                        DomBuilderSpace m ~ GhcjsDomSpace,
+                        MonadFix m,
+                        PostBuild t m,
+                        MonadHold t m) => m ()
+runMulti = do
+    url <- baseUrlWidget
+    el "br" blank
+    let (_ :<|> _ :<|> sayHi :<|> dbl :<|> _ :<|> _ :<|> _ :<|> _ ) =
+            clientA api (Proxy :: Proxy m) (Proxy :: Proxy []) (Proxy :: Proxy Int) url
+
+    num :: Dynamic t (Either Text Double) <- fmap (note "No read" . readMaybe . T.unpack) . value <$> textInput def
+    num2 :: Dynamic t (Either Text Double) <-  fmap (note "No read" . readMaybe . T.unpack) . value <$> textInput def
+
+    b <- button "Run dbl multi"
+    reqCount :: Dynamic t Int <- count b
+    r <- dbl ((\x y -> [x,y]) <$> num <*> num2) (tag (current reqCount) b)
+    dynText =<< holdDyn "Waiting" (T.pack . show .  fmap reqSuccess <$> r)
+
+    lastInd <- holdDyn [] $ fmap reqTag <$> r
+    display lastInd
+
+    divClass "demo-group" $ do
+        nms <- fmap (fmap T.words . value) $ divClass "" $ do
+            text "Names"
+            textInput def
+        grts <- fmap (fmap T.words . value) $ divClass "" $ do
+            text "Greetings"
+            textInput def
+        gust <- fmap (value) $ divClass "gusto-input" $ checkbox False def
+        b <- button "Go"
+        r' <- sayHi (fmap QParamSome <$> nms) (fmap (:[]) $ grts)
+                    (constDyn [True, False]) (1 <$ b)
+
+        dynText =<< holdDyn "Waiting" (T.pack . show . catMaybes .
+                                       fmap reqSuccess  <$> r')
+
+
+    return ()
+
+run :: forall t m. (SupportsServantReflex t m,
+                    DomBuilder t m,
+                    DomBuilderSpace m ~ GhcjsDomSpace,
+                    MonadFix m,
+                    PostBuild t m,
+                    MonadHold t m) => m ()
+run = mdo
+
+  reqCount <- count $ leftmost
+              [() <$ unitBtn, () <$ intBtn, () <$ sayHiClicks, () <$ dblBtn, () <$ mpGo]
+  -- Allow user to choose the url target for the request
+  -- (alternatively we could just `let url = constDyn (BasePath "/")`)
+  url <- baseUrlWidget
+  el "br" (return ())
+  dynText $ showBaseUrl <$> url
+
+  el "br" (return ())
+
+  -- Name the computed API client functions
+  let tweakRequest = ClientOptions $ \r -> do
+          return $ r & withCredentials .~ True
+  let (getUnit :<|> getInt :<|> sayhi :<|> dbl
+       :<|> multi :<|> qna :<|> secret :<|> doRaw) =
+        clientWithOpts api (Proxy :: Proxy m) (Proxy :: Proxy Int) url tweakRequest
+
+      c2 = client (Proxy :: Proxy ComprehensiveAPI) (Proxy :: Proxy m) (Proxy :: Proxy ()) url -- Just make sure this compiles for now
+
+  (unitBtn, intBtn) <- elClass "div" "demo-group" $ do
+    unitBtn  <- divClass "unit-button" $ button "Get unit"
+    intBtn   <- divClass "int-button"  $ button "Get int"
+
+    unitResponse <- getUnit $ tag (current reqCount) unitBtn
+    intResponse :: Event t (ReqResult Int Int) <- getInt $ tag (current reqCount) intBtn
+
+    score <- foldDyn (+) 0 (fmapMaybe reqSuccess (intResponse))
+
+    r <- holdDyn "Waiting" $ fmap showXhrResponse $
+         leftmost [fmapMaybe response (unitResponse)
+                  ,fmapMaybe response (intResponse)
+                  ]
+    divClass "unit-int-response" $ el "p" $ dynText r >> el "br" (return ()) >> text "Total: " >> display score
+    return (unitBtn, intBtn)
+
+  sayHiClicks <- elClass "div" "demo-group" $ do
+
+    text "Name"
+    el "br" $ return ()
+    inp :: Dynamic t Text <- fmap value $ divClass "name-input" $ (textInput def)
+    let checkedName = fmap (\i -> bool (QParamSome i) (QParamInvalid "Need a name") (T.null i)) inp
+    el "br" $ return ()
+
+    text "Greetings (space-separated)"
+    el "br" $ return ()
+    greetings <- fmap (fmap T.words . value) $
+      divClass "greetings-input" $ (textInput def)
+
+    el "br" $ return ()
+
+    gusto <- fmap value $ divClass "gusto-input" $ checkbox False def
+
+    el "br" $ return ()
+    sayHiClicks :: Event t () <- divClass "hi-button" $ button "Say hi"
+    let triggers = leftmost [sayHiClicks, () <$ updated inp]
+
+    resp <- sayhi checkedName greetings gusto (tag (current reqCount) triggers)
+    divClass "greeting-response" $ dynText =<<
+      holdDyn "No hi yet" (leftmost [ fmapMaybe reqSuccess (resp)
+                                    , fmapMaybe reqFailure (resp)])
+    return sayHiClicks
+
+  dblBtn <- elClass "div" "demo-group" $ do
+    text "A Double to double"
+    el "br" $ return ()
+    dblinp <- fmap value $ divClass "double-input" $ textInput def
+    (dblBtn) <- divClass "double-button" $ button "Double it"
+    dblResp <- dbl (fmap (note "read failure" . readMaybe . T.unpack) $
+                          dblinp) (tag (current reqCount) dblBtn)
+    divClass "double-errors" $ dynText =<<
+      holdDyn "(no errors)" (fmapMaybe reqFailure (dblResp))
+    el "br" (return ())
+    divClass "double-result" $ el "p" $ dynText =<<
+      holdDyn "No number yet" (fmap tShow $
+                               fmapMaybe reqSuccess (dblResp))
+    return dblBtn
+
+  mpGo <- elClass "div" "demo-group" $ do
+    text "Multi-part path"
+    b <- value <$> checkbox False def
+    mpGo <- button "Test"
+    multiResp <- multi b (tag (current reqCount) mpGo)
+    dynText =<< holdDyn "No res yet" (fmap tShow $
+                                      fmapMaybe reqSuccess $
+                                      (multiResp))
+    return mpGo
+
+  return ()
+
+  el "br" $ return ()
+
+  elClass "div" "demo-group" $ do
+    text "JSON Unicode encoding test"
+    txt <- value <$> textInput def
+    ev  <- fmap (1 <$) $ button "Question"
+    let dQ = Right . Question <$> traceDyn "will send: " txt
+    rr  <- qna dQ ev
+    el "p" $
+      dynText =<< holdDyn "No Answer" (unAnswer <$> fmapMaybe reqSuccess rr)
+
+  divClass "demo-group" $ do
+    un <- fmap value $ text "Username"    >> textArea def
+    pw <- fmap value $ text "Unhidden PW" >> textArea def
+    let ba :: Dynamic t (BasicAuthData ) = BasicAuthData
+                                           <$> fmap T.encodeUtf8 un
+                                           <*> fmap T.encodeUtf8 pw
+    b <- button "Get secret"
+    r  <- secret (Just <$> ba) (0 <$ b)
+    res <- holdDyn Nothing (reqSuccess <$> r)
+    display res
+
+
+showXhrResponse :: XhrResponse -> Text
+showXhrResponse (XhrResponse stat stattxt rbmay rtmay respHeaders) =
+  T.unlines ["stat: " <> tShow stat
+            ,"stattxt: " <> tShow stattxt
+            ,"resp: " <> maybe "" showRB rbmay
+            ,"rtext: " <> tShow rtmay
+            ,"rHeaders: " <> tShow respHeaders]
+
+tShow :: Show a => a -> Text
+tShow = T.pack . show
+
+showRB :: XhrResponseBody -> Text
+showRB (XhrResponseBody_Default t) = tShow t
+showRB (XhrResponseBody_Text t) = tShow t
+showRB (XhrResponseBody_Blob t) = "<Blob>"
+showRB (XhrResponseBody_ArrayBuffer t) = tShow t
+
+note :: e -> Maybe a -> Either e a
+note e = maybe (Left e) Right
diff --git a/servant-reflex.cabal b/servant-reflex.cabal
new file mode 100644
--- /dev/null
+++ b/servant-reflex.cabal
@@ -0,0 +1,61 @@
+Name: servant-reflex
+Version: 0.3.4
+Synopsis: servant API generator for reflex apps
+Description: Generate reflex-compatible client functions from servant API descriptions
+License: BSD3
+License-file: LICENSE.md
+Author: Greg Hale, Doug Beardsley
+Maintainer: imalsogreg@gmail.com
+Stability: Experimental
+Category: Web
+Build-type: Simple
+Cabal-version: >=1.10
+
+Flag Example
+  description: Enable example
+  default: False
+
+library
+  exposed-modules:
+    Servant.Common.BaseUrl
+    Servant.Common.Req
+    Servant.Reflex
+    Servant.Reflex.Multi
+
+  hs-source-dirs: src
+  build-depends:
+    base                >= 4.8  && < 5,
+    bytestring          >= 0.10 && < 0.11,
+    case-insensitive    >= 1.2.0.4 && < 1.3,
+    containers          >= 0.5.6   && < 0.6,
+    data-default        >= 0.5  && < 0.8,
+    exceptions          >= 0.8  && < 0.11,
+    ghcjs-dom           >= 0.2  && < 0.10,
+    http-api-data       >= 0.3.6 && < 0.4,
+    http-media          >= 0.6  && < 0.8,
+    jsaddle             >= 0.8  && < 0.10,
+    mtl                 >= 2.2.1 && < 2.3,
+    network-uri         >= 2.6  && < 2.7,
+    reflex              >= 0.5  && < 0.6,
+    reflex-dom-core     == 0.4  && < 0.5,
+    safe                >= 0.3.9 && < 0.4,
+    servant             >= 0.8  && < 0.15,
+    servant-auth        >= 0.2.1 && < 0.4,
+    string-conversions  >= 0.4  && < 0.5,
+    text                >= 1.2  && < 1.3,
+    transformers        >= 0.4  && < 0.6
+
+  ghc-options: -Wall -fwarn-tabs -funbox-strict-fields
+
+  default-language: Haskell2010
+
+executable example
+  if flag(Example)
+    buildable: True
+  else
+    buildable: False
+  build-depends: aeson, reflex, servant-reflex, base, scientific, servant, reflex-dom, text
+  default-language: Haskell2010
+  main-is: Example.hs
+  other-modules: API
+  hs-source-dirs: exec
diff --git a/src/Servant/Common/BaseUrl.hs b/src/Servant/Common/BaseUrl.hs
new file mode 100644
--- /dev/null
+++ b/src/Servant/Common/BaseUrl.hs
@@ -0,0 +1,99 @@
+{-# LANGUAGE ConstraintKinds     #-}
+{-# LANGUAGE DeriveDataTypeable  #-}
+{-# LANGUAGE DeriveGeneric       #-}
+{-# LANGUAGE FlexibleContexts    #-}
+{-# LANGUAGE GADTs               #-}
+{-# LANGUAGE OverloadedStrings   #-}
+{-# LANGUAGE ViewPatterns        #-}
+{-# LANGUAGE RankNTypes          #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+module Servant.Common.BaseUrl (
+  -- * types
+    BaseUrl (..)
+  , Scheme (..)
+  -- * functions
+  , baseUrlWidget
+  , showBaseUrl
+
+  -- * constraints
+  , SupportsServantReflex
+) where
+
+import           Control.Monad (join)
+-- import           Control.Monad.IO.Class (MonadIO)
+import           Control.Monad.Fix (MonadFix)
+import           Data.Monoid ((<>))
+import           Data.Text (Text)
+import qualified Data.Text as T
+import           GHC.Generics
+import           Language.Javascript.JSaddle.Monad (MonadJSM)
+import           Reflex
+import           Reflex.Dom.Core
+import           Text.Read
+
+
+type SupportsServantReflex t m = (Reflex t, TriggerEvent t m, PerformEvent t m, HasWebView (Performable m), MonadJSM (Performable m))
+
+-- | URI scheme to use
+data Scheme =
+    Http  -- ^ http://
+  | Https -- ^ https://
+  deriving (Show, Read, Eq, Ord, Generic)
+
+-- | Simple data type to represent the target of HTTP requests
+--   for servant's automatically-generated clients.
+data BaseUrl = BaseFullUrl Scheme Text Int Text
+             | BasePath Text
+  deriving (Ord, Read, Show, Generic)
+
+
+instance Eq BaseUrl where
+    BasePath s == BasePath s' = s == s'
+    BaseFullUrl a b c path == BaseFullUrl a' b' c' path'
+        = a == a' && b == b' && c == c' && s path == s path'
+        where s x = if T.isPrefixOf "/" x then T.tail x else x
+    _ == _ = False
+
+showBaseUrl :: BaseUrl -> Text
+showBaseUrl (BasePath s) = s
+showBaseUrl (BaseFullUrl urlscheme host port path) =
+  schemeString <> "//" <> host <> (portString </> path)
+    where
+      a </> b = if "/" `T.isPrefixOf` b || T.null b then a <> b else a <> "/" <> b
+      schemeString = case urlscheme of
+        Http  -> "http:"
+        Https -> "https:"
+      portString = case (urlscheme, port) of
+        (Http, 80) -> ""
+        (Https, 443) -> ""
+        _ -> ":" <> T.pack (show port)
+
+baseUrlWidget :: forall t m .(SupportsServantReflex t m,
+                              DomBuilderSpace m ~ GhcjsDomSpace,
+                              MonadFix m,
+                              PostBuild t m,
+                              MonadHold t m,
+                              DomBuilder t m)
+              => m (Dynamic t BaseUrl)
+baseUrlWidget = elClass "div" "base-url" $ do
+  urlWidget <- dropdown (0 :: Int) (constDyn $ 0 =: "BasePath" <> 1 =: "BaseUrlFull") def
+  let bUrlWidget = ffor (value urlWidget) $ \i -> case i of
+        0 -> pathWidget
+        1 -> fullUrlWidget
+        _ -> error "Surprising value"
+  join <$> widgetHold pathWidget (updated bUrlWidget)
+  where pathWidget :: m (Dynamic t BaseUrl)
+        pathWidget = do
+          text "Url base path"
+          t <- textInput (def {_textInputConfig_attributes =
+                          constDyn ("placeholder" =: "/a/b")})
+          return $ BasePath <$> value t
+        fullUrlWidget :: m (Dynamic t BaseUrl)
+        fullUrlWidget = do
+          schm <- dropdown Https (constDyn $ Https =: "https" <> Http =: "http") def
+          srv  <- textInput def {_textInputConfig_attributes = constDyn $ "placeholder" =: "example.com"}
+          text ":"
+          prt  <- textInput def { _textInputConfig_attributes = constDyn $ "placeholder" =: "80"}
+          port :: Dynamic t Int <- holdDyn 80 (fmapMaybe (readMaybe . T.unpack) $ updated (value prt))
+          path <- textInput def { _textInputConfig_attributes = constDyn $ "placeholder" =: "a/b" }
+          return $ BaseFullUrl <$> value schm <*> value srv <*> port <*> value path
diff --git a/src/Servant/Common/Req.hs b/src/Servant/Common/Req.hs
new file mode 100644
--- /dev/null
+++ b/src/Servant/Common/Req.hs
@@ -0,0 +1,430 @@
+{-# LANGUAGE CPP                 #-}
+{-# LANGUAGE DeriveFunctor       #-}
+{-# LANGUAGE FlexibleContexts    #-}
+{-# LANGUAGE GADTs               #-}
+{-# LANGUAGE OverloadedStrings   #-}
+{-# LANGUAGE LambdaCase          #-}
+{-# LANGUAGE RankNTypes          #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE TupleSections       #-}
+
+module Servant.Common.Req where
+
+-------------------------------------------------------------------------------
+import           Control.Applicative        (liftA2, liftA3)
+import           Control.Arrow              ((&&&))
+import           Control.Concurrent
+import           Control.Monad              (join)
+import           Control.Monad.IO.Class     (MonadIO, liftIO)
+import           Data.Bifunctor             (first)
+import qualified Data.ByteString.Builder    as Builder
+import qualified Data.ByteString.Lazy.Char8 as BL
+import qualified Data.Map                   as Map
+import           Data.Maybe                 (catMaybes, fromMaybe)
+import           Data.Functor.Compose
+import           Data.Monoid                ((<>))
+import           Data.Proxy                 (Proxy(..))
+import           Data.Text                  (Text)
+import qualified Data.Text                  as T
+import qualified Data.Text.Encoding         as TE
+import           Data.Traversable           (forM)
+import           Language.Javascript.JSaddle.Monad (JSM, MonadJSM, liftJSM)
+import qualified Network.URI                as N
+import           Reflex.Dom.Core                 hiding (tag)
+import           Servant.Common.BaseUrl     (BaseUrl, showBaseUrl,
+                                             SupportsServantReflex)
+import           Servant.API.ContentTypes   (MimeUnrender(..), NoContent(..))
+import           Web.HttpApiData            (ToHttpApiData(..))
+-------------------------------------------------------------------------------
+import           Servant.API.BasicAuth
+
+
+------------------------------------------------------------------------------
+-- | The result of a request event
+data ReqResult tag a
+    = ResponseSuccess tag a XhrResponse
+      -- ^ The succesfully decoded response from a request tagged with 'tag'
+    | ResponseFailure tag Text XhrResponse
+      -- ^ The failure response, which may have failed decoding or had
+      --   a non-successful response code
+    | RequestFailure  tag Text
+      -- ^ A failure to construct the request tagged with 'tag' at trigger time
+  deriving (Functor)
+
+data ClientOptions = ClientOptions
+    { optsRequestFixup :: forall a. Show a => XhrRequest a -> JSM (XhrRequest a)
+      -- ^ Aribtrarily modify requests just before they are sent.
+      -- Warning: This escape hatch opens the possibility for your
+      -- requests to diverge from what the server expects, when the
+      -- server is also derived from a servant API
+    }
+
+defaultClientOptions :: ClientOptions
+defaultClientOptions = ClientOptions { optsRequestFixup = return }
+
+-- withCredentials :: Lens' (XhrRequest a) Bool
+withCredentials :: (Show a, Functor f) => (Bool -> f Bool) -> XhrRequest a -> f (XhrRequest a)
+withCredentials inj r@(XhrRequest _ _ cfg) =
+    let cfg' = (\b -> cfg { _xhrRequestConfig_withCredentials = b}) <$>
+               inj (_xhrRequestConfig_withCredentials cfg)
+    in (\c' -> r {_xhrRequest_config = c' }) <$> cfg'
+
+------------------------------------------------------------------------------
+-- | Simple filter/accessor for successful responses, when you want to
+-- ignore the error case. For example:
+-- >> goodResponses <- fmapMaybe reqSuccess <$> clientFun triggers
+reqSuccess :: ReqResult tag a -> Maybe a
+reqSuccess (ResponseSuccess _ x _) = Just x
+reqSuccess _                       = Nothing
+
+
+------------------------------------------------------------------------------
+-- | Simple filter/accessor like 'reqSuccess', but keeping the request tag
+reqSuccess' :: ReqResult tag a -> Maybe (tag,a)
+reqSuccess' (ResponseSuccess tag x _) = Just (tag,x)
+reqSuccess' _                         = Nothing
+
+
+------------------------------------------------------------------------------
+-- | Simple filter/accessor for any failure case
+reqFailure :: ReqResult tag a -> Maybe Text
+reqFailure (ResponseFailure _ s _) = Just s
+reqFailure (RequestFailure  _ s)   = Just s
+reqFailure _                       = Nothing
+
+------------------------------------------------------------------------------
+-- | Simple filter/accessor like 'reqFailure', but keeping the request tag
+reqFailure' :: ReqResult tag a -> Maybe (tag,Text)
+reqFailure' (ResponseFailure tag s _) = Just (tag,s)
+reqFailure' (RequestFailure  tag s)   = Just (tag,s)
+reqFailure' _                         = Nothing
+
+
+------------------------------------------------------------------------------
+-- | Simple filter/accessor for the raw XHR response
+response :: ReqResult tag a -> Maybe XhrResponse
+response (ResponseSuccess _ _ x) = Just x
+response (ResponseFailure _ _ x) = Just x
+response _                       = Nothing
+
+------------------------------------------------------------------------------
+-- | Retrieve response tag
+reqTag :: ReqResult tag a -> tag
+reqTag (ResponseSuccess tag _ _) = tag
+reqTag (ResponseFailure tag _ _) = tag
+reqTag (RequestFailure  tag _  ) = tag
+
+-------------------------------------------------------------------------------
+-- | You must wrap the parameter of a QueryParam endpoint with 'QParam' to
+-- indicate whether the parameter is valid and present, validly absent, or
+-- invalid
+data QParam a = QParamSome a
+              -- ^ A valid query parameter
+              | QNone
+              -- ^ Indication that the parameter is intentionally absent (the request is valid)
+              | QParamInvalid Text
+              -- ^ Indication that your validation failed (the request isn't valid)
+
+
+qParamToQueryPart :: ToHttpApiData a => QParam a -> Either Text (Maybe Text)
+qParamToQueryPart (QParamSome a)    = Right (Just $ toQueryParam a)
+qParamToQueryPart QNone             = Right Nothing
+qParamToQueryPart (QParamInvalid e) = Left e
+
+
+data QueryPart t = QueryPartParam  (Dynamic t (Either Text (Maybe Text)))
+                 | QueryPartParams (Dynamic t [Text])
+                 | QueryPartFlag   (Dynamic t Bool)
+
+
+-------------------------------------------------------------------------------
+-- The data structure used to build up request information while traversing
+-- the shape of a servant API
+data Req t = Req
+  { reqMethod    :: Text
+  , reqPathParts :: [Dynamic t (Either Text Text)]
+  , qParams      :: [(Text, QueryPart t)]
+  , reqBody      :: Maybe (Dynamic t (Either Text (BL.ByteString, Text)))
+  , headers      :: [(Text, Dynamic t (Either Text Text))]
+  , respHeaders  :: XhrResponseHeaders
+  , authData     :: Maybe (Dynamic t (Maybe BasicAuthData))
+  }
+
+defReq :: Req t
+defReq = Req "GET" [] [] Nothing [] def Nothing
+
+prependToPathParts :: Dynamic t (Either Text Text) -> Req t -> Req t
+prependToPathParts p req =
+  req { reqPathParts = p : reqPathParts req }
+
+addHeader :: (ToHttpApiData a, Reflex t) => Text -> Dynamic t (Either Text a) -> Req t -> Req t
+addHeader name val req = req { headers = (name, (fmap . fmap) (TE.decodeUtf8 . toHeader) val) : headers req }
+
+
+reqToReflexRequest
+    :: forall t. Reflex t
+    => Text
+    -> Dynamic t BaseUrl
+    -> Req t
+    -> Dynamic t (Either Text (XhrRequest XhrPayload))
+reqToReflexRequest reqMeth reqHost req =
+  let t :: Dynamic t [Either Text Text]
+      t = sequence $ reverse $ reqPathParts req
+
+      baseUrl :: Dynamic t (Either Text Text)
+      baseUrl = Right . showBaseUrl <$> reqHost
+
+      urlParts :: Dynamic t (Either Text [Text])
+      urlParts = fmap sequence t
+
+      urlPath :: Dynamic t (Either Text Text)
+      urlPath = (fmap.fmap)
+                (T.intercalate "/" . fmap escape)
+                urlParts
+
+      queryPartString :: (Text, QueryPart t) -> Dynamic t (Maybe (Either Text Text))
+      queryPartString (pName, qp) = case qp of
+        QueryPartParam p -> ffor p $ \case
+          Left e         -> Just (Left e)
+          Right (Just a) -> Just (Right $ pName <> "=" <> escape a)
+          Right Nothing  -> Nothing
+        QueryPartParams ps -> ffor ps $ \pStrings ->
+          if null pStrings
+          then Nothing
+          else Just . Right
+               . T.intercalate "&"
+               $ fmap (\p -> pName <> "=" <> escape p) pStrings
+        QueryPartFlag fl -> ffor fl $ \case
+          True ->  Just $ Right pName
+          False -> Nothing
+
+
+      queryPartStrings :: [Dynamic t (Maybe (Either Text Text))]
+      queryPartStrings = map queryPartString (qParams req)
+      queryPartStrings' = fmap (sequence . catMaybes) $ sequence queryPartStrings :: Dynamic t (Either Text [Text])
+      queryString :: Dynamic t (Either Text Text) =
+        ffor queryPartStrings' $ \qs -> fmap (T.intercalate "&") qs
+      xhrUrl =  (liftA3 . liftA3) (\a p q -> a </> if T.null q then p else p <> "?" <> q)
+          baseUrl urlPath queryString
+        where
+          (</>) :: Text -> Text -> Text
+          x </> y | ("/" `T.isSuffixOf` x) || ("/" `T.isPrefixOf` y) = x <> y
+                  | otherwise = x <> "/" <> y
+
+
+      xhrHeaders :: Dynamic t (Either Text [(Text, Text)])
+      xhrHeaders = (fmap sequence . sequence . fmap f . headers) req
+        where
+          f = \(headerName, dynam) ->
+                fmap (fmap (\rightVal -> (headerName, rightVal))) dynam
+
+      mkConfigBody :: Either Text [(Text,Text)]
+                   -> (Either Text (BL.ByteString, Text))
+                   -> Either Text (XhrRequestConfig XhrPayload)
+      mkConfigBody ehs rb = case (ehs, rb) of
+                  (_, Left e)                     -> Left e
+                  (Left e, _)                     -> Left e
+                  (Right hs, Right (bBytes, bCT)) ->
+                    Right $ XhrRequestConfig
+                      { _xhrRequestConfig_sendData = bytesToPayload bBytes
+                      , _xhrRequestConfig_headers  =
+                        Map.insert "Content-Type" bCT (Map.fromList hs)
+                      , _xhrRequestConfig_user = Nothing
+                      , _xhrRequestConfig_password = Nothing
+                      , _xhrRequestConfig_responseType = Just XhrResponseType_ArrayBuffer
+                      , _xhrRequestConfig_withCredentials = False
+                      , _xhrRequestConfig_responseHeaders = def
+                      }
+
+      xhrOpts :: Dynamic t (Either Text (XhrRequestConfig XhrPayload))
+      xhrOpts = case reqBody req of
+        Nothing    -> ffor xhrHeaders $ \case
+                               Left e -> Left e
+                               Right hs -> Right $ def { _xhrRequestConfig_headers = Map.fromList hs
+                                                       , _xhrRequestConfig_user = Nothing
+                                                       , _xhrRequestConfig_password = Nothing
+                                                       , _xhrRequestConfig_responseType = Just XhrResponseType_ArrayBuffer
+                                                       , _xhrRequestConfig_sendData = ""
+                                                       , _xhrRequestConfig_withCredentials = False
+                                                       }
+        Just rBody -> liftA2 mkConfigBody xhrHeaders rBody
+
+      mkAuth :: Maybe BasicAuthData -> Either Text (XhrRequestConfig x) -> Either Text (XhrRequestConfig x)
+      mkAuth _ (Left e) = Left e
+      mkAuth Nothing r  = r
+      mkAuth (Just (BasicAuthData u p)) (Right config) = Right $ config
+        { _xhrRequestConfig_user     = Just $ TE.decodeUtf8 u
+        , _xhrRequestConfig_password = Just $ TE.decodeUtf8 p}
+
+      addAuth :: Dynamic t (Either Text (XhrRequestConfig x))
+              -> Dynamic t (Either Text (XhrRequestConfig x))
+      addAuth xhr = case authData req of
+        Nothing -> xhr
+        Just auth -> liftA2 mkAuth auth xhr
+
+      xhrReq = (liftA2 . liftA2) (\p opt -> XhrRequest reqMeth p opt) xhrUrl (addAuth xhrOpts)
+
+  in xhrReq
+
+-- * performing requests
+
+displayHttpRequest :: Text -> Text
+displayHttpRequest httpmethod = "HTTP " <> httpmethod <> " request"
+
+-- | This function performs the request
+performRequests :: forall t m f tag.(SupportsServantReflex t m, Traversable f)
+                => Text
+                -> Dynamic t (f (Req t))
+                -> Dynamic t BaseUrl
+                -> ClientOptions
+                -> Event t tag
+                -> m (Event t (tag, f (Either Text XhrResponse)))
+performRequests reqMeth rs reqHost opts trigger = do
+  let xhrReqs =
+          join $ (\(fxhr :: f (Req t)) -> sequence $
+                     reqToReflexRequest reqMeth reqHost <$> fxhr) <$> rs
+
+      -- xhrReqs = fmap snd <$> xhrReqsAndDebugs
+      reqs    = attachPromptlyDynWith
+                (\fxhr t -> Compose (t, fxhr)) xhrReqs trigger
+
+  resps <- performSomeRequestsAsync opts reqs
+  return $ getCompose <$> resps
+
+-- | Issues a collection of requests when the supplied Event fires.
+-- When ALL requests from a given firing complete, the results are
+-- collected and returned via the return Event.
+performSomeRequestsAsync
+    :: (MonadIO (Performable m),
+        MonadJSM (Performable m),
+        HasWebView (Performable m),
+        PerformEvent t m,
+        TriggerEvent t m,
+        Traversable f,
+        IsXhrPayload a,
+        Show a
+       )
+    => ClientOptions
+    -> Event t (f (Either Text (XhrRequest a)))
+    -> m (Event t (f (Either Text XhrResponse)))
+performSomeRequestsAsync opts =
+    performSomeRequestsAsync' opts newXMLHttpRequest . fmap return
+
+
+------------------------------------------------------------------------------
+-- | A modified version or Reflex.Dom.Xhr.performRequestsAsync
+-- that accepts 'f (Either e (XhrRequestb))' events
+performSomeRequestsAsync'
+    :: (MonadJSM (Performable m), PerformEvent t m, TriggerEvent t m, Traversable f, Show b)
+    => ClientOptions
+    -> (XhrRequest b -> (a -> JSM ()) -> Performable m XMLHttpRequest)
+    -> Event t (Performable m (f (Either Text (XhrRequest b)))) -> m (Event t (f (Either Text a)))
+performSomeRequestsAsync' opts newXhr req = performEventAsync $ ffor req $ \hrs cb -> do
+  rs <- hrs
+  resps <- forM rs $ \r -> case r of
+      Left e -> do
+          resp <- liftIO $ newMVar (Left e)
+          return resp
+      Right r' -> do
+          resp <- liftIO newEmptyMVar
+          r'' <- liftJSM $ (optsRequestFixup opts) r'
+          _ <- newXhr r'' $ liftIO . putMVar resp . Right
+          return resp
+  _ <- liftIO $ forkIO $ cb =<< forM resps takeMVar
+  return ()
+
+
+
+type XhrPayload = T.Text
+bytesToPayload :: BL.ByteString -> XhrPayload
+bytesToPayload = TE.decodeUtf8 . BL.toStrict
+
+
+performRequestsCT
+    :: (SupportsServantReflex t m,
+        MimeUnrender ct a, Traversable f)
+    => Proxy ct
+    -> Text
+    -> Dynamic t (f (Req t))
+    -> Dynamic t BaseUrl
+    -> ClientOptions
+    -> Event t tag
+    -> m (Event t (f (ReqResult tag a)))
+performRequestsCT ct reqMeth reqs reqHost opts trigger = do
+  resps <- performRequests reqMeth reqs reqHost opts trigger
+  let decodeResp (Just (XhrResponseBody_ArrayBuffer x)) =
+                     first T.pack .
+                     mimeUnrender ct $
+                     BL.fromStrict x
+      decodeResp _ = Left "No body"
+  return $ fmap
+      (\(t,rs) -> ffor rs $ \r -> case r of
+              Left e  -> RequestFailure t e
+              Right g -> evalResponse (decodeResp . _xhrResponse_response) (t,g)
+      )
+      resps
+
+
+performRequestsNoBody
+    :: (SupportsServantReflex t m,
+        Traversable f)
+    => Text
+    -> Dynamic t (f (Req t))
+    -> Dynamic t BaseUrl
+    -> ClientOptions
+    -> Event t tag
+    -> m (Event t (f (ReqResult tag NoContent)))
+performRequestsNoBody reqMeth reqs reqHost opts trigger = do
+  resps <- performRequests reqMeth reqs reqHost opts trigger
+  let decodeResp = const $ Right NoContent
+  return $ ffor resps $ \(tag,rs) -> ffor rs $ \r -> case r of
+      Left e  -> RequestFailure tag e
+      Right g -> evalResponse decodeResp (tag,g)
+
+
+------------------------------------------------------------------------------
+evalResponse
+    :: (XhrResponse -> Either Text a)
+    -> (tag, XhrResponse)
+    -> ReqResult tag a
+evalResponse decode (tag, xhr) =
+    let status = _xhrResponse_status xhr
+        okStatus = status >= 200 && status < 400
+        errMsg = fromMaybe
+            ("Empty response with error code " <>
+                T.pack (show $ _xhrResponse_status xhr))
+            (_xhrResponse_responseText xhr)
+        respPayld  = if okStatus
+                     then either
+                          (\e -> ResponseFailure tag e xhr)
+                          (\v -> ResponseSuccess tag v xhr)
+                          (decode xhr)
+                     else ResponseFailure tag errMsg xhr
+    in respPayld
+
+------------------------------------------------------------------------------
+-- | Utility for simultaneously accessing/filtering Success and Failure
+-- response 'Event's,
+fanReqResult :: Reflex t => Event t (ReqResult tag a) -> (Event t Text, Event t a)
+fanReqResult = fmapMaybe reqFailure &&& fmapMaybe reqSuccess
+
+------------------------------------------------------------------------------
+-- | Utility for simultaneously accessing/filtering Success and Failure
+-- response 'Event's, but keeping the request tag
+fanReqResult' :: Reflex t => Event t (ReqResult tag a) -> (Event t (tag, Text), Event t (tag, a))
+fanReqResult' = fmapMaybe reqFailure' &&& fmapMaybe reqSuccess'
+
+
+note :: e -> Maybe a -> Either e a
+note e = maybe (Left e) Right
+
+fmapL :: (e -> e') -> Either e a -> Either e' a
+fmapL _ (Right a) = Right a
+fmapL f (Left e)  = Left (f e)
+
+builderToText :: Builder.Builder -> T.Text
+builderToText = TE.decodeUtf8 . BL.toStrict . Builder.toLazyByteString
+
+escape :: T.Text -> T.Text
+escape = T.pack . N.escapeURIString (not . N.isReserved) . T.unpack . TE.decodeUtf8 . BL.toStrict . Builder.toLazyByteString . toEncodedUrlPiece
+
diff --git a/src/Servant/Reflex.hs b/src/Servant/Reflex.hs
new file mode 100644
--- /dev/null
+++ b/src/Servant/Reflex.hs
@@ -0,0 +1,606 @@
+{-# LANGUAGE AllowAmbiguousTypes        #-}
+{-# LANGUAGE CPP                        #-}
+{-# LANGUAGE DataKinds                  #-}
+{-# LANGUAGE FlexibleContexts           #-}
+{-# LANGUAGE FlexibleInstances          #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE InstanceSigs               #-}
+{-# LANGUAGE MultiParamTypeClasses      #-}
+{-# LANGUAGE OverloadedStrings          #-}
+{-# LANGUAGE PolyKinds                  #-}
+{-# LANGUAGE Rank2Types                 #-}
+{-# LANGUAGE ScopedTypeVariables        #-}
+{-# LANGUAGE TupleSections              #-}
+{-# LANGUAGE TypeFamilies               #-}
+{-# LANGUAGE TypeOperators              #-}
+{-# LANGUAGE UndecidableInstances       #-}
+
+#if MIN_VERSION_base(4,9,0)
+{-# OPTIONS_GHC -fno-warn-redundant-constraints #-}
+#endif
+
+-- #include "overlapping-compat.h"
+-- | This module provides 'client' which can automatically generate
+-- querying functions for each endpoint just from the type representing your
+-- API.
+module Servant.Reflex
+  ( client
+  , clientWithOpts
+  , clientWithOptsAndResultHandler
+  , clientWithRoute
+  , clientWithRouteAndResultHandler
+  , BuildHeaderKeysTo(..)
+  , toHeaders
+  , HasClient
+  , Client
+  , module Servant.Common.Req
+  , module Servant.Common.BaseUrl
+  ) where
+
+------------------------------------------------------------------------------
+import           Control.Applicative
+import           Data.Monoid             ((<>))
+import qualified Data.Set                as Set
+import qualified Data.Text.Encoding      as E
+import           Data.CaseInsensitive    (mk)
+import           Data.Functor.Identity
+import           Data.Proxy              (Proxy (..))
+import qualified Data.Map                as Map
+import           Data.Text               (Text)
+import qualified Data.Text               as T
+import           GHC.Exts                (Constraint)
+import           GHC.TypeLits            (KnownSymbol, symbolVal)
+import           Servant.API             ((:<|>)(..),(:>), BasicAuth,
+                                          BasicAuthData, BuildHeadersTo(..),
+                                          Capture, contentType, Header,
+                                          Headers(..), HttpVersion, IsSecure,
+                                          MimeRender(..), MimeUnrender,
+                                          NoContent, QueryFlag, QueryParam,
+                                          QueryParams, Raw, ReflectMethod(..),
+                                          RemoteHost, ReqBody,
+                                          ToHttpApiData(..), Vault, Verb)
+import qualified Servant.Auth            as Auth
+
+import           Reflex.Dom.Core         (Dynamic, Event, Reflex,
+                                          XhrRequest(..),
+                                          XhrResponseHeaders(..),
+                                          XhrResponse(..), attachPromptlyDynWith, constDyn, ffor, fmapMaybe,
+                                          leftmost, performRequestsAsync,
+                                          )
+------------------------------------------------------------------------------
+import           Servant.Common.BaseUrl  (BaseUrl(..), Scheme(..), baseUrlWidget,
+                                          showBaseUrl,
+                                          SupportsServantReflex)
+import           Servant.Common.Req      (ClientOptions(..),
+                                          defaultClientOptions,
+                                          Req, ReqResult(..), QParam(..),
+                                          QueryPart(..), addHeader, authData,
+                                          defReq, evalResponse, prependToPathParts,
+                                          -- performRequestCT,
+                                          performRequestsCT,
+                                          -- performRequestNoBody,
+                                          performRequestsNoBody,
+                                          performSomeRequestsAsync,
+                                          qParamToQueryPart, reqBody,
+                                          reqSuccess, reqFailure,
+                                          reqMethod, respHeaders,
+                                          response,
+                                          reqTag,
+                                          qParams, withCredentials)
+
+
+-- * Accessing APIs as a Client
+
+-- | 'client' allows you to produce operations to query an API from a client.
+--
+-- > type MyApi = "books" :> Get '[JSON] [Book] -- GET /books
+-- >         :<|> "books" :> ReqBody '[JSON] Book :> Post '[JSON] Book -- POST /books
+-- >
+-- > myApi :: Proxy MyApi
+-- > myApi = Proxy
+-- >
+-- > getAllBooks :: Event t l -> m (Event t (l, ReqResult [Book]))
+-- > postNewBook :: Dynamic t (Maybe Book) -> Event t l
+--               -> m (Event t (l, ReqResult Book)))
+-- > (getAllBooks :<|> postNewBook) = client myApi host
+-- >   where host = constDyn $ BaseUrl Http "localhost" 8080
+client
+    :: (HasClient t m layout tag)
+    => Proxy layout
+    -> Proxy m
+    -> Proxy tag
+    -> Dynamic t BaseUrl
+    -> Client t m layout tag
+client p q t baseurl = clientWithRoute p q t defReq baseurl defaultClientOptions
+
+clientWithOpts
+    :: (HasClient t m layout tag)
+    => Proxy layout
+    -> Proxy m
+    -> Proxy tag
+    -> Dynamic t BaseUrl
+    -> ClientOptions
+    -> Client t m layout tag
+clientWithOpts p q t baseurl = clientWithRoute p q t defReq baseurl
+
+-- | Like 'clientWithOpts' but allows passing a function which will process the
+-- result event in some way. This can be used to handle errors in a uniform way
+-- across call sites.
+clientWithOptsAndResultHandler
+    :: (HasClient t m layout tag)
+    => Proxy layout
+    -> Proxy m
+    -> Proxy tag
+    -> Dynamic t BaseUrl
+    -> ClientOptions
+    -> (forall a. Event t (ReqResult tag a) -> m (Event t (ReqResult tag a)))
+    -> Client t m layout tag
+clientWithOptsAndResultHandler p q t = clientWithRouteAndResultHandler p q t defReq
+
+
+-- | This class lets us define how each API combinator
+-- influences the creation of an HTTP request. It's mostly
+-- an internal class, you can just use 'client'.
+class Monad m => HasClient t m layout (tag :: *) where
+  type Client t m layout tag :: *
+  clientWithRoute
+    :: Proxy layout
+    -> Proxy m
+    -> Proxy tag
+    -> Req t
+    -> Dynamic t BaseUrl
+    -> ClientOptions
+    -> Client t m layout tag
+  clientWithRoute l m t r b o = clientWithRouteAndResultHandler l m t r b o return
+
+  clientWithRouteAndResultHandler
+    :: Proxy layout
+    -> Proxy m
+    -> Proxy tag
+    -> Req t
+    -> Dynamic t BaseUrl
+    -> ClientOptions
+    -> (forall a. Event t (ReqResult tag a) -> m (Event t (ReqResult tag a)))
+    -> Client t m layout tag
+
+
+instance (HasClient t m a tag, HasClient t m b tag) => HasClient t m (a :<|> b) tag where
+  type Client t m (a :<|> b) tag = Client t m a tag :<|> Client t m b tag
+
+  clientWithRouteAndResultHandler Proxy q pTag req baseurl opts wrap =
+    clientWithRouteAndResultHandler (Proxy :: Proxy a) q pTag req baseurl opts wrap :<|>
+    clientWithRouteAndResultHandler (Proxy :: Proxy b) q pTag req baseurl opts wrap
+
+
+-- Capture. Example:
+-- > type MyApi = "books" :> Capture "isbn" Text :> Get '[JSON] Book
+-- >
+-- > myApi :: Proxy MyApi = Proxy
+-- >
+-- > getBook :: SupportsServantReflex t m
+--           => Dynamic t BaseUrl
+--           -> Dynamic t (Maybe Text)
+--           -> Event t l
+--           -> m (Event t (l, ReqResult Book))
+-- > getBook = client myApi (constDyn host)
+
+instance (SupportsServantReflex t m, ToHttpApiData a, HasClient t m sublayout tag)
+      => HasClient t m (Capture capture a :> sublayout) tag where
+
+  type Client t m (Capture capture a :> sublayout) tag =
+    Dynamic t (Either Text a) -> Client t m sublayout tag
+
+  clientWithRouteAndResultHandler Proxy q t req baseurl opts wrap val =
+    clientWithRouteAndResultHandler
+      (Proxy :: Proxy sublayout) q t (prependToPathParts p req) baseurl opts wrap
+    where p = (fmap . fmap) (toUrlPiece) val
+
+
+-- VERB (Returning content) --
+instance {-# OVERLAPPABLE #-}
+  -- Note [Non-Empty Content Types]
+  (MimeUnrender ct a, ReflectMethod method, cts' ~ (ct ': cts), SupportsServantReflex t m
+  ) => HasClient t m (Verb method status cts' a) tag where
+  type Client t m (Verb method status cts' a) tag =
+    Event t tag -> m (Event t (ReqResult tag a))
+    -- TODO how to access input types here?
+    -- ExceptT ServantError IO a
+  clientWithRouteAndResultHandler Proxy _ _ req baseurl opts wrap trigs =
+      wrap =<< fmap runIdentity <$> performRequestsCT (Proxy :: Proxy ct) method (constDyn $ Identity $ req') baseurl opts trigs
+      where method = E.decodeUtf8 $ reflectMethod (Proxy :: Proxy method)
+            req' = req { reqMethod = method }
+
+
+-- -- VERB (No content) --
+instance {-# OVERLAPPING #-}
+  (ReflectMethod method, SupportsServantReflex t m) =>
+  HasClient t m (Verb method status cts NoContent) tag where
+  type Client t m (Verb method status cts NoContent) tag =
+    Event t tag -> m (Event t (ReqResult tag NoContent))
+    -- TODO: how to access input types here?
+    -- ExceptT ServantError IO NoContent
+  clientWithRouteAndResultHandler Proxy _ _ req baseurl opts wrap trigs =
+    wrap =<< fmap  runIdentity <$> performRequestsNoBody method (constDyn $ Identity req) baseurl opts trigs
+      where method = E.decodeUtf8 $ reflectMethod (Proxy :: Proxy method)
+
+
+toHeaders :: BuildHeadersTo ls => ReqResult tag a -> ReqResult tag (Headers ls a)
+toHeaders r =
+  let toBS = E.encodeUtf8
+      hdrs = maybe []
+                   (\xhr -> fmap (\(h,v) -> (mk (toBS h), toBS v))
+                     (Map.toList $ _xhrResponse_headers xhr))
+                   (response r)
+  in  ffor r $ \a -> Headers {getResponse = a ,getHeadersHList = buildHeadersTo hdrs}
+
+class BuildHeaderKeysTo hs where
+  buildHeaderKeysTo :: Proxy hs -> [T.Text]
+
+instance {-# OVERLAPPABLE #-} BuildHeaderKeysTo '[]
+  where buildHeaderKeysTo _ = []
+
+instance {-# OVERLAPPABLE #-} (BuildHeaderKeysTo xs, KnownSymbol h)
+  => BuildHeaderKeysTo ((Header h v) ': xs) where
+  buildHeaderKeysTo _ = T.pack (symbolVal (Proxy :: Proxy h)) : buildHeaderKeysTo (Proxy :: Proxy xs)
+
+-- HEADERS Verb (Content) --
+-- Headers combinator not treated in fully general case,
+-- in order to deny instances for (Headers ls (Capture "id" Int)),
+-- a combinator that wouldn't make sense
+-- TODO Overlapping??
+instance {-# OVERLAPPABLE #-}
+  -- Note [Non-Empty Content Types]
+  ( MimeUnrender ct a, BuildHeadersTo ls, BuildHeaderKeysTo ls,
+    ReflectMethod method, cts' ~ (ct ': cts),
+    SupportsServantReflex t m
+  ) => HasClient t m (Verb method status cts' (Headers ls a)) tag where
+  type Client t m (Verb method status cts' (Headers ls a)) tag =
+      Event t tag -> m (Event t (ReqResult tag (Headers ls a)))
+  clientWithRouteAndResultHandler Proxy _ _ req baseurl opts wrap trigs = do
+    let method = E.decodeUtf8 $ reflectMethod (Proxy :: Proxy method)
+    resp <- fmap runIdentity <$> performRequestsCT (Proxy :: Proxy ct) method (constDyn $ Identity req') baseurl opts trigs
+    wrap $ toHeaders <$> resp
+    where req' = req { respHeaders =
+                       OnlyHeaders (Set.fromList (buildHeaderKeysTo (Proxy :: Proxy ls)))
+                     }
+
+
+-- HEADERS Verb (No content) --
+instance {-# OVERLAPPABLE #-}
+  ( BuildHeadersTo ls, BuildHeaderKeysTo ls, ReflectMethod method,
+    SupportsServantReflex t m
+  ) => HasClient t m (Verb method status cts (Headers ls NoContent)) tag where
+  type Client t m (Verb method status cts (Headers ls NoContent)) tag
+    = Event t tag -> m (Event t (ReqResult tag (Headers ls NoContent)))
+  clientWithRouteAndResultHandler Proxy _ _ req baseurl opts wrap trigs = do
+    let method = E.decodeUtf8 $ reflectMethod (Proxy :: Proxy method)
+    resp <- fmap runIdentity <$> performRequestsNoBody method (constDyn $ Identity req') baseurl opts trigs
+    wrap $ toHeaders <$> resp
+    where req' = req {respHeaders =
+                      OnlyHeaders (Set.fromList (buildHeaderKeysTo (Proxy :: Proxy ls)))
+                     }
+
+
+
+-- HEADER
+-- > newtype Referer = Referer { referrer :: Text }
+-- >   deriving (Eq, Show, Generic, FromText, ToHttpApiData)
+-- >
+-- >            -- GET /view-my-referer
+-- > type MyApi = "view-my-referer" :> Header "Referer" Referer :> Get '[JSON] Referer
+-- >
+-- >
+-- > viewReferer :: Maybe Referer -> ExceptT String IO Book
+-- > viewReferer = client myApi host
+-- >   where host = BaseUrl Http "localhost" 8080
+-- > -- then you can just use "viewRefer" to query that endpoint
+-- > -- specifying Nothing or e.g Just "http://haskell.org/" as arguments
+instance (KnownSymbol sym, ToHttpApiData a,
+          HasClient t m sublayout tag, SupportsServantReflex t m)
+      => HasClient t m (Header sym a :> sublayout) tag where
+
+  type Client t m (Header sym a :> sublayout) tag =
+    Dynamic t (Either Text a) -> Client t m sublayout tag
+
+  clientWithRouteAndResultHandler Proxy q t req baseurl opts wrap eVal =
+    clientWithRouteAndResultHandler
+      (Proxy :: Proxy sublayout) q t
+      (Servant.Common.Req.addHeader hname eVal req)
+      baseurl opts wrap
+    where hname = T.pack $ symbolVal (Proxy :: Proxy sym)
+
+
+
+
+-- | Using a 'HttpVersion' combinator in your API doesn't affect the client
+-- functions.
+instance HasClient t m sublayout tag
+  => HasClient t m (HttpVersion :> sublayout) tag where
+
+  type Client t m (HttpVersion :> sublayout) tag =
+    Client t m sublayout tag
+
+  clientWithRouteAndResultHandler Proxy =
+    clientWithRouteAndResultHandler (Proxy :: Proxy sublayout)
+
+
+-- | If you use a 'QueryParam' in one of your endpoints in your API,
+-- the corresponding querying function will automatically take
+-- an additional argument of the type specified by your 'QueryParam',
+-- enclosed in Maybe.
+--
+-- If you give Nothing, nothing will be added to the query string.
+--
+-- If you give a non-'Nothing' value, this function will take care
+-- of inserting a textual representation of this value in the query string.
+--
+-- You can control how values for your type are turned into
+-- text by specifying a 'ToHttpApiData' instance for your type.
+--
+-- Example:
+--
+-- > type MyApi = "books" :> QueryParam "author" Text :> Get '[JSON] [Book]
+-- >
+-- > myApi :: Proxy MyApi
+-- > myApi = Proxy
+-- >
+-- > getBooksBy :: Maybe Text -> ExceptT String IO [Book]
+-- > getBooksBy = client myApi host
+-- >   where host = BaseUrl Http "localhost" 8080
+-- > -- then you can just use "getBooksBy" to query that endpoint.
+-- > -- 'getBooksBy Nothing' for all books
+-- > -- 'getBooksBy (Just "Isaac Asimov")' to get all books by Isaac Asimov
+instance (KnownSymbol sym, ToHttpApiData a, HasClient t m sublayout tag, Reflex t)
+      => HasClient t m (QueryParam sym a :> sublayout) tag where
+
+  type Client t m (QueryParam sym a :> sublayout) tag =
+    Dynamic t (QParam a) -> Client t m sublayout tag
+
+  -- if mparam = Nothing, we don't add it to the query string
+  clientWithRouteAndResultHandler Proxy q t req baseurl opts wrap mparam =
+    clientWithRouteAndResultHandler (Proxy :: Proxy sublayout) q t
+      (req {qParams = paramPair : qParams req}) baseurl opts wrap
+
+    where pname = symbolVal (Proxy :: Proxy sym)
+          --p prm = QueryPartParam $ (fmap . fmap) (toQueryParam) prm
+          --paramPair = (T.pack pname, p mparam)
+          p prm = QueryPartParam $ fmap qParamToQueryPart prm -- (fmap . fmap) (unpack . toQueryParam) prm
+          paramPair = (T.pack pname, p mparam)
+
+
+
+-- | If you use a 'QueryParams' in one of your endpoints in your API,
+-- the corresponding querying function will automatically take
+-- an additional argument, a list of values of the type specified
+-- by your 'QueryParams'.
+--
+-- If you give an empty list, nothing will be added to the query string.
+--
+-- Otherwise, this function will take care
+-- of inserting a textual representation of your values in the query string,
+-- under the same query string parameter name.
+--
+-- You can control how values for your type are turned into
+-- text by specifying a 'ToHttpApiData' instance for your type.
+--
+-- Example:
+--
+-- > type MyApi = "books" :> QueryParams "authors" Text :> Get '[JSON] [Book]
+-- >
+-- > myApi :: Proxy MyApi
+-- > myApi = Proxy
+-- >
+-- > getBooksBy :: [Text] -> ExceptT String IO [Book]
+-- > getBooksBy = client myApi host
+-- >   where host = BaseUrl Http "localhost" 8080
+-- > -- then you can just use "getBooksBy" to query that endpoint.
+-- > -- 'getBooksBy []' for all books
+-- > -- 'getBooksBy ["Isaac Asimov", "Robert A. Heinlein"]'
+-- > --   to get all books by Asimov and Heinlein
+instance (KnownSymbol sym, ToHttpApiData a, HasClient t m sublayout tag, Reflex t)
+      => HasClient t m (QueryParams sym a :> sublayout) tag where
+
+  type Client t m (QueryParams sym a :> sublayout) tag =
+    Dynamic t [a] -> Client t m sublayout tag
+
+  clientWithRouteAndResultHandler Proxy q t req baseurl opts wrap paramlist =
+    clientWithRouteAndResultHandler (Proxy :: Proxy sublayout) q t req' baseurl opts wrap
+
+      where req'    = req { qParams =  (T.pack pname, params') : qParams req }
+            pname   = symbolVal (Proxy :: Proxy sym)
+            params' = QueryPartParams $ (fmap . fmap) toQueryParam
+                        paramlist
+
+
+
+-- | If you use a 'QueryFlag' in one of your endpoints in your API,
+-- the corresponding querying function will automatically take
+-- an additional 'Bool' argument.
+--
+-- If you give 'False', nothing will be added to the query string.
+--
+-- Otherwise, this function will insert a value-less query string
+-- parameter under the name associated to your 'QueryFlag'.
+--
+-- Example:
+--
+-- > type MyApi = "books" :> QueryFlag "published" :> Get '[JSON] [Book]
+-- >
+-- > myApi :: Proxy MyApi
+-- > myApi = Proxy
+-- >
+-- > getBooks :: Bool -> ExceptT String IO [Book]
+-- > getBooks = client myApi host
+-- >   where host = BaseUrl Http "localhost" 8080
+-- > -- then you can just use "getBooks" to query that endpoint.
+-- > -- 'getBooksBy False' for all books
+-- > -- 'getBooksBy True' to only get _already published_ books
+
+-- TODO Bring back
+instance (KnownSymbol sym, HasClient t m sublayout tag, Reflex t)
+      => HasClient t m (QueryFlag sym :> sublayout) tag where
+
+  type Client t m (QueryFlag sym :> sublayout) tag =
+    Dynamic t Bool -> Client t m sublayout tag
+
+  clientWithRouteAndResultHandler Proxy q t req baseurl opts wrap flag =
+    clientWithRouteAndResultHandler (Proxy :: Proxy sublayout) q t req' baseurl opts wrap
+
+    where req'     = req { qParams = thisPair : qParams req }
+          thisPair = (T.pack pName, QueryPartFlag flag) :: (Text, QueryPart t)
+          pName    = symbolVal (Proxy :: Proxy sym)
+
+
+
+-- | Send a raw 'XhrRequest ()' directly to 'baseurl'
+instance SupportsServantReflex t m => HasClient t m Raw tag where
+  type Client t m Raw tag = Dynamic t (Either Text (XhrRequest ()))
+                      -> Event t tag
+                      -> m (Event t (ReqResult tag ()))
+
+  clientWithRouteAndResultHandler _ _ _ _ baseurl _ wrap xhrs triggers = do
+
+    let xhrs'   = liftA2 (\x path -> case x of
+                             Left e -> Left e
+                             Right jx -> Right $ jx { _xhrRequest_url = path <> _xhrRequest_url jx }
+                         ) xhrs (showBaseUrl <$> baseurl)
+        xhrs''  = attachPromptlyDynWith (flip (,)) xhrs' triggers :: Event t (tag, Either Text (XhrRequest ()))
+        badReq = fmapMaybe (\(t,x) -> either (Just . (t,)) (const Nothing) x) xhrs'' :: Event t (tag, Text)
+        okReq  = fmapMaybe (\(t,x) -> either (const Nothing) (Just . (t,)) x) xhrs'' :: Event t (tag, XhrRequest ())
+
+    resps  <- performRequestsAsync okReq
+    wrap $ leftmost [ uncurry RequestFailure <$> badReq
+                      , evalResponse (const $ Right ()) <$> resps
+                      ]
+
+
+-- | If you use a 'ReqBody' in one of your endpoints in your API,
+-- the corresponding querying function will automatically take
+-- an additional argument of the type specified by your 'ReqBody'.
+-- That function will take care of encoding this argument as JSON and
+-- of using it as the request body.
+--
+-- All you need is for your type to have a 'ToJSON' instance.
+--
+-- Example:
+--
+-- > type MyApi = "books" :> ReqBody '[JSON] Book :> Post '[JSON] Book
+-- >
+-- > myApi :: Proxy MyApi
+-- > myApi = Proxy
+-- >
+-- > addBook :: Book -> ExceptT String IO Book
+-- > addBook = client myApi host
+-- >   where host = BaseUrl Http "localhost" 8080
+-- > -- then you can just use "addBook" to query that endpoint
+
+instance (MimeRender ct a, HasClient t m sublayout tag, Reflex t)
+      => HasClient t m (ReqBody (ct ': cts) a :> sublayout) tag where
+
+  type Client t m (ReqBody (ct ': cts) a :> sublayout) tag =
+    Dynamic t (Either Text a) -> Client t m sublayout tag
+
+  clientWithRouteAndResultHandler Proxy q t req baseurl opts wrap body =
+    clientWithRouteAndResultHandler (Proxy :: Proxy sublayout) q t req' baseurl opts wrap
+       where req'        = req { reqBody = bodyBytesCT }
+             ctProxy     = Proxy :: Proxy ct
+             ctString    = T.pack $ show $ contentType ctProxy
+             bodyBytesCT = Just $ (fmap . fmap)
+                             (\b -> (mimeRender ctProxy b, ctString))
+                             body
+
+
+
+-- | Make the querying function append @path@ to the request path.
+instance (KnownSymbol path, HasClient t m sublayout tag, Reflex t) => HasClient t m (path :> sublayout) tag where
+  type Client t m (path :> sublayout) tag = Client t m sublayout tag
+
+  clientWithRouteAndResultHandler Proxy q t req baseurl opts wrap =
+     clientWithRouteAndResultHandler (Proxy :: Proxy sublayout) q t
+                     (prependToPathParts (pure (Right $ T.pack p)) req) baseurl opts wrap
+
+    where p = symbolVal (Proxy :: Proxy path)
+
+
+instance HasClient t m api tag => HasClient t m (Vault :> api) tag where
+  type Client t m (Vault :> api) tag = Client t m api tag
+
+  clientWithRouteAndResultHandler Proxy =
+    clientWithRouteAndResultHandler (Proxy :: Proxy api)
+
+
+instance HasClient t m api tag => HasClient t m (RemoteHost :> api) tag where
+  type Client t m (RemoteHost :> api) tag = Client t m api tag
+
+  clientWithRouteAndResultHandler Proxy =
+    clientWithRouteAndResultHandler (Proxy :: Proxy api)
+
+
+
+instance HasClient t m api tag => HasClient t m (IsSecure :> api) tag where
+  type Client t m (IsSecure :> api) tag = Client t m api tag
+
+  clientWithRouteAndResultHandler Proxy =
+    clientWithRouteAndResultHandler (Proxy :: Proxy api)
+
+
+instance (HasClient t m api tag, Reflex t)
+      => HasClient t m (BasicAuth realm usr :> api) tag where
+
+  type Client t m (BasicAuth realm usr :> api) tag = Dynamic t (Maybe BasicAuthData)
+                                               -> Client t m api tag
+
+  clientWithRouteAndResultHandler Proxy q t req baseurl opts wrap authdata =
+    clientWithRouteAndResultHandler (Proxy :: Proxy api) q t req' baseurl opts wrap
+      where
+        req'    = req { authData = Just authdata }
+
+-- instance HasClient t m subapi =>
+--   HasClient t m (WithNamedConfig name config subapi) where
+
+--   type Client t m (WithNamedConfig name config subapi) = Client t m subapi
+--   clientWithRoute Proxy q = clientWithRoute (Proxy :: Proxy subapi) q
+
+
+{- Note [Non-Empty Content Types]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Rather than have
+
+   instance (..., cts' ~ (ct ': cts)) => ... cts' ...
+
+It may seem to make more sense to have:
+
+   instance (...) => ... (ct ': cts) ...
+
+But this means that if another instance exists that does *not* require
+non-empty lists, but is otherwise more specific, no instance will be overall
+more specific. This in turn generally means adding yet another instance (one
+for empty and one for non-empty lists).
+-}
+
+
+-- SUPPORT FOR servant-auth --
+
+-- For JavaScript clients we should be sending/storing JSON web tokens in a
+-- way that is inaccessible to JavaScript.
+--
+-- For @servant-auth@ this is done with HTTP-only cookies. In a Reflex-DOM
+-- app this means the @servant-auth@ client should only verify that the API
+-- supports Cookie-based authentication but do nothing with the token
+-- directly.
+
+-- @HasCookieAuth auths@ is nominally a redundant constraint, but ensures
+-- we're not trying to rely on cookies when the API does not use them.
+instance (HasCookieAuth auths, HasClient t m api tag) => HasClient t m (Auth.Auth auths a :> api) tag where
+
+  type Client t m (Auth.Auth auths a :> api) tag = Client t m api tag
+  clientWithRouteAndResultHandler Proxy = clientWithRouteAndResultHandler (Proxy :: Proxy api)
+
+
+type family HasCookieAuth xs :: Constraint where
+  HasCookieAuth (Auth.Cookie ': xs) = ()
+  HasCookieAuth (x ': xs)   = HasCookieAuth xs
+  HasCookieAuth '[]         = CookieAuthNotEnabled
+
+class CookieAuthNotEnabled
+
diff --git a/src/Servant/Reflex/Multi.hs b/src/Servant/Reflex/Multi.hs
new file mode 100644
--- /dev/null
+++ b/src/Servant/Reflex/Multi.hs
@@ -0,0 +1,388 @@
+{-# LANGUAGE AllowAmbiguousTypes   #-}
+{-# LANGUAGE CPP                   #-}
+{-# LANGUAGE DataKinds             #-}
+{-# LANGUAGE FlexibleContexts      #-}
+{-# LANGUAGE FlexibleInstances     #-}
+{-# LANGUAGE InstanceSigs          #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE OverloadedStrings     #-}
+{-# LANGUAGE PolyKinds             #-}
+{-# LANGUAGE ScopedTypeVariables   #-}
+{-# LANGUAGE TupleSections         #-}
+{-# LANGUAGE TypeFamilies          #-}
+{-# LANGUAGE TypeOperators         #-}
+{-# LANGUAGE UndecidableInstances  #-}
+
+module Servant.Reflex.Multi (
+    -- * Compute servant client functions
+    clientA
+    , clientWithOptsA
+    , BaseUrl(..)
+    , Scheme(..)
+
+    -- * Build QueryParam arguments
+    , QParam(..)
+
+    -- * Access response data
+    , withCredentials
+
+    -- * Access response data
+    , ReqResult(..)
+    , reqSuccess
+    , reqSuccess'
+    , reqFailure
+    , response
+
+    , HasClientMulti(..)
+    ) where
+
+------------------------------------------------------------------------------
+import           Control.Applicative    (liftA2)
+import           Data.Functor.Compose   (Compose (..), getCompose)
+import           Data.Proxy             (Proxy (..))
+import qualified Data.Set               as Set
+import           Data.Text              (Text)
+import qualified Data.Text              as T
+import qualified Data.Text.Encoding     as E
+import           GHC.TypeLits           (KnownSymbol, symbolVal)
+import           Servant.API            ((:<|>) (..), (:>), BasicAuth,
+                                         BasicAuthData, BuildHeadersTo (..),
+                                         Capture, Header, Headers (..),
+                                         HttpVersion, IsSecure, MimeRender (..),
+                                         MimeUnrender, NoContent, QueryFlag,
+                                         QueryParam, QueryParams, Raw,
+                                         ReflectMethod (..), RemoteHost,
+                                         ReqBody, ToHttpApiData (..), Vault,
+                                         Verb, contentType)
+
+import           Reflex.Dom.Core        (Dynamic, Event, Reflex,
+                                         XhrRequest (..),
+                                         XhrResponseHeaders (..),
+                                         attachPromptlyDynWith, constDyn)
+------------------------------------------------------------------------------
+import           Servant.Common.BaseUrl (BaseUrl (..), Scheme (..),
+                                         SupportsServantReflex)
+import           Servant.Common.Req     (ClientOptions,
+                                         QParam (..), QueryPart (..), Req,
+                                         ReqResult (..), addHeader, authData,
+                                         defReq,
+                                         defaultClientOptions,
+                                         performRequestsCT,
+                                         performRequestsNoBody,
+                                         performSomeRequestsAsync,
+                                         prependToPathParts, qParamToQueryPart,
+                                         qParams, reqBody, reqFailure,
+                                         reqMethod, reqSuccess, reqSuccess',
+                                         respHeaders, response, withCredentials)
+import           Servant.Reflex         (BuildHeaderKeysTo (..), toHeaders)
+
+
+------------------------------------------------------------------------------
+clientA :: (HasClientMulti t m layout f tag, Applicative f, Reflex t)
+        => Proxy layout -> Proxy m -> Proxy f -> Proxy tag
+        -> Dynamic t BaseUrl -> ClientMulti t m layout f tag
+clientA p q f tag baseurl  =
+    clientWithRouteMulti p q f tag (constDyn (pure defReq)) baseurl
+    defaultClientOptions
+
+
+-- | A version of @client@ that sets the withCredentials flag
+-- on requests. Use this function for clients of CORS API's
+clientWithOptsA :: (HasClientMulti t m layout f tag, Applicative f, Reflex t)
+                 => Proxy layout -> Proxy m -> Proxy f -> Proxy tag
+                 -> Dynamic t BaseUrl -> ClientOptions -> ClientMulti t m layout f tag
+clientWithOptsA p q f tag baseurl opts =
+    clientWithRouteMulti p q f tag
+    (constDyn (pure defReq)) baseurl opts
+
+------------------------------------------------------------------------------
+class HasClientMulti t m layout f (tag :: *) where
+  type ClientMulti t m layout f tag :: *
+  clientWithRouteMulti :: Proxy layout -> Proxy m -> Proxy f -> Proxy tag
+                       -> Dynamic t (f (Req t)) -> Dynamic t BaseUrl
+                       -> ClientOptions -> ClientMulti t m layout f tag
+
+
+------------------------------------------------------------------------------
+instance (HasClientMulti t m a f tag, HasClientMulti t m b f tag) =>
+    HasClientMulti t m (a :<|> b) f tag where
+  type ClientMulti t m (a :<|> b) f tag = ClientMulti t m a f tag :<|>
+                                          ClientMulti t m b f tag
+  clientWithRouteMulti Proxy q f tag reqs baseurl opts =
+    clientWithRouteMulti (Proxy :: Proxy a) q f tag reqs baseurl opts :<|>
+    clientWithRouteMulti (Proxy :: Proxy b) q f tag reqs baseurl opts
+
+
+------------------------------------------------------------------------------
+instance (SupportsServantReflex t m,
+          ToHttpApiData a,
+          HasClientMulti t m sublayout f tag,
+          Applicative f)
+      => HasClientMulti t m (Capture capture a :> sublayout) f tag where
+
+  type ClientMulti t m (Capture capture a :> sublayout) f tag =
+    f (Dynamic t (Either Text a)) -> ClientMulti t m sublayout f tag
+
+  clientWithRouteMulti _ q f tag reqs baseurl opts vals =
+    clientWithRouteMulti (Proxy :: Proxy sublayout) q f tag reqs' baseurl opts
+    where
+      reqs' = (prependToPathParts <$> ps <*>) <$> reqs
+      ps    = (fmap .  fmap . fmap) toUrlPiece vals
+
+
+------------------------------------------------------------------------------
+-- VERB (Returning content) --
+instance {-# OVERLAPPABLE #-}
+  -- Note [Non-Empty Content Types]
+  (MimeUnrender ct a,
+   ReflectMethod method, cts' ~ (ct ': cts),
+   SupportsServantReflex t m,
+   Applicative f,
+   Traversable f
+  ) => HasClientMulti t m (Verb method status cts' a) f tag where
+
+  type ClientMulti t m (Verb method status cts' a) f tag =
+    Event t tag -> m (Event t (f (ReqResult tag a)))
+
+  clientWithRouteMulti _ _ _ _ reqs baseurl opts =
+    performRequestsCT (Proxy :: Proxy ct) method reqs' baseurl opts
+      where method = E.decodeUtf8 $ reflectMethod (Proxy :: Proxy method)
+            reqs' = fmap (\r -> r { reqMethod = method }) <$> reqs
+
+
+------------------------------------------------------------------------------
+-- -- VERB (No content) --
+instance {-# OVERLAPPING #-}
+  (ReflectMethod method, SupportsServantReflex t m, Traversable f) =>
+  HasClientMulti t m (Verb method status cts NoContent) f tag where
+  type ClientMulti t m (Verb method status cts NoContent) f tag =
+    Event t tag -> m (Event t (f (ReqResult tag NoContent)))
+    -- TODO: how to access input types here?
+    -- ExceptT ServantError IO NoContent
+  clientWithRouteMulti Proxy _ _ _ req baseurl opts =
+    performRequestsNoBody method req baseurl opts
+      where method = E.decodeUtf8 $ reflectMethod (Proxy :: Proxy method)
+
+
+------------------------------------------------------------------------------
+instance {-# OVERLAPPABLE #-}
+  -- Note [Non-Empty Content Types]
+  ( MimeUnrender ct a, BuildHeadersTo ls, BuildHeaderKeysTo ls,
+    ReflectMethod method, cts' ~ (ct ': cts),
+    SupportsServantReflex t m,
+    Traversable f
+  ) => HasClientMulti t m (Verb method status cts' (Headers ls a)) f tag where
+  type ClientMulti t m (Verb method status cts' (Headers ls a)) f tag =
+    Event t tag -> m (Event t (f (ReqResult tag (Headers ls a))))
+  clientWithRouteMulti Proxy _ _ _ reqs baseurl opts triggers = do
+    let method = E.decodeUtf8 $ reflectMethod (Proxy :: Proxy method)
+    resp <- performRequestsCT (Proxy :: Proxy ct) method reqs' baseurl opts triggers :: m (Event t (f (ReqResult tag a)))
+    return $ fmap toHeaders <$> resp
+    where
+      reqs' = fmap (\r ->
+                r { respHeaders =
+                    OnlyHeaders (Set.fromList
+                                 (buildHeaderKeysTo (Proxy :: Proxy ls)))
+                  }) <$> reqs
+
+
+------------------------------------------------------------------------------
+instance {-# OVERLAPPABLE #-}
+  ( BuildHeadersTo ls,
+    BuildHeaderKeysTo ls,
+    ReflectMethod method,
+    SupportsServantReflex t m,
+    Traversable f
+  ) => HasClientMulti t m (Verb method status
+                           cts (Headers ls NoContent)) f tag where
+  type ClientMulti t m (Verb method status cts (Headers ls NoContent)) f tag
+    = Event t tag -> m (Event t (f (ReqResult tag (Headers ls NoContent))))
+  clientWithRouteMulti Proxy _ _ _ reqs baseurl opts triggers = do
+    let method = E.decodeUtf8 $ reflectMethod (Proxy :: Proxy method)
+    resp <- performRequestsNoBody method reqs' baseurl opts triggers
+    return $ fmap toHeaders <$> resp
+    where reqs' = fmap (\req ->
+                    req {respHeaders = OnlyHeaders (Set.fromList
+                         (buildHeaderKeysTo (Proxy :: Proxy ls)))
+                        }) <$> reqs
+
+
+------------------------------------------------------------------------------
+instance (KnownSymbol sym,
+          ToHttpApiData a,
+          HasClientMulti t m sublayout f tag,
+          SupportsServantReflex t m,
+          Traversable f,
+          Applicative f)
+      => HasClientMulti t m (Header sym a :> sublayout) f tag where
+
+  type ClientMulti t m (Header sym a :> sublayout) f tag =
+    f (Dynamic t (Either Text a)) -> ClientMulti t m sublayout f tag
+
+  clientWithRouteMulti Proxy f q tag reqs baseurl opts eVals =
+    clientWithRouteMulti (Proxy :: Proxy sublayout) f
+                    q tag
+                    reqs'
+                    baseurl opts
+    where hname = T.pack $ symbolVal (Proxy :: Proxy sym)
+          reqs' = ((\eVal req -> Servant.Common.Req.addHeader hname eVal req)
+                  <$> eVals <*>) <$> reqs
+
+
+------------------------------------------------------------------------------
+instance HasClientMulti t m sublayout f tag
+  => HasClientMulti t m (HttpVersion :> sublayout) f tag where
+
+  type ClientMulti t m (HttpVersion :> sublayout) f tag =
+    ClientMulti t m sublayout f tag
+
+  clientWithRouteMulti Proxy q f tag =
+    clientWithRouteMulti (Proxy :: Proxy sublayout) q f tag
+
+
+------------------------------------------------------------------------------
+instance (KnownSymbol sym,
+          ToHttpApiData a,
+          HasClientMulti t m sublayout f tag,
+          Reflex t,
+          Applicative f)
+      => HasClientMulti t m (QueryParam sym a :> sublayout) f tag where
+
+  type ClientMulti t m (QueryParam sym a :> sublayout) f tag =
+    Dynamic t (f (QParam a)) -> ClientMulti t m sublayout f tag
+
+  -- if mparam = Nothing, we don't add it to the query string
+  -- TODO: Check the above comment
+  clientWithRouteMulti Proxy q f tag reqs baseurl opts mparams =
+    clientWithRouteMulti (Proxy :: Proxy sublayout) q f tag
+      reqs' baseurl opts
+
+    where pname = symbolVal (Proxy :: Proxy sym)
+          p prm = QueryPartParam $ fmap qParamToQueryPart prm
+          paramPair mp = (T.pack pname, p mp)
+          -- reqs' = (\params reqs -> (\req param -> req {qParams = paramPair param : qParams req}) <$> reqs <*> params)
+          --         <$> mparams <*> reqs
+          reqs' = liftA2 (\(pr :: QParam a) (r :: Req t) -> r { qParams = paramPair (constDyn pr) : qParams r })
+                  <$> mparams <*> reqs
+
+
+instance (KnownSymbol sym,
+          ToHttpApiData a,
+          HasClientMulti t m sublayout f tag,
+          Reflex t,
+          Applicative f)
+      => HasClientMulti t m (QueryParams sym a :> sublayout) f tag where
+
+  type ClientMulti t m (QueryParams sym a :> sublayout) f tag =
+    Dynamic t (f [a]) -> ClientMulti t m sublayout f tag
+
+  clientWithRouteMulti Proxy q f tag reqs baseurl opts paramlists =
+    clientWithRouteMulti (Proxy :: Proxy sublayout) q f tag reqs' baseurl opts
+
+      where req' l r = r { qParams =  (T.pack pname, params' (constDyn l)) : qParams r }
+            pname   = symbolVal (Proxy :: Proxy sym)
+            params' l = QueryPartParams $ (fmap . fmap) (toQueryParam)
+                        l
+            reqs' = liftA2 req' <$> paramlists <*> reqs
+
+
+instance (KnownSymbol sym,
+          HasClientMulti t m sublayout f tag,
+          Reflex t,
+          Applicative f)
+      => HasClientMulti t m (QueryFlag sym :> sublayout) f tag where
+
+  type ClientMulti t m (QueryFlag sym :> sublayout) f tag =
+    Dynamic t (f Bool) -> ClientMulti t m sublayout f tag
+
+  clientWithRouteMulti Proxy q f' tag reqs baseurl opts flags =
+    clientWithRouteMulti (Proxy :: Proxy sublayout) q f' tag reqs' baseurl opts
+
+    where req' f req = req { qParams = thisPair (constDyn f) : qParams req }
+          thisPair f = (T.pack pName, QueryPartFlag f) :: (Text, QueryPart t)
+          pName      = symbolVal (Proxy :: Proxy sym)
+          reqs'      = liftA2 req' <$> flags <*> reqs
+
+
+instance (SupportsServantReflex t m,
+          Traversable f, Applicative f) => HasClientMulti t m Raw f tag where
+  type ClientMulti t m Raw f tag = f (Dynamic t (Either Text (XhrRequest ())))
+                                 -> Event t tag
+                                 -> m (Event t (f (ReqResult tag ())))
+
+  clientWithRouteMulti _ _ _ _ _ _ opts rawReqs triggers = do
+    let rawReqs' = sequence rawReqs :: Dynamic t (f (Either Text (XhrRequest ())))
+        rawReqs'' = attachPromptlyDynWith (\fxhr t -> Compose (t, fxhr)) rawReqs' triggers
+    resps <- fmap (fmap aux . sequenceA . getCompose) <$> performSomeRequestsAsync opts rawReqs''
+    return resps
+    where
+      aux (tag, Right r) = ResponseSuccess tag () r
+      aux (tag, Left  e) = RequestFailure tag e
+
+
+instance (MimeRender ct a,
+          HasClientMulti t m sublayout f tag,
+          Reflex t,
+          Applicative f)
+      => HasClientMulti t m (ReqBody (ct ': cts) a :> sublayout) f tag where
+
+  type ClientMulti t m (ReqBody (ct ': cts) a :> sublayout) f tag =
+    Dynamic t (f (Either Text a)) -> ClientMulti t m sublayout f tag
+
+  clientWithRouteMulti Proxy q f tag reqs baseurl opts bodies =
+    clientWithRouteMulti (Proxy :: Proxy sublayout) q f tag reqs' baseurl opts
+       where req'        b r = r { reqBody = bodyBytesCT (constDyn b) }
+             ctProxy         = Proxy :: Proxy ct
+             ctString        = T.pack $ show $ contentType ctProxy
+             bodyBytesCT b   = Just $ (fmap . fmap)
+                               (\b' -> (mimeRender ctProxy b', ctString))
+                               b
+             reqs'           = liftA2 req' <$> bodies <*> reqs
+
+
+instance (KnownSymbol path,
+          HasClientMulti t m sublayout f tag,
+          Reflex t,
+          Functor f) => HasClientMulti t m (path :> sublayout) f tag where
+  type ClientMulti t m (path :> sublayout) f tag = ClientMulti t m sublayout f tag
+
+  clientWithRouteMulti Proxy q f tag reqs baseurl =
+     clientWithRouteMulti (Proxy :: Proxy sublayout) q f tag
+                     (fmap (prependToPathParts (pure (Right $ T.pack p))) <$> reqs)
+                     baseurl
+
+    where p = symbolVal (Proxy :: Proxy path)
+
+
+instance HasClientMulti t m api f tag => HasClientMulti t m (Vault :> api) f tag where
+  type ClientMulti t m (Vault :> api) f tag = ClientMulti t m api f tag
+
+  clientWithRouteMulti Proxy q f tag reqs baseurl =
+    clientWithRouteMulti (Proxy :: Proxy api) q f tag reqs baseurl
+
+
+instance HasClientMulti t m api f tag => HasClientMulti t m (RemoteHost :> api) f tag where
+  type ClientMulti t m (RemoteHost :> api) f tag = ClientMulti t m api f tag
+
+  clientWithRouteMulti Proxy q f tag reqs baseurl =
+    clientWithRouteMulti (Proxy :: Proxy api) q f tag reqs baseurl
+
+
+instance HasClientMulti t m api f tag => HasClientMulti t m (IsSecure :> api) f tag where
+  type ClientMulti t m (IsSecure :> api) f tag = ClientMulti t m api f tag
+
+  clientWithRouteMulti Proxy q f tag reqs baseurl =
+    clientWithRouteMulti (Proxy :: Proxy api) q f tag reqs baseurl
+
+
+instance (HasClientMulti t m api f tag, Reflex t, Applicative f)
+      => HasClientMulti t m (BasicAuth realm usr :> api) f tag where
+
+  type ClientMulti t m (BasicAuth realm usr :> api) f tag = Dynamic t (f (Maybe BasicAuthData))
+                                               -> ClientMulti t m api f tag
+
+  clientWithRouteMulti Proxy q f tag reqs baseurl opts authdatas =
+    clientWithRouteMulti (Proxy :: Proxy api) q f tag reqs' baseurl opts
+      where
+        req'  a r = r { authData = Just (constDyn a) }
+        reqs' = liftA2 req' <$> authdatas <*> reqs
