diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c) 2015, Matthew Wraith
+
+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 Matthew Wraith 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/prosper.cabal b/prosper.cabal
new file mode 100644
--- /dev/null
+++ b/prosper.cabal
@@ -0,0 +1,48 @@
+-- Initial prosper.cabal generated by cabal init.  For further 
+-- documentation, see http://haskell.org/cabal/users-guide/
+
+name:                prosper
+version:             0.1.0.0
+synopsis:            Bindings to the Prosper marketplace API
+-- description:         
+homepage:            https://api.prosper.com
+license:             BSD3
+license-file:        LICENSE
+author:              Matthew Wraith
+maintainer:          wraithm@gmail.com
+copyright:           (c) 2015 Matthew Wraith
+category:            Finance
+build-type:          Simple
+cabal-version:       >=1.10
+
+library
+  exposed-modules:     
+    Prosper, 
+    Prosper.Account, 
+    Prosper.Listing, 
+    Prosper.User, 
+    Prosper.Note, 
+    Prosper.Money, 
+    Prosper.Commands, 
+    Prosper.Invest,
+    Prosper.Internal.Request, 
+    Prosper.Internal.JSON, 
+    Prosper.Internal.CSV
+
+  build-depends:       
+    base >=4.8 && <4.9, 
+    transformers >=0.4 && <0.5, 
+    text >=1.2 && <1.3, 
+    bytestring >=0.10 && <0.11, 
+    mtl >=2.2 && <2.3, 
+    containers >=0.5 && <0.6,
+    vector,
+    aeson,
+    cereal,
+    io-streams,
+    HsOpenSSL,
+    http-streams
+
+
+  hs-source-dirs:      src
+  default-language:    Haskell2010
diff --git a/src/Prosper.hs b/src/Prosper.hs
new file mode 100644
--- /dev/null
+++ b/src/Prosper.hs
@@ -0,0 +1,50 @@
+-- | These are bindings to the Prosper marketplace API.
+-- The documentation for the API can be seen at
+-- https://api.prosper.com/.
+module Prosper
+    (
+    -- * Commands
+      invest
+    , account
+    , allListings
+    , notes
+    , listingFromNote
+
+    , AccountException (..)
+
+    -- * User
+    , User (..)
+
+    -- * Account
+    , Account (..)
+    , emptyAccount
+
+    -- * Listing
+    , Listing (..)
+    , Offer (..)
+    , Credit (..)
+    , Rating (..)
+    , Category (..)
+    , Status (..)
+
+    -- * Note
+    , NoteStatus (..)
+    , NoteDefaultReason (..)
+    , Note (..)
+
+    -- * Invest
+    , InvestStatus (..)
+    , InvestMessage (..)
+    , InvestResponse (..)
+
+    -- * Types
+    , Money
+    ) where
+
+import           Prosper.Account
+import           Prosper.Commands
+import           Prosper.Invest
+import           Prosper.Listing
+import           Prosper.Money
+import           Prosper.Note
+import           Prosper.User
diff --git a/src/Prosper/Account.hs b/src/Prosper/Account.hs
new file mode 100644
--- /dev/null
+++ b/src/Prosper/Account.hs
@@ -0,0 +1,53 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module Prosper.Account
+    ( Account (..)
+    , emptyAccount
+    ) where
+
+import           Control.Applicative ((<$>), (<*>))
+import           Control.Monad       (mzero)
+
+import           Data.Aeson
+
+import           Prosper.Money
+
+-- | A data structure for holding account information for Prosper
+data Account = Account
+    { availableCash                   :: !Money
+      -- ^ Available cash for investing
+    , pendingInvestments              :: !Money
+      -- ^ Amount of money invested that is pending origination
+    , totPrincipalRecvdOnActiveNotes  :: !Money
+      -- ^ Total principal payments received on active notes
+    , totalInvestedOnActiveNotes      :: !Money
+      -- ^ Total amount invested
+    , outstandingPrincipalActiveNotes :: !Money
+      -- ^ Total principal outstanding on active notes
+    , -- | Total dollars held in investible cash,
+      -- pending orders in the market, outstanding principal
+      totalAccountValue               :: !Money
+    , pendingInvestmentsSecondaryMkt  :: !Money
+      -- ^ Investments on Folio
+    , pendingQuickInvestOrders        :: !Money
+      -- ^ Prosper Quick Invests
+    } deriving (Show, Eq)
+
+-- | An empty account. All values are zero.
+emptyAccount :: Account
+emptyAccount = Account 0 0 0 0 0 0 0 0
+
+-- | Parser for account info
+--
+-- Located at api/Account
+instance FromJSON Account where
+    parseJSON (Object v) = Account
+        <$> v .: "AvailableCashBalance"
+        <*> v .: "PendingInvestmentsPrimaryMkt"
+        <*> v .: "TotalPrincipalReceivedOnActiveNotes"
+        <*> v .: "TotalAmountInvestedOnActiveNotes"
+        <*> v .: "OutstandingPrincipalOnActiveNotes"
+        <*> v .: "TotalAccountValue"
+        <*> v .: "PendingInvestmentsSecondaryMkt"
+        <*> v .: "PendingQuickInvestOrders"
+    parseJSON _ = mzero
diff --git a/src/Prosper/Commands.hs b/src/Prosper/Commands.hs
new file mode 100644
--- /dev/null
+++ b/src/Prosper/Commands.hs
@@ -0,0 +1,77 @@
+{-# LANGUAGE DeriveDataTypeable #-}
+{-# LANGUAGE OverloadedStrings  #-}
+
+module Prosper.Commands
+    ( invest
+    , account
+    , allListings
+    , notes
+    , listingFromNote
+
+    , listingCSV
+
+    , AccountException (..)
+    ) where
+
+import           Control.Exception     (Exception, throwIO)
+import           Control.Monad         (when)
+
+import           Data.ByteString.Char8 as C
+import           Data.Maybe            (listToMaybe)
+import           Data.Monoid           ((<>))
+import           Data.Typeable         (Typeable)
+import           Data.Vector           (Vector)
+
+import           Network.Http.Client
+import           System.IO.Streams     (InputStream)
+
+import           Prosper.Account
+import           Prosper.Internal.JSON
+import           Prosper.Internal.CSV
+import           Prosper.Invest
+import           Prosper.Listing
+import           Prosper.Money
+import           Prosper.Note
+import           Prosper.User
+
+-- | An investment request. This requires a 'User', an amount of 'Money', and a 'Listing'.
+invest :: User -> Money -> Listing -> IO InvestResponse
+invest user amt l = investRequest user (listingId l) amt
+
+-- | Request 'Account' information from Prosper
+account :: User -> IO Account
+account user = jsonGetHandler user "Account" accountHandler
+  where
+    accountHandler resp is =
+        if getStatusCode resp == 500
+            then throwIO (AccountException (getStatusMessage resp))
+            else jsonHandler resp is
+
+-- | Used as a hack around the 500 Critical Exception error
+data AccountException = AccountException ByteString
+    deriving (Typeable, Show)
+
+instance Exception AccountException
+
+-- | Request notes for a Prosper user
+notes :: User -> IO (Vector Note)
+notes user = jsonGet user "Notes"
+
+-- | Given a 'Note', look up the associated 'Listing' by the ListingId
+listingFromNote :: User -> Note -> IO (Maybe Listing)
+listingFromNote user (Note { listingNumber = lid }) = do
+    ls <- jsonGet user command
+    return $ listToMaybe ls
+  where
+    command = "ListingsHistorical?$filter=ListingNumber eq " <> C.pack (show lid)
+
+-- | Send a request to the Listings end-point at Prosper
+allListings :: User -> IO (Vector Listing)
+allListings user = jsonGet user "Listings"
+
+-- | Request a particular 'Listing' via the CSV endpoint
+listingCSV :: User -> Listing -> (InputStream ByteString -> IO a) -> IO a
+listingCSV user l = csvGetStream user url
+  where
+    lid = listingId l
+    url = "Listings?$filter=ListingNumber%20eq%20" <> C.pack (show lid)
diff --git a/src/Prosper/Internal/CSV.hs b/src/Prosper/Internal/CSV.hs
new file mode 100644
--- /dev/null
+++ b/src/Prosper/Internal/CSV.hs
@@ -0,0 +1,31 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module Prosper.Internal.CSV
+    ( csvGet
+    , csvGetStream
+    ) where
+
+import           Network.Http.Client
+import           System.IO.Streams     (InputStream)
+
+import           Data.ByteString       (ByteString)
+
+import           Prosper.Money
+import           Prosper.User
+import           Prosper.Internal.Request
+
+-- | Make a GET request to Prosper's CSV api, return the raw CSV data
+csvGet
+    :: User -- ^ The user name and password for the prosper user
+    -> ByteString -- ^ The name of the API service, relative to the API url
+    -> IO ByteString -- ^ Raw CSV response
+csvGet userInfo url = issueRequest userInfo url GET "text/csv" concatHandler []
+
+-- | Make a GET request to Prosper's CSV api, return the raw CSV data
+csvGetStream
+    :: User -- ^ The user name and password for the prosper user
+    -> ByteString -- ^ The name of the API service, relative to the API url
+    -> (InputStream ByteString -> IO a)
+    -> IO a -- ^ Raw CSV response
+csvGetStream userInfo url handler =
+    issueRequest userInfo url GET "text/csv" (\_ is -> handler is) []
diff --git a/src/Prosper/Internal/JSON.hs b/src/Prosper/Internal/JSON.hs
new file mode 100644
--- /dev/null
+++ b/src/Prosper/Internal/JSON.hs
@@ -0,0 +1,49 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module Prosper.Internal.JSON
+    ( jsonGet
+    , jsonGetHandler
+    , investRequest
+    ) where
+
+import           Network.Http.Client
+import           System.IO.Streams        (InputStream)
+
+import           Data.Aeson               (FromJSON)
+import           Data.ByteString          (ByteString)
+import qualified Data.ByteString.Char8    as C
+import           Data.Monoid              ((<>))
+
+import           Prosper.Internal.Request
+import           Prosper.Invest
+import           Prosper.Money
+import           Prosper.User
+
+-- | Make a GET request to Prosper's JSON api, return the parsed JSON data
+jsonGet
+    :: FromJSON a
+    => User -- ^ The user name and password for the prosper user
+    -> ByteString -- ^ The name of the API service, relative to the API url
+    -> IO a -- ^ JSON response
+jsonGet userInfo url =
+    issueRequest userInfo url GET "application/json" jsonHandler []
+
+jsonGetHandler
+    :: FromJSON a
+    => User -- ^ The user name and password for the prosper user
+    -> ByteString -- ^ The name of the API service, relative to the API url
+    -> (Response -> InputStream ByteString -> IO a)
+    -> IO a -- ^ JSON response
+jsonGetHandler userInfo url handler =
+    issueRequest userInfo url GET "application/json" handler []
+
+investRequest
+    :: User
+    -> Int -- ^ The listing id
+    -> Money -- ^ Amount
+    -> IO InvestResponse -- ^ JSON response from Prosper
+investRequest userInfo listingId amount =
+    issueRequest userInfo "Invest" POST "application/x-www-form-urlencoded" jsonHandler
+        [ ("listingId", C.pack $ show listingId)
+        , ("amount", C.pack $ show amount)
+        ]
diff --git a/src/Prosper/Internal/Request.hs b/src/Prosper/Internal/Request.hs
new file mode 100644
--- /dev/null
+++ b/src/Prosper/Internal/Request.hs
@@ -0,0 +1,39 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module Prosper.Internal.Request where
+
+import           Network.Http.Client
+import           OpenSSL
+import           System.IO.Streams     (InputStream)
+
+import           Data.ByteString       (ByteString)
+import qualified Data.ByteString.Char8 as C
+import           Data.Monoid           ((<>))
+
+import           Prosper.User
+
+apiUrl :: ByteString
+apiUrl = "api.prosper.com"
+
+issueRequest
+    :: User
+    -> ByteString
+    -> Method
+    -> ContentType
+    -> (Response -> InputStream ByteString -> IO a)
+    -> [(ByteString, ByteString)]
+    -> IO a
+issueRequest (User user pass) url method ct handler params = withOpenSSL $ do
+    ctx <- baselineContextSSL
+    con <- openConnectionSSL ctx apiUrl 443
+    req <- buildRequest $ do
+        http method $ "/api/" <> url
+        setAuthorizationBasic user pass
+        setContentType ct
+    sendRequest con req (setBody params)
+    resp <- receiveResponse con handler
+    closeConnection con
+    return resp
+  where
+    setBody [] = emptyBody
+    setBody xs = encodedFormBody xs
diff --git a/src/Prosper/Invest.hs b/src/Prosper/Invest.hs
new file mode 100644
--- /dev/null
+++ b/src/Prosper/Invest.hs
@@ -0,0 +1,107 @@
+{-# LANGUAGE DeriveGeneric     #-}
+{-# LANGUAGE OverloadedStrings #-}
+
+module Prosper.Invest
+    ( InvestStatus (..)
+    , InvestMessage (..)
+    , InvestResponse (..)
+    ) where
+
+import           Control.Applicative (pure, (<$>), (<*>))
+import           Control.Monad       (mzero)
+
+import           Data.Aeson          hiding (Error, Success)
+import           Data.Serialize
+import           Data.Text.Read      as R
+
+import           GHC.Generics
+
+import           Prosper.Money
+
+-- | Status of an invest request
+data InvestStatus
+    = Success
+    | Failed
+    | Error
+    | PartialSuccess
+    deriving (Show, Eq, Read, Generic)
+
+-- | Status of Invest request response JSON parser
+instance FromJSON InvestStatus where
+    parseJSON (String "SUCCESS") = pure Success
+    parseJSON (String "FAILED") = pure Failed
+    parseJSON (String "ERROR") = pure Error
+    parseJSON (String "PARTIAL_SUCCESS") = pure PartialSuccess
+    parseJSON _ = mzero
+
+instance Serialize InvestStatus where
+
+-- | Message associated with an error
+data InvestMessage
+    = NoError
+    | InternalError
+    | InvestedAmountLessThanRequested
+    | ListingNotAvailable
+    | ListingNotFound
+    | InsufficientFunds
+    | ListingClosedBeforeBidPlaced
+    | ServerBusy
+    | SuitabilityRequirementsNotMet
+    | InvestedAmountLessThanMinimumRequired
+    | OtherError -- ^ Not in the prosper docs, this is a catch all
+    deriving (Show, Eq, Read, Generic)
+
+-- | Parser for message in an error
+instance FromJSON InvestMessage where
+    parseJSON (String "NO_ERROR") = pure NoError
+    parseJSON (String "INTERNAL_ERROR") = pure InternalError
+    parseJSON (String "INVESTED_AMOUNT_LESS_THAN_REQUESTED") =
+        pure InvestedAmountLessThanRequested
+    parseJSON (String "LISTING_NOT_AVAILABLE") = pure ListingNotAvailable
+    parseJSON (String "LISTING_NOT_FOUND") = pure ListingNotFound
+    parseJSON (String "INSUFFICIENT_FUNDS") = pure InsufficientFunds
+    parseJSON (String "NOT_ENOUGH_BALANCE_AVAILABLE") = pure InsufficientFunds -- Isn't in the Prosper Docs
+    parseJSON (String "LISTING_CLOSED_BEFORE_BID_PLACED") =
+        pure ListingClosedBeforeBidPlaced
+    parseJSON (String "SERVER_BUSY") = pure ServerBusy
+    parseJSON (String "SUITABILITY_REQUIREMENTS_NOT_MET") =
+        pure SuitabilityRequirementsNotMet
+    parseJSON (String "INVESTED_AMOUNT_LESS_THAN_MINIMUM_REQUIRED") =
+        pure InvestedAmountLessThanMinimumRequired
+    parseJSON _ = pure OtherError
+
+instance Serialize InvestMessage where
+
+-- | JSON response to an invest request
+data InvestResponse = InvestResponse
+    { investStatus    :: InvestStatus
+    , requestedAmount :: Money
+    , investListingId :: Int
+    , investMessage   :: InvestMessage
+    , amountInvested  :: Money
+    } deriving (Show, Generic)
+
+newtype Money' = MkMoney { unMoney :: Money } deriving (Eq, Generic)
+
+instance Show Money' where
+    show (MkMoney x) = show x
+
+instance FromJSON Money' where
+    parseJSON (String x) = readDouble x
+      where
+        readDouble y = case R.double y of
+            Right (z,_) -> pure $ MkMoney z
+            Left _ -> mzero
+    parseJSON _ = mzero
+
+-- | Parser for invest request response on api/Invest
+instance FromJSON InvestResponse where
+    parseJSON (Object v) = InvestResponse
+        <$> v .: "Status"
+        <*> (unMoney <$> v .: "RequestedAmount")
+        <*> v .: "ListingId"
+        <*> v .: "Message"
+        <*> (unMoney <$> v .: "AmountInvested")
+    parseJSON _ = mzero
+
+instance Serialize InvestResponse where
diff --git a/src/Prosper/Listing.hs b/src/Prosper/Listing.hs
new file mode 100644
--- /dev/null
+++ b/src/Prosper/Listing.hs
@@ -0,0 +1,241 @@
+{-# LANGUAGE DeriveDataTypeable #-}
+{-# LANGUAGE DeriveGeneric      #-}
+{-# LANGUAGE OverloadedStrings  #-}
+
+module Prosper.Listing
+    ( Listing(..)
+    , Offer(..)
+    , Credit(..)
+    , Rating(..)
+    , Category(..)
+    , Status(..)
+    ) where
+
+import           Control.Applicative (pure, (<$>), (<*>))
+import           Control.Monad       (mzero)
+
+import           Data.Aeson
+import           Data.Text.Read      as R
+import           Data.Typeable
+import           GHC.Generics
+
+import           Prosper.Money
+
+data Listing = Listing
+    { listingId       :: !Int
+    , status          :: !Status
+    , rating          :: !Rating -- ^ Letter score assigned by Prosper
+    , score           :: !(Maybe Int) -- ^ Prosper score
+    , category        :: !Category -- ^ The reason for the loan (e.g. Auto, Student, etc)
+
+    -- Market data
+    , amountRemaining :: !Money
+
+    , offer           :: !Offer -- ^ Contract data
+    , credit          :: !Credit -- ^ Credit data
+    } deriving Show
+--     investmentType :: (Fractional | Whole)
+
+-- | Two 'Listing's are equivalent if their 'listingId's are equal
+instance Eq Listing where
+    (Listing { listingId = id1 }) == (Listing { listingId = id2 }) =
+        id1 == id2
+
+-- | Data related to the listing's offer and contract terms
+data Offer = Offer
+    { requestAmount  :: !Money
+    , rate           :: !Double -- ^ Interest rate for the borrower
+    , termInMonths   :: !Int -- ^ Integer number of months
+    , yield          :: !Double
+    , effectiveYield :: !Double
+    , apr            :: !Double -- ^ APR for the borrower
+    } deriving Show
+--     estimatedLossRate :: Double -- Maybe Money?
+--     estimatedReturn :: Double -- Maybe Money?
+--     startDate       :: Date -- Add dates later
+--     creationDate    :: Date
+--     verificationStage :: Maybe Int -- Don't know what VerificationStage is...
+--     Add WholeLoanStartDate and WholeLoanEndDate
+
+-- | Data related to the credibility of the listing
+data Credit = Credit
+    { fico                     :: !Int
+    , bankcardUtilization      :: !Double
+    , isHomeowner              :: !Bool
+    , debtToIncome             :: !Double
+    , monthsEmployed           :: !(Maybe Int)
+    , currentDelinquencies     :: !(Maybe Int)
+    , amountDelinquent         :: !(Maybe Money)
+    , openCreditLines          :: !(Maybe Int)
+    , totOpenRevolvingAccts    :: !(Maybe Int)
+    , revolvingBalance         :: !(Maybe Money)
+    , revolvingAvailableCredit :: !(Maybe Int) -- ^ Percent
+    , incomeRange              :: !(Maybe (Money, Money)) -- ^ It is possible that they're unemployed, that's Nothing
+    , statedMonthlyIncome      :: !(Maybe Money)
+    , currentCreditLines       :: !(Maybe Int)
+    , nowDelinquentDerog       :: !(Maybe Int)
+    , wasDelinquentDerog       :: !(Maybe Int)
+    } deriving Show
+--     firstCreditLine :: Date
+--     creditLinesLast7Years :: Int
+--     inquiriesLast6Months :: Int
+--     delinquenciesLast7Years :: Int -- These are maybe too specific to Prosper
+--     publicRecordsLast10Years :: Int
+--     oldestTradeOpenDate :: Date
+
+-- | Parse a 'Listing' from JSON
+instance FromJSON Listing where
+    parseJSON (Object v) = Listing
+            <$> v .: "ListingNumber" -- Is listingid?
+
+            -- Prosper-specific data
+            <*> v .: "ListingStatus"
+            <*> v .: "ProsperRating"
+            <*> v .:? "ProsperScore"
+            <*> v .: "ListingCategory"
+
+            <*> v .: "AmountRemaining"
+
+            <*> (Offer
+            <$> v .: "ListingRequestAmount"
+            <*> v .: "BorrowerRate"
+            <*> v .: "ListingTerm"
+            <*> v .: "LenderYield"
+            <*> v .: "EffectiveYield"
+            <*> v .: "BorrowerAPR")
+
+            <*> (Credit
+            <$> (unFico <$> v .: "FICOScore")
+            <*> v .: "BankcardUtilization"
+            <*> v .: "IsHomeowner"
+            <*> v .: "DTIwProsperLoan"
+            <*> v .:? "MonthsEmployed"
+            <*> v .:? "CurrentDelinquencies"
+            <*> v .:? "AmountDelinquent"
+            <*> v .:? "OpenCreditLines"
+            <*> v .:? "TotalOpenRevolvingAccounts"
+            <*> v .:? "RevolvingBalance"
+            <*> v .:? "RevolvingAvailablePercent"
+            -- Prosper credit data
+            <*> (unIR <$> v .: "IncomeRange")
+            <*> v .:? "StatedMonthlyIncome"
+            <*> v .:? "CurrentCreditLines"
+            <*> v .:? "NowDelinquentDerog"
+            <*> v .:? "WasDelinquentDerog")
+    parseJSON _ = mzero
+
+-- Prosper's API is really weird and has the FICO type as a String
+-- in JSON.
+newtype FICO = FICO { unFico :: Int } 
+    deriving Eq
+
+instance Show FICO where
+    show (FICO x) = show x
+
+instance FromJSON FICO where
+    parseJSON (String s) = readInt s
+      where
+        readInt x = case R.decimal x of
+            Right (y,_) -> pure $ FICO y
+            Left _ -> mzero
+    parseJSON _ = mzero
+
+newtype IncomeRange = IR { unIR :: Maybe (Money, Money) } 
+    deriving Eq
+
+instance Show IncomeRange where
+    show (IR (Just (l, h))) = "$" ++ show l ++ "-$" ++ show h
+    show (IR Nothing) = "Not displayed or unemployed"
+
+instance FromJSON IncomeRange where
+    parseJSON (Number 0) = pure $ IR Nothing -- Not displayed
+    parseJSON (Number 1) = pure $ IR (Just (0, 0)) -- Make $0
+    parseJSON (Number 2) = pure $ IR (Just (1, 24999))
+    parseJSON (Number 3) = pure $ IR (Just (25000, 49999))
+    parseJSON (Number 4) = pure $ IR (Just (50000, 74999))
+    parseJSON (Number 5) = pure $ IR (Just (75000, 99999))
+    parseJSON (Number 6) = pure $ IR (Just (100000, 500000)) -- DOCTHIS 500,000 is just an arbitrary high value
+    parseJSON (Number 7) = pure $ IR Nothing -- Unemployed
+    parseJSON _ = pure $ IR Nothing
+
+-- | Prosper ratings, 'AA' is the most credible. 'HR' is the least credible.
+data Rating
+    = HR
+    | E
+    | D
+    | C
+    | B
+    | A
+    | AA
+    deriving (Show, Eq, Ord, Typeable, Generic, Read, Enum)
+
+instance FromJSON Rating where
+instance ToJSON Rating where
+
+-- | The 'Category' of a loan is the type of loan.
+-- This is basically copied verbatim from the Prosper API.
+data Category
+    = NotAvailable
+    | DebtConsolidation
+    | HomeImprovement
+    | Business
+    | PersonalLoan
+    | StudentUse
+    | Auto
+    | Other
+    | BabyAdoptionLoans
+    | Boat
+    | CosmeticProcedures
+    | EngagementRingFinancing
+    | GreenLoans
+    | HouseholdExpenses
+    | LargePurchases
+    | MedicalDental
+    | Motorcycle
+    | RV
+    | Taxes
+    | Vacation
+    | WeddingLoans
+    deriving (Show, Eq, Typeable, Generic, Read)
+
+instance FromJSON Category where
+    parseJSON (Number 0) = pure NotAvailable
+    parseJSON (Number 1) = pure DebtConsolidation
+    parseJSON (Number 2) = pure HomeImprovement
+    parseJSON (Number 3) = pure Business
+    parseJSON (Number 4) = pure PersonalLoan
+    parseJSON (Number 5) = pure StudentUse
+    parseJSON (Number 6) = pure Auto
+    parseJSON (Number 7) = pure Other
+    parseJSON (Number 8) = pure BabyAdoptionLoans
+    parseJSON (Number 9) = pure Boat
+    parseJSON (Number 10) = pure CosmeticProcedures
+    parseJSON (Number 11) = pure EngagementRingFinancing
+    parseJSON (Number 12) = pure GreenLoans
+    parseJSON (Number 13) = pure HouseholdExpenses
+    parseJSON (Number 14) = pure LargePurchases
+    parseJSON (Number 15) = pure MedicalDental
+    parseJSON (Number 16) = pure Motorcycle
+    parseJSON (Number 17) = pure RV
+    parseJSON (Number 18) = pure Taxes
+    parseJSON (Number 19) = pure Vacation
+    parseJSON (Number 20) = pure WeddingLoans
+    parseJSON _ = pure Other
+
+data Status
+    = Active
+    | Withdrawn
+    | Expired
+    | ListingCompleted
+    | ListingCancelled
+    | Pending
+    deriving (Show, Eq, Typeable, Generic)
+
+instance FromJSON Status where
+    parseJSON (Number 2) = pure Active
+    parseJSON (Number 4) = pure Withdrawn
+    parseJSON (Number 5) = pure Expired
+    parseJSON (Number 6) = pure ListingCompleted
+    parseJSON (Number 7) = pure ListingCancelled
+    parseJSON (Number 8) = pure Pending
+    parseJSON _ = mzero
diff --git a/src/Prosper/Money.hs b/src/Prosper/Money.hs
new file mode 100644
--- /dev/null
+++ b/src/Prosper/Money.hs
@@ -0,0 +1,3 @@
+module Prosper.Money where
+
+type Money = Double
diff --git a/src/Prosper/Note.hs b/src/Prosper/Note.hs
new file mode 100644
--- /dev/null
+++ b/src/Prosper/Note.hs
@@ -0,0 +1,120 @@
+{-# LANGUAGE DeriveGeneric     #-}
+{-# LANGUAGE OverloadedStrings #-}
+
+module Prosper.Note 
+    ( NoteStatus (..)
+    , NoteDefaultReason (..)
+    , Note (..)
+    ) where
+
+import           Control.Applicative (pure, (<$>), (<*>))
+
+import           Data.Aeson
+import           Data.Text
+
+import           GHC.Generics
+
+import           Prosper.Listing     (Rating (..))
+import           Prosper.Money
+
+data NoteStatus
+    = OriginationDelayed
+    | Current
+    | ChargeOff
+    | Defaulted
+    | NoteCompleted
+    | FinalPaymentInProgress
+    | NoteCancelled
+    deriving (Show, Eq)
+
+instance ToJSON NoteStatus where
+    toJSON OriginationDelayed = Number 0
+    toJSON Current = Number 1
+    toJSON ChargeOff = Number 2
+    toJSON Defaulted = Number 3
+    toJSON NoteCompleted = Number 4
+    toJSON FinalPaymentInProgress = Number 5
+    toJSON NoteCancelled = Number 6
+
+instance FromJSON NoteStatus where
+    parseJSON (Number 0) = pure OriginationDelayed
+    parseJSON (Number 1) = pure Current
+    parseJSON (Number 2) = pure ChargeOff
+    parseJSON (Number 3) = pure Defaulted
+    parseJSON (Number 4) = pure NoteCompleted
+    parseJSON (Number 5) = pure FinalPaymentInProgress
+    parseJSON (Number 6) = pure NoteCancelled
+    parseJSON _ = fail "Could not parse NoteStatus"
+
+data NoteDefaultReason
+    = Delinquency
+    | Bankruptcy
+    | Deceased
+    | Repurchased
+    | PaidInFull
+    | SettledInFull
+    deriving (Show, Eq)
+
+instance ToJSON NoteDefaultReason where
+    toJSON Delinquency = Number 1
+    toJSON Bankruptcy = Number 2
+    toJSON Deceased = Number 3
+    toJSON Repurchased = Number 4
+    toJSON PaidInFull = Number 5
+    toJSON SettledInFull = Number 6
+
+instance FromJSON NoteDefaultReason where
+    parseJSON (Number 1) = pure Delinquency
+    parseJSON (Number 2) = pure Bankruptcy
+    parseJSON (Number 3) = pure Deceased
+    parseJSON (Number 4) = pure Repurchased
+    parseJSON (Number 5) = pure PaidInFull
+    parseJSON (Number 6) = pure SettledInFull
+    parseJSON _ = fail "Could not parse NoteDefaultReason"
+
+data Note = Note
+    { loanNoteId          :: Text
+    , listingNumber       :: Int
+    , amountParticipation :: Money
+    , totalAmountBorrowed :: Money
+    , borrowerRate        :: Double
+    , noteRating          :: Rating
+    , term                :: Int
+    , ageInMonths         :: Int
+--     , originationDate :: Date
+    , daysPastDue         :: Int
+    , principalBalance    :: Money
+    , principalRepaid     :: Money
+    , interestPaid        :: Money
+    , serviceFees         :: Money
+    , prosperFees         :: Money
+    , lateFees            :: Money
+    -- groupLeaderReward
+    , noteStatus          :: NoteStatus
+    , noteDefaultReason   :: Maybe NoteDefaultReason
+    , isSold              :: Bool
+    } deriving (Show, Eq, Generic)
+
+instance FromJSON Note where
+    parseJSON (Object v) = Note
+        <$> v .: "LoanNoteID"
+        <*> v .: "ListingNumber"
+        <*> v .: "AmountParticipation"
+        <*> v .: "TotalAmountBorrowed"
+        <*> v .: "BorrowerRate"
+        <*> v .: "ProsperRating"
+        <*> v .: "Term"
+        <*> v .: "AgeInMonths"
+        <*> v .: "DaysPastDue"
+        <*> v .: "PrincipalBalance"
+        <*> v .: "PrincipalRepaid"
+        <*> v .: "InterestPaid"
+        <*> v .: "ServiceFees"
+        <*> v .: "ProsperFees"
+        <*> v .: "LateFees"
+        <*> v .: "NoteStatus"
+        <*> v .:? "NoteDefaultReason"
+        <*> v .: "IsSold"
+    parseJSON _ = fail "Could not parse Note"
+
+instance ToJSON Note where
diff --git a/src/Prosper/User.hs b/src/Prosper/User.hs
new file mode 100644
--- /dev/null
+++ b/src/Prosper/User.hs
@@ -0,0 +1,16 @@
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE RecordWildCards   #-}
+
+module Prosper.User
+    ( User(..)
+    ) where
+
+import           Control.Monad             (when)
+
+import           Data.ByteString           (ByteString)
+
+-- | User info for Prosper data
+data User = User
+    { username :: !ByteString -- ^ Username for Prosper
+    , password :: !ByteString -- ^ Password for Prosper
+    } deriving (Show, Eq)
