diff --git a/mackerel-client.cabal b/mackerel-client.cabal
--- a/mackerel-client.cabal
+++ b/mackerel-client.cabal
@@ -1,5 +1,5 @@
 name:                   mackerel-client
-version:                0.0.2
+version:                0.0.3
 author:                 itchyny
 maintainer:             itchyny <https://github.com/itchyny>
 license:                MIT
@@ -29,6 +29,7 @@
                       , Web.Mackerel.Types.Monitor
                       , Web.Mackerel.Types.Alert
                       , Web.Mackerel.Types.Dashboard
+                      , Web.Mackerel.Types.GraphAnnotation
                       , Web.Mackerel.Api
                       , Web.Mackerel.Api.Organization
                       , Web.Mackerel.Api.User
@@ -38,11 +39,12 @@
                       , Web.Mackerel.Api.Monitor
                       , Web.Mackerel.Api.Alert
                       , Web.Mackerel.Api.Dashboard
+                      , Web.Mackerel.Api.GraphAnnotation
                       , Web.Mackerel.Client
                       , Web.Mackerel.Config
   other-modules:        Web.Mackerel.Internal.TH
                       , Web.Mackerel.Internal.Api
-  build-depends:        base >= 4.7 && < 5.0
+  build-depends:        base >= 4.9 && < 5.0
                       , filepath
                       , directory
                       , http-types
@@ -71,7 +73,7 @@
                       , Types.AlertSpec
                       , Types.DashboardSpec
                       , ConfigSpec
-  build-depends:        base >= 4.7 && < 5.0
+  build-depends:        base >= 4.9 && < 5.0
                       , mackerel-client
                       , aeson
                       , aeson-qq
diff --git a/src/Web/Mackerel/Api.hs b/src/Web/Mackerel/Api.hs
--- a/src/Web/Mackerel/Api.hs
+++ b/src/Web/Mackerel/Api.hs
@@ -2,6 +2,7 @@
 
 import Web.Mackerel.Api.Alert as Api
 import Web.Mackerel.Api.Dashboard as Api
+import Web.Mackerel.Api.GraphAnnotation as Api
 import Web.Mackerel.Api.Host as Api
 import Web.Mackerel.Api.Monitor as Api
 import Web.Mackerel.Api.Organization as Api
