diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright Author name here (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 Author name here 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/apioiaf-client.cabal b/apioiaf-client.cabal
new file mode 100644
--- /dev/null
+++ b/apioiaf-client.cabal
@@ -0,0 +1,42 @@
+name:                apioiaf-client
+version:             0.1.0.0
+synopsis:            Consumer library for anapioficeandfire.com
+description:         
+  .
+  A wrapper library for consuming the data provided by <anapioficeandfire.com>
+  .
+  See README for API details <https://github.com/kberger/anapioficeandfire-haskell#readme>
+homepage:            https://github.com/kberger/anapioficeandfire-haskell#readme
+license:             BSD3
+license-file:        LICENSE
+author:              Karl Berger
+maintainer:          krab.berger@gmail.com
+copyright:           2016 Karl Berger
+category:            Web
+build-type:          Simple
+-- extra-source-files:
+cabal-version:       >=1.10
+
+library
+  ghc-options:         -Wall
+  hs-source-dirs:      src
+  exposed-modules:     IceAndFire
+  build-depends:       base >= 4.7 && < 5
+                     , wreq
+                     , aeson
+                     , lens
+                     , bytestring
+  default-language:    Haskell2010
+
+test-suite apioiaf-client-test
+  type:                exitcode-stdio-1.0
+  hs-source-dirs:      test
+  main-is:             Spec.hs
+  build-depends:       base
+                     , apioiaf-client
+  ghc-options:         -Wall -threaded -rtsopts -with-rtsopts=-N
+  default-language:    Haskell2010
+
+source-repository head
+  type:     git
+  location: https://github.com/kberger/anapioficeandfire-haskell
diff --git a/src/IceAndFire.hs b/src/IceAndFire.hs
new file mode 100644
--- /dev/null
+++ b/src/IceAndFire.hs
@@ -0,0 +1,227 @@
+{-# LANGUAGE OverloadedStrings, DeriveGeneric #-}
+
+module IceAndFire
+    ( Book(..)
+    , Character(..)
+    , House(..)
+    , getBookById
+    , getCharacterById
+    , getCharactersByName
+    , getCharactersByCulture
+    , getCharactersByGender
+    , getHouseById
+    , getHouseByName
+    ) where
+
+import Network.Wreq
+import Data.Aeson
+import Data.Aeson.Types
+import Data.ByteString.Char8 (unpack)
+import Control.Lens
+
+data Book = Book
+    { bookUrl :: String
+    , bookName :: String
+    , isbn :: String
+    , authors :: [String]
+    , numberOfPages :: Integer
+    , publisher :: String
+    , country :: String
+    , mediaType :: String
+    , released :: String
+    , characters :: [String]
+    , povCharacters :: [String] 
+    } deriving Show
+
+instance FromJSON Book where
+    parseJSON (Object v) = Book <$>
+                           v .: "url" <*>
+                           v .: "name" <*>
+                           v .: "isbn" <*>
+                           v .: "authors" <*>
+                           v .: "numberOfPages" <*>
+                           v .: "publisher" <*>
+                           v .: "country" <*>
+                           v .: "mediaType" <*>
+                           v .: "released" <*>
+                           v .: "characters" <*>
+                           v .: "povCharacters"
+    parseJSON invalid    = typeMismatch "Book" invalid
+
+data Character = Character
+    { charUrl :: String
+    , charName :: String
+    , gender :: String
+    , culture :: String
+    , born :: String
+    , died :: String
+    , charTitles :: [String]
+    , aliases :: [String]
+    , father :: String
+    , mother :: String
+    , spouse :: String
+    , allegiances :: [String]
+    , books :: [String]
+    , povBooks :: [String]
+    , tvSeries :: [String]
+    , playedBy :: [String]
+    } deriving Show
+
+instance FromJSON Character where
+    parseJSON (Object v) = Character <$>
+                           v .: "url" <*>
+                           v .: "name" <*>
+                           v .: "gender" <*>
+                           v .: "culture" <*>
+                           v .: "born" <*>
+                           v .: "died" <*>
+                           v .: "titles" <*>
+                           v .: "aliases" <*>
+                           v .: "father" <*>
+                           v .: "mother" <*>
+                           v .: "spouse" <*>
+                           v .: "allegiances" <*>
+                           v .: "books" <*>
+                           v .: "povBooks" <*>
+                           v .: "tvSeries" <*>
+                           v .: "playedBy"
+    parseJSON invalid    = typeMismatch "Character" invalid
+
+data House = House
+    { houseUrl :: String
+    , houseName :: String
+    , region :: String
+    , coatOfArms :: String
+    , words :: String
+    , houseTitles :: [String]
+    , seats :: [String]
+    , currentLord :: String
+    , heir :: String
+    , overlord :: String
+    , founded :: String
+    , founder :: String
+    , diedOut :: String
+    , ancestralWeapons :: [String]
+    , cadetBranches :: [String]
+    , swornMembers :: [String]
+    } deriving Show
+
+instance FromJSON House where
+    parseJSON (Object v) = House <$>
+                           v .: "url" <*>
+                           v .: "name" <*>
+                           v .: "region" <*>
+                           v .: "coatOfArms" <*>
+                           v .: "words" <*>
+                           v .: "titles" <*>
+                           v .: "seats" <*>
+                           v .: "currentLord" <*>
+                           v .: "heir" <*>
+                           v .: "overlord" <*>
+                           v .: "founded" <*>
+                           v .: "founder" <*>
+                           v .: "diedOut" <*>
+                           v .: "ancestralWeapons" <*>
+                           v .: "cadetBranches" <*>
+                           v .: "swornMembers"
+    parseJSON invalid    = typeMismatch "House" invalid
+
+baseUrl :: String
+baseUrl = "http://www.anapioficeandfire.com/api"
+
+-- | Get Book by id number
+getBookById :: Int -> IO (Maybe Book)
+getBookById = loadSingleById "books"
+
+-- | Get Book by name
+getBookByName :: String -> IO [Book]
+getBookByName bName = entityQuery "books" [("name", bName)]
+
+-- | Get Character by id number
+getCharacterById :: Int -> IO (Maybe Character)
+getCharacterById = loadSingleById "characters"
+
+-- | Get Characters by name
+getCharactersByName :: String -> IO [Character]
+getCharactersByName cName = entityQuery "characters" [("name", cName)]
+
+-- | Get Character by culture
+--
+-- Example:
+--
+-- @
+-- 'getCharactersByCulture' \"dothraki\"
+-- @
+--
+-- >>> d <- getCharactersByCulture "dothraki"
+-- >>> List.length d
+-- 23
+getCharactersByCulture :: String -> IO [Character]
+getCharactersByCulture cCulture = entityQuery "characters" [("culture", cCulture)]
+
+-- | Get Character by gender
+--
+-- Example:
+--
+-- @
+-- 'getCharactersByGender' \"female\"
+-- @
+--
+-- >>> f <- getCharactersByGender "female"
+-- >>> List.length f
+-- 461
+getCharactersByGender :: String -> IO [Character]
+getCharactersByGender cGender = entityQuery "characters" [("gender", cGender)]
+
+-- | Get House by id number
+getHouseById :: Int -> IO (Maybe House)
+getHouseById = loadSingleById "houses"
+
+-- | Get House by name
+getHouseByName :: String -> IO [House]
+getHouseByName hName = entityQuery "houses" [("name", hName)]
+
+-- | Get House by region
+--
+-- Example:
+--
+-- @
+-- 'getHousesByRegion' \"The Crownlands\"
+-- @
+--
+-- >>> c <- getHousesByRegion "The Crownlands"
+-- >>> List.length c
+-- 49
+getHousesByRegion :: String -> IO [House]
+getHousesByRegion hRegion = entityQuery "houses" [("region", hRegion)]
+
+-- | Get a House by its words
+getHouseByWords :: String -> IO [House]
+getHouseByWords hWords = entityQuery "houses" [("hasWords", "true"), ("words", hWords)]
+
+loadSingleById :: (FromJSON a) => String -> Int -> IO (Maybe a)
+loadSingleById entityType entityId = do
+    response <- get (baseUrl ++ "/" ++ entityType ++ "/" ++ (show entityId) :: String)
+    let entityJson = decode (view responseBody response)
+    return entityJson
+
+--Mainly used to control common query paramaters like pageSize
+--Probably where caching should go
+entityQuery :: (FromJSON a) => String -> [(String,String)] -> IO [a]
+entityQuery entityType qParams = 
+    loadFromQueryUrl (baseUrl ++ "/" ++ entityType ++ "/?pageSize=50" ++ paramsToStr qParams)
+        where paramsToStr = foldl (\ acc (k,v) -> acc ++ "&" ++ k ++ "=" ++ v) ""
+
+loadFromQueryUrl :: (FromJSON a) => String -> IO [a]
+loadFromQueryUrl url = do
+    response <- get url
+    let entity = decode (view responseBody response)
+    let unpacked = case entity of (Just [])   -> []
+                                  (Just list) -> list
+                                  Nothing     -> []
+    -- Greedily consume and append 'next' links until none more
+    let nextLink = (response ^? responseLink "rel" "next" . linkURL)
+    let next = case nextLink of (Just linkUrl) -> loadFromQueryUrl (unpack linkUrl)
+                                Nothing        -> return ([] :: [a])
+    nextList <- next
+    return (unpacked ++ nextList)
diff --git a/test/Spec.hs b/test/Spec.hs
new file mode 100644
--- /dev/null
+++ b/test/Spec.hs
@@ -0,0 +1,2 @@
+main :: IO ()
+main = putStrLn "Test suite not yet implemented"
