diff --git a/openai-hs.cabal b/openai-hs.cabal
--- a/openai-hs.cabal
+++ b/openai-hs.cabal
@@ -4,10 +4,10 @@
 --
 -- see: https://github.com/sol/hpack
 --
--- hash: bc145a17f925189f4d8d879579d0e37dc7d796a46ca6bb0303538c1f3f2c1f16
+-- hash: 8f7d9bff4fa5f43dad386049b3579aaa96e640a7ad21fddc4cd1338daa0c972b
 
 name:           openai-hs
-version:        0.1.1.0
+version:        0.2.0.0
 synopsis:       Unofficial OpenAI client
 description:    Unofficial OpenAI client
 category:       Web
@@ -39,6 +39,7 @@
   build-depends:
       aeson
     , base >=4.7 && <5
+    , bytestring
     , casing
     , cpphs
     , http-client
@@ -46,6 +47,7 @@
     , openai-servant
     , servant
     , servant-client
+    , servant-multipart
     , text
   default-language: Haskell2010
 
@@ -76,6 +78,7 @@
     , servant
     , servant-client
     , servant-client-core
+    , servant-multipart
     , text
     , vector
   default-language: Haskell2010
diff --git a/src/OpenAI/Client.hs b/src/OpenAI/Client.hs
--- a/src/OpenAI/Client.hs
+++ b/src/OpenAI/Client.hs
@@ -16,6 +16,12 @@
     -- * Searching
   , SearchResult(..), SearchResultCreate(..)
   , searchDocuments
+    -- * File API
+  , FileCreate(..), File(..), FileId(..), FileHunk(..)
+  , FileDeleteConfirmation(..)
+  , createFile, deleteFile
+    -- * Answer API
+  , getAnswer, AnswerReq(..), AnswerResp(..)
   )
 where
 
@@ -27,8 +33,10 @@
 import Network.HTTP.Client (Manager)
 import Servant.API
 import Servant.Client
+import qualified Data.ByteString.Lazy as BSL
 import qualified Data.Text as T
 import qualified Data.Text.Encoding as T
+import qualified Servant.Multipart as MP
 
 -- | Your OpenAI API key. Can be obtained from the OpenAI dashboard. Format: @sk-<redacted>@
 type ApiKey = T.Text
@@ -77,8 +85,20 @@
 EP0(listEngines, (OpenAIList Engine))
 EP(getEngine, EngineId, Engine)
 
-listEngines'
+createFile :: OpenAIClient -> FileCreate -> IO (Either ClientError File)
+createFile sc rfc =
+  do bnd <- MP.genBoundary
+     createFileInternal sc (bnd, rfc)
+
+EP(createFileInternal, (BSL.ByteString, FileCreate), File)
+EP(deleteFile, FileId, FileDeleteConfirmation)
+
+EP(getAnswer, AnswerReq, AnswerResp)
+
+(listEngines'
   :<|> getEngine'
   :<|> completeText'
-  :<|> searchDocuments'
+  :<|> searchDocuments')
+  :<|> (createFileInternal' :<|> deleteFile')
+  :<|> getAnswer'
   = client api
diff --git a/test/ApiSpec.hs b/test/ApiSpec.hs
--- a/test/ApiSpec.hs
+++ b/test/ApiSpec.hs
@@ -29,17 +29,52 @@
 apiTests :: SpecWith ()
 apiTests =
   beforeAll makeClient $
-  do describe "engines" $
+  do describe "file api" $
+       do it "allows creating one" $ \cli ->
+            do let file =
+                     FileCreate
+                     { fcPurpose = "search"
+                     , fcDocuments = [FileHunk "Test 1" Nothing, FileHunk "text 2" (Just "foo")]
+                     }
+               res <- forceSuccess $ createFile cli file
+               _ <- forceSuccess $ deleteFile cli (fId res)
+               pure ()
+     describe "answer api" $
+       do it "works" $ \cli ->
+            do let file =
+                     FileCreate
+                     { fcPurpose = "search"
+                     , fcDocuments =
+                         [ FileHunk "Cities in California: San Francisco, Los Angeles" (Just "cali")
+                         , FileHunk "Tasty fruit: Apple, Orange" (Just "fruit")
+                         , FileHunk "Cities in Germany: Freiburg, Berlin" (Just "germany")
+                         ]
+                     }
+               res <- forceSuccess $ createFile cli file
+               let searchReq =
+                     AnswerReq
+                     { arFile = Just (fId res)
+                     , arDocuments = Nothing
+                     , arQuestion = "Where is San Francisco?"
+                     , arSearchModel = EngineId "babbage"
+                     , arModel = EngineId "davinci"
+                     , arExamplesContext = "Good programming languages: Haskell, PureScript"
+                     , arExamples = [["Is PHP a good programming language?", "No, sorry."]]
+                     , arReturnMetadata = True
+                     }
+               answerRes <- forceSuccess $ getAnswer cli searchReq
+               T.unpack (head (arsAnswers answerRes)) `shouldContain` ("California" :: String)
+               _ <- forceSuccess $ deleteFile cli (fId res)
+               pure ()
+     describe "engines" $
        do it "lists engines" $ \cli ->
             do res <- forceSuccess $ listEngines cli
                V.null (olData res) `shouldBe` False
-          -- TODO: This doesn't work for some reason, even the cURL example from the docs fail.
-          --it "retrieve engine" $ \cli ->
-          --  do engineList <- forceSuccess $ listEngines cli
-          --     print engineList
-          --     let firstEngine = V.head (olData engineList)
-          --     engine <- forceSuccess $ getEngine cli (eId firstEngine)
-          --     engine `shouldBe` firstEngine
+          it "retrieve engine" $ \cli ->
+            do engineList <- forceSuccess $ listEngines cli
+               let firstEngine = V.head (olData engineList)
+               engine <- forceSuccess $ getEngine cli (eId firstEngine)
+               engine `shouldBe` firstEngine
      describe "text completion" $
        do it "works (smoke test)" $ \cli ->
             do firstEngine <- V.head . olData <$> forceSuccess (listEngines cli)
@@ -57,7 +92,34 @@
                  forceSuccess $
                  searchDocuments cli (eId firstEngine) $
                  SearchResultCreate
-                 { sccrDocuments = V.fromList ["pool", "gym", "night club"]
+                 { sccrDocuments = Just $ V.fromList ["pool", "gym", "night club"]
+                 , sccrFile = Nothing
                  , sccrQuery = "swimmer"
+                 , sccrReturnMetadata = False
                  }
                V.length (olData searchResults) `shouldBe` 3
+     describe "file based document search" $
+       do it "works" $ \cli ->
+            do let file =
+                     FileCreate
+                     { fcPurpose = "search"
+                     , fcDocuments =
+                         [ FileHunk "pool" (Just "pool")
+                         , FileHunk "gym" (Just "gym")
+                         , FileHunk "night club" (Just "nc")
+                         ]
+                     }
+               createRes <- forceSuccess $ createFile cli file
+               let searchReq =
+                     SearchResultCreate
+                     { sccrFile = Just (fId createRes)
+                     , sccrDocuments = Nothing
+                     , sccrQuery = "pool"
+                     , sccrReturnMetadata = True
+                     }
+               searchRes <- forceSuccess $ searchDocuments cli (EngineId "ada") searchReq
+               let res = V.head (olData searchRes)
+               srDocument res `shouldBe` 0 -- pool
+               srMetadata res `shouldBe` Just "pool"
+               _ <- forceSuccess $ deleteFile cli (fId createRes)
+               pure ()
