packages feed

plaid-0.1.0.0: examples/Main.hs

module Main where

{-
 Module containing useful real world examples of using plaid library.
-}

import           Control.Exception.Safe (MonadThrow, throwM)
import           Control.Monad.Except   (liftEither, runExceptT)
import           Control.Monad.Reader
import           Data.ByteString.Lazy   (ByteString)
import           Data.Plaid
import           Data.Text              (Text)
import           Data.Time
import           Text.Pretty.Simple

-- | Client id
clientId :: ClientId
clientId = ClientId "5d11dd0fdeb8a80013cc99e9"

-- | Public key
publicKey :: PublicKey
publicKey = "f19293a734d8e9cc89faacb09719e5"

-- | Sandbox secret key
sandboxSecret :: Secret
sandboxSecret = Secret "0d5e0ec25d432388f7fb34d3528394"

-- | Public token
publicToken :: PublicToken
publicToken = PublicToken "public-sandbox-e5c3a0d9-822b-4d8c-bd13-4253485c99b2"

-- | Access token
accessToken :: AccessToken
accessToken =  AccessToken "access-sandbox-9e96926d-4da6-4620-a13b-c72980976436"

-- | Example of item id
itemId :: Text
itemId = "Qlr98nQgkdTQyM8agmjGt3a4RV6lKxup88BLV"

-- | Main function from which we call different api endpoints for demonstration
main :: IO ()
main = do
  let env = PlaidEnv publicKey clientId sandboxSecret Sandbox
  exchangeTokenResponse <- runPlaid env exampleExchangeToken
  pPrint exchangeTokenResponse
  authResponse <- runPlaid env exampleRetrieveAuthRequest
  pPrint authResponse
  transactionsResponse <- runPlaid env exampleRetrieveTransactionsRequest
  pPrint transactionsResponse
  identityResponse <- runPlaid env exampleIdentityRequest
  pPrint identityResponse
  incomeResponse <- runPlaid env exampleIncomeRequest
  pPrint incomeResponse

-- | POST /item/public_token/exchange
--  https://plaid.com/docs/#exchange-token-flow
exampleExchangeToken
  :: ( MonadReader PlaidEnv m
     , MonadIO m
     , MonadThrow m
     , PlaidHttp m
     )
  => m (Either PlaidError PlaidAccessTokenResponse)
exampleExchangeToken = do
  -- get the plaid environment
  env <- ask
  runExceptT $ do
    -- create the public token request body
    -- this action can fail if we provide wrong parameters
    publicTokenBody <- liftEither $
        mkCreatePublicTokenEnv env
          -- Pay attention to provide valid institution id! There is a list of valid ones
          -- in the docs https:://plaid.com/docs/#investments-top-institutions-we-cover
          (InstitutionId "ins_3")
          -- Provide the list of plaid products or empty list
          ["transactions"]
          -- This is optional. If you want you can setup a web-hook where plaid will send its responses.
          defaultPlaidOptions
    -- fire the create public token action
    PlaidPublicTokenResponse {..} <- lift $ plaidCreatePublicToken publicTokenBody
    -- use the response to create an exchange public token request body
    -- it looks something like this:
    -- @
    -- PlaidBody {plaidBodyEnv = PlaidEnv {plaidEnvPublicKey = "f19293a734d8e9cc89faacb09719e5", plaidEnvClientId = ClientId {unClientId = "5d11dd0fdeb8a80013cc99e9"}, plaidEnvSecret = Secret {unSecret = "0d5e0ec25d432388f7fb34d3528394"}, plaidEnvEnvironment = sandbox}, plaidBodyPublicToken = Just (PublicToken {unPublicToken = "public-sandbox-6a6d0da0-4d53-4702-a1eb-9b430625122b"}), plaidBodyAccessToken = Nothing, plaidBodyOptions = Nothing, plaidBodyInstitutionId = Nothing, plaidBodyInitialProducts = Nothing}
    -- @

    exchangeBody <- liftEither (mkExchangePublicTokenEnv env _plaidPublicTokenResponsePublicToken)
    -- fire exchange token action
    lift $ plaidExchangeToken exchangeBody
    -- if the response is successfull it looks something like this:
    -- @
    -- Right (PlaidAccessTokenResponse {plaidAccessTokenResponseAccessToken = "access-sandbox-0ca6b500-c682-437e-bdc9-051665b71941", plaidAccessTokenResponseRequestId = "2vBC1rv95r7Se60", plaidAccessTokenResponseItemId = "mdwNyLvv9zF655lGQ1bxikExVGb4doULb5VPp"})
    -- @
    
getAuthBody
  :: ( MonadReader PlaidEnv m
     , MonadIO m
     , MonadThrow m
     , PlaidHttp m
     )
  => m (Either PlaidError (PlaidBody AuthGet))