diff --git a/src/Web/Mackerel/Api/GraphAnnotation.hs b/src/Web/Mackerel/Api/GraphAnnotation.hs
new file mode 100644
--- /dev/null
+++ b/src/Web/Mackerel/Api/GraphAnnotation.hs
@@ -0,0 +1,39 @@
+{-# LANGUAGE OverloadedStrings, TemplateHaskell #-}
+-- | GraphAnnotation API.
+module Web.Mackerel.Api.GraphAnnotation
+  ( listGraphAnnotations
+  , createGraphAnnotation
+  , updateGraphAnnotation
+  , deleteGraphAnnotation
+  ) where
+
+import Data.Aeson.TH (deriveJSON)
+import qualified Data.ByteString.Char8 as BS
+import Data.Semigroup ((<>))
+import Network.HTTP.Types (StdMethod(..))
+
+import Web.Mackerel.Client
+import Web.Mackerel.Internal.Api
+import Web.Mackerel.Internal.TH
+import Web.Mackerel.Types.GraphAnnotation
+
+data ListGraphAnnotationsResponse = ListGraphAnnotationsResponse { responseGraphAnnotations :: [GraphAnnotation] }
+$(deriveJSON options ''ListGraphAnnotationsResponse)
+
+listGraphAnnotations :: Client -> String -> Integer -> Integer -> IO (Either ApiError [GraphAnnotation])
+listGraphAnnotations client service from to = do
+  let query = [ ("service", Just $ BS.pack service), ("from", Just $ BS.pack $ show from), ("to", Just $ BS.pack $ show to) ]
+  request client GET "/api/v0/graph-annotations" query emptyBody (createHandler responseGraphAnnotations)
+
+createGraphAnnotation :: Client -> GraphAnnotation -> IO (Either ApiError GraphAnnotation)
+createGraphAnnotation client graphAnnotation
+  = request client POST "/api/v0/graph-annotations" [] (Just graphAnnotation) (createHandler id)
+
+updateGraphAnnotation :: Client -> GraphAnnotation -> IO (Either ApiError GraphAnnotation)
+updateGraphAnnotation client graphAnnotation = do
+  let Just (GraphAnnotationId graphAnnotationId') = graphAnnotationId graphAnnotation
+  request client PUT ("/api/v0/graph-annotations/" <> BS.pack graphAnnotationId') [] (Just graphAnnotation) (createHandler id)
+
+deleteGraphAnnotation :: Client -> GraphAnnotationId -> IO (Either ApiError GraphAnnotation)
+deleteGraphAnnotation client (GraphAnnotationId graphAnnotationId')
+  = request client DELETE ("/api/v0/graph-annotations/" <> BS.pack graphAnnotationId') [] emptyBody (createHandler id)
diff --git a/src/Web/Mackerel/Types.hs b/src/Web/Mackerel/Types.hs
--- a/src/Web/Mackerel/Types.hs
+++ b/src/Web/Mackerel/Types.hs
@@ -2,6 +2,7 @@
 
 import Web.Mackerel.Types.Alert as Types
 import Web.Mackerel.Types.Dashboard as Types
+import Web.Mackerel.Types.GraphAnnotation as Types
 import Web.Mackerel.Types.Host as Types
 import Web.Mackerel.Types.Monitor as Types
 import Web.Mackerel.Types.Organization as Types
diff --git a/src/Web/Mackerel/Types/GraphAnnotation.hs b/src/Web/Mackerel/Types/GraphAnnotation.hs
new file mode 100644
--- /dev/null
+++ b/src/Web/Mackerel/Types/GraphAnnotation.hs
@@ -0,0 +1,38 @@
+{-# LANGUAGE TemplateHaskell #-}
+module Web.Mackerel.Types.GraphAnnotation where
+
+import Data.Aeson
+import qualified Data.Aeson as Aeson
+import Data.Aeson.TH (deriveJSON, fieldLabelModifier)
+import Data.Aeson.Types (typeMismatch)
+import Data.Char (toLower)
+import Data.Default (Default(..))
+import qualified Data.Text as Text
+
+import Web.Mackerel.Internal.TH
+
+data GraphAnnotationId = GraphAnnotationId String
+                       deriving (Eq, Show)
+
+instance FromJSON GraphAnnotationId where
+  parseJSON (Aeson.String graphAnnotationId') = return $ GraphAnnotationId $ Text.unpack graphAnnotationId'
+  parseJSON o = typeMismatch "GraphAnnotationId" o
+
+instance ToJSON GraphAnnotationId where
+  toJSON (GraphAnnotationId graphAnnotationId') = toJSON graphAnnotationId'
+
+data GraphAnnotation
+  = GraphAnnotation {
+    graphAnnotationId :: Maybe GraphAnnotationId,
+    graphAnnotationTitle :: String,
+    graphAnnotationDescription :: String,
+    graphAnnotationFrom :: Integer,
+    graphAnnotationTo :: Integer,
+    graphAnnotationService :: String,
+    graphAnnotationRoles :: Maybe [String]
+  } deriving (Eq, Show)
+
+instance Default GraphAnnotation where
+  def = GraphAnnotation def def def def def def def
+
+$(deriveJSON options { fieldLabelModifier = (\(c:cs) -> toLower c : cs) . drop 15 } ''GraphAnnotation)
diff --git a/src/Web/Mackerel/Types/Monitor.hs b/src/Web/Mackerel/Types/Monitor.hs
--- a/src/Web/Mackerel/Types/Monitor.hs
+++ b/src/Web/Mackerel/Types/Monitor.hs
@@ -40,6 +40,34 @@
 instance ToJSON MonitorOperator where
   toJSON op = toJSON (show op)
 
+data MonitorExternalMethod = MonitorExternalMethodGET
+                           | MonitorExternalMethodPOST
+                           | MonitorExternalMethodPUT
+                           | MonitorExternalMethodDELETE
+                           deriving Eq
+
+instance Show MonitorExternalMethod where
+  show MonitorExternalMethodGET = "GET"
+  show MonitorExternalMethodPOST = "POST"
+  show MonitorExternalMethodPUT = "PUT"
+  show MonitorExternalMethodDELETE = "DELETE"
+
+instance Read MonitorExternalMethod where
+  readsPrec _ xs = [ (hs, drop (length str) xs) | (hs, str) <- pairs', take (length str) xs == str ]
+    where pairs' = [(MonitorExternalMethodGET, "GET"), (MonitorExternalMethodPOST, "POST"), (MonitorExternalMethodPUT, "PUT"), (MonitorExternalMethodDELETE, "DELETE")]
+
+instance FromJSON MonitorExternalMethod where
+  parseJSON (Aeson.String txt)
+    | str == "GET" = return MonitorExternalMethodGET
+    | str == "POST" = return MonitorExternalMethodPOST
+    | str == "PUT" = return MonitorExternalMethodPUT
+    | str == "DELETE" = return MonitorExternalMethodDELETE
+    where str = Text.unpack txt
+  parseJSON o = typeMismatch "MonitorExternalMethod" o
+
+instance ToJSON MonitorExternalMethod where
+  toJSON method = toJSON (show method)
+
 data MonitorExternalHeader
   = MonitorExternalHeader {
     monitorHeaderName :: String,
@@ -95,7 +123,10 @@
   | MonitorExternal {
     monitorId :: Maybe MonitorId,
     monitorName :: String,
+    monitorMethod :: Maybe MonitorExternalMethod,
     monitorUrl :: String,
+    monitorRequestBody :: Maybe String,
+    monitorHeaders :: Maybe [MonitorExternalHeader],
     monitorServiceOption :: Maybe String,
     monitorResponseTimeDuration :: Maybe Double,
     monitorResponseTimeWarning :: Maybe Double,
@@ -105,7 +136,6 @@
     monitorCertificationExpirationWarning :: Maybe Integer,
     monitorCertificationExpirationCritical :: Maybe Integer,
     monitorSkipCertificateVerification :: Maybe Bool,
-    monitorHeaders :: Maybe [MonitorExternalHeader],
     monitorIsMute :: Maybe Bool,
     monitorNotificationInterval :: Maybe Integer
   }
diff --git a/test/Types/MonitorSpec.hs b/test/Types/MonitorSpec.hs
--- a/test/Types/MonitorSpec.hs
+++ b/test/Types/MonitorSpec.hs
@@ -92,7 +92,10 @@
   let externalMonitor = MonitorExternal {
         monitorId = Just $ MonitorId "abcde4",
         monitorName = "Example external monitor",
+        monitorMethod = Just MonitorExternalMethodGET,
         monitorUrl = "https://example.com",
+        monitorRequestBody = Just "Request Body",
+        monitorHeaders = Just [MonitorExternalHeader "Cache-Control" "no-cache"],
         monitorServiceOption = Just "service1",
         monitorResponseTimeDuration = Just 5,
         monitorResponseTimeWarning = Just 3000,
@@ -102,7 +105,6 @@
         monitorCertificationExpirationWarning = Just 1200,
         monitorCertificationExpirationCritical = Just 60,
         monitorSkipCertificateVerification = Just True,
-        monitorHeaders = Just [MonitorExternalHeader "Cache-Control" "no-cache"],
         monitorIsMute = Just True,
         monitorNotificationInterval = Just 60
       }
@@ -112,7 +114,10 @@
       "type": "external",
       "id": "abcde4",
       "name": "Example external monitor",
+      "method": "GET",
       "url": "https://example.com",
+      "requestBody": "Request Body",
+      "headers": [{ "name": "Cache-Control", "value": "no-cache" }],
       "service": "service1",
       "responseTimeDuration": 5,
       "responseTimeWarning": 3000,
@@ -122,7 +127,6 @@
       "certificationExpirationWarning": 1200,
       "certificationExpirationCritical": 60,
       "skipCertificateVerification": true,
-      "headers": [{ "name": "Cache-Control", "value": "no-cache" }],
       "isMute": true,
       "notificationInterval": 60
     }
