diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,5 @@
+# Revision history for stooq
+
+## 0.1.0.0 -- 2022-03-30
+
+* Initial release.
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2022 Alojzy Leszcz
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/src/lib/Web/Data/Stooq/API.hs b/src/lib/Web/Data/Stooq/API.hs
new file mode 100644
--- /dev/null
+++ b/src/lib/Web/Data/Stooq/API.hs
@@ -0,0 +1,96 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+-- | Here's a simple wrapper around API offered by Stooq.pl.
+-- It's capable of returning the latest price for the given instrument.
+-- For more information about tickers available, visit the service.
+-- Keep in mind that in some situations their ticker convention is different to what's known e.g. from Yahoo Finance
+-- e.g.
+--
+-- xxxx.UK: London Stock Exchange (LSE)
+--
+-- xxxx.US: NYSE (OTC market not available, so a lot of ADRs like `OGZPY` or `SBRCY` can't be fetched)
+--
+-- xxxx.DE: Deutsche Börse
+--
+-- xxxx: (no exchange code after full stop) Warsaw Stock Exchange (GPW)
+--
+-- Use:
+--
+-- >>> fetch "SPY.US"
+-- Just [StooqPrice {symbol = "SPY.US", time = ..., ...}]
+module Web.Data.Stooq.API where
+
+import Control.Lens ((^.))
+import Data.Text (Text, unpack)
+import Data.Time.Calendar (fromGregorian, Day)
+import Data.Time.Clock (UTCTime(..))
+import Data.Time.LocalTime (LocalTime(LocalTime), TimeOfDay(TimeOfDay), TimeZone, localTimeToUTC, hoursToTimeZone)
+import Network.Wreq (get, responseBody)
+
+import qualified Web.Data.Stooq.Internals as Impl
+
+-- | A single-case DU that represents a ticker.
+newtype StooqSymbol = StooqSymbol String
+    deriving (Show, Read, Eq, Ord)
+
+-- | A type representing market price data returned by Stooq.
+data StooqPrice =
+    StooqPrice {
+        symbol  :: String,
+        time    :: UTCTime,
+        open    :: Double,
+        high    :: Double,
+        low     :: Double,
+        close   :: Double,
+        volume  :: Int,
+        openint :: Int
+    } deriving Show
+
+-- | Sends a request for the specified ticker and returns its latest price.
+-- Returns "Nothing" if the response is invalid (this is most likely due to using a non-existent ticker).
+fetchPrice :: StooqSymbol -> IO (Maybe [StooqPrice])
+fetchPrice ticker = do
+    r <- get (queryUrl ticker)
+    return $ fmap (map toApiType . Impl.symbols) (Impl.parseResponse (r ^. responseBody))
+
+    where
+        baseUrl :: String
+        baseUrl = "https://stooq.pl/q/l/?s="
+
+        queryUrl :: StooqSymbol -> String
+        queryUrl (StooqSymbol ticker) = baseUrl ++ ticker ++ "&e=json"
+
+        toApiType :: Impl.StooqRow -> StooqPrice
+        toApiType row = StooqPrice {
+            symbol  = (unpack . Impl.symbol) row,
+            time    = localTimeToUTC stooqTimeZone $ LocalTime ((stooqIntToDay . Impl.date) row) ((stooqStringToTime . unpack . Impl.time) row),
+            open    = Impl.open row,
+            high    = Impl.high row,
+            low     = Impl.low row,
+            close   = Impl.close row,
+            volume  = Impl.volume row,
+            openint = Impl.openint row
+        }
+
+        stooqIntToDay :: Int -> Day
+        stooqIntToDay date = fromGregorian (toInteger $ (date `div` 10000) `mod` 10000) ((date `div` 100) `mod` 100) (date `mod` 100)
+
+        stooqStringToTime :: String -> TimeOfDay
+        stooqStringToTime [h1,h2,m1,m2,s1,s2] = TimeOfDay (read [h1,h2]) (read [m1,m2]) (read [s1,s2])
+        stooqStringToTime x = error $ "Unexpected time format: " ++ x
+
+        stooqTimeZone :: TimeZone
+        stooqTimeZone = hoursToTimeZone 1
+
+-- | Sends a request for multiple tickers at once.
+-- The function makes only a single HTTP call.
+fetchPrices :: [StooqSymbol] -> IO (Maybe [StooqPrice])
+fetchPrices tickers = fetchPrice (concatTickers tickers)
+    where
+        concatTickers :: [StooqSymbol] -> StooqSymbol
+        concatTickers = foldl1 (\(StooqSymbol t1) (StooqSymbol t2) -> StooqSymbol (t1 ++ " " ++ t2))
+
+-- | A shorthand around "fetchPrice" that allows to call the function using a plain String, without converting it to a `StooqSymbol` first.
+fetch :: String -> IO (Maybe [StooqPrice])
+fetch = fetchPrice . StooqSymbol
+    
diff --git a/src/utils/Web/Data/Stooq/Internals.hs b/src/utils/Web/Data/Stooq/Internals.hs
new file mode 100644
--- /dev/null
+++ b/src/utils/Web/Data/Stooq/Internals.hs
@@ -0,0 +1,32 @@
+{-# LANGUAGE DeriveGeneric #-}
+
+module Web.Data.Stooq.Internals where
+
+import Data.Aeson (FromJSON, decode)
+import Data.ByteString.Lazy.Internal (ByteString)
+import Data.Text (Text)
+import GHC.Generics (Generic)
+
+data StooqRow =
+    StooqRow {
+        symbol  :: !Text,
+        date    :: Int,
+        time    :: !Text,
+        open    :: Double,
+        high    :: Double,
+        low     :: Double,
+        close   :: Double,
+        volume  :: Int,
+        openint :: Int
+    } deriving (Show, Generic)
+
+data StooqResponse =
+    StooqResponse {
+        symbols :: [StooqRow]
+    } deriving (Show, Generic)
+
+instance FromJSON StooqRow
+instance FromJSON StooqResponse
+
+parseResponse :: ByteString -> Maybe StooqResponse
+parseResponse = decode
diff --git a/stooq-api.cabal b/stooq-api.cabal
new file mode 100644
--- /dev/null
+++ b/stooq-api.cabal
@@ -0,0 +1,47 @@
+cabal-version:      >= 2.0
+
+name:               stooq-api
+version:            0.1.0.0
+synopsis:           A simple wrapper around stooq.pl API for downloading market data.
+description:
+  Here's a simple wrapper around API offered by Stooq.pl.
+  It's capable of returning the latest price for the given instrument.
+  .
+  For more information about tickers available, visit the service.
+
+bug-reports:        https://github.com/bratfizyk/stooq-api/issues
+license:            MIT
+license-file:       LICENSE
+author:             Alojzy Leszcz
+maintainer:         alojzy.leszcz@gmail.com
+category:           Web
+build-type:         Simple
+extra-source-files: CHANGELOG.md
+Source-repository head
+  type:     git
+  location: https://github.com/bratfizyk/stooq-api
+
+library stooq-api-utils
+  exposed-modules:    Web.Data.Stooq.Internals
+  build-depends:      base,
+                      aeson,
+                      bytestring,
+                      text,
+                      time
+  hs-source-dirs:     src/utils
+  default-language:   Haskell2010
+
+library
+    exposed-modules:  Web.Data.Stooq.API
+    build-depends:    base          >= 4.13     && < 4.15,
+                      bytestring    >= 0.10.10  && < 0.11,
+                      aeson         >= 1.5.6    && < 1.6,
+                      lens          >= 4.18.1   && < 5.1,
+                      text          >= 1.2      && < 1.3,
+                      time          >= 1.9.3    && < 1.10,
+                      utf8-string   >= 1.0.2    && < 1.1,
+                      vector        >= 0.12.1   && < 0.13,
+                      wreq          >= 0.5.3    && < 0.6,
+                      stooq-api-utils
+    hs-source-dirs:   src/lib
+    default-language: Haskell2010