getAuthBody = do
  env <- ask
  runExceptT $ do
    publicTokenBody <- liftEither $ createPublicTokenBody env
    PlaidAccessTokenResponse {..} <- lift $ exchangeToken publicTokenBody
    liftEither (mkGetAuthEnv env _plaidAccessTokenResponseAccessToken)

-- | POST /auth/get
-- https://plaid.com/docs/#retrieve-auth-request
exampleRetrieveAuthRequest
  :: ( MonadReader PlaidEnv m
     , MonadIO m
     , MonadThrow m
     , PlaidHttp m
     )
  => m (Either PlaidError ByteString)
exampleRetrieveAuthRequest =
  -- get the plaid environment
  runExceptT $ do
    -- create the public token request body
    -- this action can fail if we provide wrong parameters
    eauthBody <- lift getAuthBody
    authBody <- liftEither eauthBody
    lift $ plaidGetAuth authBody

-- | POST /transactions/get
-- https://plaid.com/docs/#retrieve-transactions-request
exampleRetrieveTransactionsRequest
  :: ( MonadReader PlaidEnv m
     , MonadIO m
     , MonadThrow m
     , PlaidHttp m
     )
  => m (Either PlaidError ByteString)
exampleRetrieveTransactionsRequest = do
  -- get the plaid environment
  env <- ask
  runExceptT $ do
    -- create the public token request body
    -- this action can fail if we provide wrong parameters
    publicTokenBody <- liftEither $ createPublicTokenBody env
    PlaidAccessTokenResponse {..} <- lift $ exchangeToken publicTokenBody
    authBody <- liftEither (mkGetAuthEnv env _plaidAccessTokenResponseAccessToken)
    _ <- lift $ plaidGetAuth authBody
    let startTime = fromGregorian 2018 1 1
        endTime   = fromGregorian 2019 1 1
    transactionBody <-
      liftEither
        (mkCreateTransactionsGetEnv
           env
           _plaidAccessTokenResponseAccessToken
           startTime
           endTime
           Nothing
           (Just defPaginationOptions)
        )
    lift $ plaidGetTransactions transactionBody
-- | POST /income/get
-- http://plaid.com/docs/#income
exampleIncomeRequest
  :: ( MonadReader PlaidEnv m
     , MonadIO m
     , MonadThrow m
     , PlaidHttp m
     )
  => m (Either PlaidError ByteString)
exampleIncomeRequest = do
  env <- ask
  runExceptT $ do
    -- create the public token request body
    -- this action can fail if we provide wrong parameters
    publicTokenBody <- liftEither $ createPublicTokenBody env
    PlaidAccessTokenResponse {..} <- lift $ exchangeToken publicTokenBody
    incomeBody <- liftEither (mkCreateIncomeGetEnv env _plaidAccessTokenResponseAccessToken)
    lift $ plaidGetIncome incomeBody

-- | POST /identity/get
-- http://plaid.com/docs/#identity
exampleIdentityRequest
  :: ( MonadReader PlaidEnv m
     , MonadIO m
     , MonadThrow m
     , PlaidHttp m
     )
  => m (Either PlaidError ByteString)
exampleIdentityRequest = do
  env <- ask
  runExceptT $ do
    -- create the public token request body
    -- this action can fail if we provide wrong parameters
    publicTokenBody <- liftEither $ createPublicTokenBody env
    PlaidAccessTokenResponse {..} <- lift $ exchangeToken publicTokenBody
    identityBody <- liftEither (mkCreateIdentityGetEnv env _plaidAccessTokenResponseAccessToken)
    lift $ plaidGetIdentity identityBody

exchangeToken
  :: ( MonadReader PlaidEnv m
     , MonadIO m
     , MonadThrow m
     , PlaidHttp m
     )
  => PlaidBody PublicTokenCreate
  -> m PlaidAccessTokenResponse
exchangeToken publicTokenBody = do
  env <- ask
  -- fire the create public token action
  PlaidPublicTokenResponse {..} <- plaidCreatePublicToken publicTokenBody
  case mkExchangePublicTokenEnv env _plaidPublicTokenResponsePublicToken of
    Left err           -> throwM err
    Right exchangeBody -> plaidExchangeToken exchangeBody

createPublicTokenBody :: PlaidEnv -> Either PlaidError (PlaidBody PublicTokenCreate)
createPublicTokenBody env =
  mkCreatePublicTokenEnv env
    -- pay attention to provide valid institution id! There is a list of valid ones
    -- in the docs https:://plaid.com/docs/#investments-top-institutions-we-cover
    (InstitutionId "ins_3")
    -- provide the list of plaid products or empty list
    ["transactions"]
    -- this is optional. If you want you can setup a web-hook where plaid will send its responses.
    mempty

defaultPlaidOptions :: Maybe PlaidOptions
defaultPlaidOptions =
  Just $
     PlaidOptions
       { _plaidOptionsWebHook = "http://bogicevicsasa.com"
       , _plaidOptionsOverrideUsername = "user_good"
       , _plaidOptionsOverridePassword = "pass_good"
       }