diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -34,3 +34,18 @@
 ## 0.4.1 -- 2022-04-22
 
 * Relax various constraints
+
+## 0.4.1 -- 2022-04-22
+
+* Add new datatype Result
+* Fix the following endpoints to produce 'Result' rather than NoContent
+    * apiTriggerAxfr
+    * apiNotifySlaves
+    * apiGetZoneAxfr
+    * apiRectifyZone
+* Fix the following client functions similarly:
+    * triggerAxfr
+    * notifySlaves
+    * getZoneAxfr
+    * rectifyZone
+* Improve compilation time by switching to TH for JSON instances
diff --git a/PowerDNS/API.hs b/PowerDNS/API.hs
--- a/PowerDNS/API.hs
+++ b/PowerDNS/API.hs
@@ -4,9 +4,9 @@
 --
 -- This module exports a complete servant API description of the PowerDNS. May be useful to some.
 
-{-# LANGUAGE DataKinds #-}
-{-# LANGUAGE TypeOperators #-}
+{-# LANGUAGE DataKinds     #-}
 {-# LANGUAGE DeriveGeneric #-}
+{-# LANGUAGE TypeOperators #-}
 module PowerDNS.API
   ( API
   , api
@@ -20,18 +20,17 @@
   )
 where
 
-import           GHC.Generics (Generic)
-import           Data.Proxy (Proxy(..))
+import Data.Proxy (Proxy(..))
+import GHC.Generics (Generic)
 
-import           Servant.API
-import           Servant.API.Generic ((:-), ToServantApi)
+import Servant.API
 
-import           PowerDNS.API.Version
-import           PowerDNS.API.Zones
-import           PowerDNS.API.Servers
-import           PowerDNS.API.Cryptokeys
-import           PowerDNS.API.Metadata
-import           PowerDNS.API.TSIGKeys
+import PowerDNS.API.Cryptokeys
+import PowerDNS.API.Metadata
+import PowerDNS.API.Servers
+import PowerDNS.API.TSIGKeys
+import PowerDNS.API.Version
+import PowerDNS.API.Zones
 
 api :: Proxy API
 api = Proxy
@@ -46,4 +45,3 @@
   , metadata   :: f :- "api" :> "v1" :> ToServantApi MetadataAPI
   , tsigkeys   :: f :- "api" :> "v1" :> ToServantApi TSIGKeysAPI
   } deriving Generic
-
diff --git a/PowerDNS/API/Cryptokeys.hs b/PowerDNS/API/Cryptokeys.hs
--- a/PowerDNS/API/Cryptokeys.hs
+++ b/PowerDNS/API/Cryptokeys.hs
@@ -9,6 +9,7 @@
 {-# LANGUAGE DeriveDataTypeable #-}
 {-# LANGUAGE DeriveGeneric      #-}
 {-# LANGUAGE TypeOperators      #-}
+{-# LANGUAGE TemplateHaskell    #-}
 module PowerDNS.API.Cryptokeys
   (
   -- * API
@@ -22,9 +23,9 @@
 import           Data.Data (Data)
 
 import           Control.DeepSeq (NFData)
-import           Data.Aeson (FromJSON(..), ToJSON(..), defaultOptions,
-                             fieldLabelModifier, genericParseJSON,
-                             genericToJSON)
+import           Data.Aeson.TH (defaultOptions,
+                             fieldLabelModifier,
+                             deriveJSON)
 import qualified Data.Text as T
 import           Servant.API
 import           Servant.API.Generic
@@ -66,8 +67,4 @@
     , ck_bits :: Maybe Integer
     } deriving (Eq, Ord, Show, Generic, NFData, Data, Empty)
 
-instance ToJSON Cryptokey where
-  toJSON = genericToJSON defaultOptions { fieldLabelModifier = strip "ck_"}
-
-instance FromJSON Cryptokey where
-  parseJSON = genericParseJSON defaultOptions { fieldLabelModifier = strip "ck_"}
+$(deriveJSON defaultOptions { fieldLabelModifier = strip "ck_"} ''Cryptokey)
diff --git a/PowerDNS/API/Metadata.hs b/PowerDNS/API/Metadata.hs
--- a/PowerDNS/API/Metadata.hs
+++ b/PowerDNS/API/Metadata.hs
@@ -9,6 +9,7 @@
 {-# LANGUAGE DeriveDataTypeable #-}
 {-# LANGUAGE DeriveGeneric      #-}
 {-# LANGUAGE TypeOperators      #-}
+{-# LANGUAGE TemplateHaskell    #-}
 module PowerDNS.API.Metadata
   (
   -- * API
@@ -20,10 +21,9 @@
 where
 
 import           Control.DeepSeq (NFData)
-import           Data.Aeson ( FromJSON(..), ToJSON(..)
-                            , defaultOptions, fieldLabelModifier
-                            , genericParseJSON, genericToJSON
-                            )
+import           Data.Aeson.TH ( defaultOptions, fieldLabelModifier
+                               , deriveJSON
+                               )
 
 import           Data.Data (Data)
 import qualified Data.Text as T
@@ -56,8 +56,4 @@
   , md_metadata :: [T.Text]
   } deriving (Eq, Ord, Show, Generic, NFData, Data)
 
-instance ToJSON Metadata where
-  toJSON = genericToJSON defaultOptions { fieldLabelModifier = strip "md_"}
-
-instance FromJSON Metadata where
-  parseJSON = genericParseJSON defaultOptions { fieldLabelModifier = strip "md_"}
+$(deriveJSON defaultOptions { fieldLabelModifier = strip "md_" } ''Metadata)
diff --git a/PowerDNS/API/Servers.hs b/PowerDNS/API/Servers.hs
--- a/PowerDNS/API/Servers.hs
+++ b/PowerDNS/API/Servers.hs
@@ -6,6 +6,7 @@
 
 {-# LANGUAGE DataKinds          #-}
 {-# LANGUAGE DeriveAnyClass     #-}
+{-# LANGUAGE TemplateHaskell    #-}
 {-# LANGUAGE DeriveDataTypeable #-}
 {-# LANGUAGE DeriveGeneric      #-}
 {-# LANGUAGE TypeOperators      #-}
@@ -34,13 +35,12 @@
 import           Text.Read (readMaybe)
 
 import           Control.DeepSeq (NFData)
-import           Data.Aeson (FromJSON(..), ToJSON(..), defaultOptions
-                            , Value(String)
+import           Data.Aeson.TH (defaultOptions
                             , fieldLabelModifier, constructorTagModifier
-                            , genericParseJSON
+                            , deriveJSON
                             , allNullaryToStringTag
-                            , genericToJSON
-                            , (.:), (.=)
+                            )
+import           Data.Aeson (FromJSON(..), ToJSON(..), Value(String), (.:), (.=)
                             , withObject, object
                             )
 import           Data.Aeson.Types (Parser)
@@ -52,32 +52,6 @@
 
 ----------------------------------------------------------------------------------------
 
-type QueryParamReq = QueryParam' [Required, Strict]
-data ServersAPI f = ServersAPI
-  { apiListServers :: f :- "servers"
-                        :> Get '[JSON] [Server]
-
-  , apiGetServer   :: f :- "servers" :> Capture "server_id" T.Text
-                        :> Get '[JSON] Server
-
-  , apiSearch      :: f :- "servers" :> Capture "server_id" T.Text :> "search-data"
-                        :> QueryParamReq "q" T.Text
-                        :> QueryParamReq "max" Integer
-                        :> QueryParam "object_type" ObjectType
-                        :> Get '[JSON] [SearchResult]
-
-  , apiFlushCache  :: f :- "servers" :> Capture "server_id" T.Text
-                        :> QueryParamReq "domain" T.Text
-                        :> Put '[JSON] CacheFlushResult
-
-  , apiStatistics  :: f :- "servers" :> Capture "server_id" T.Text :> "statistics"
-                        :> QueryParam "statistic" T.Text
-                        :> QueryParam "includerings" Bool
-                        :> Get '[JSON] [AnyStatisticItem]
-  } deriving Generic
-
-----------------------------------------------------------------------------------------
-
 data Server = Server
   { server_type :: Maybe T.Text
   , server_id :: Maybe T.Text
@@ -88,45 +62,18 @@
   , server_zones_url :: Maybe T.Text
   } deriving (Eq, Ord, Show, Generic, NFData, Data, Empty)
 
-instance ToJSON Server where
-  toJSON = genericToJSON defaultOptions { fieldLabelModifier = strip "server_"}
-
-instance FromJSON Server where
-  parseJSON = genericParseJSON defaultOptions { fieldLabelModifier = strip "server_"}
+$(deriveJSON defaultOptions { fieldLabelModifier = strip "server_" } ''Server)
 
 ----------------------------------------------------------------------------------------
 
-data SearchResult = SearchResult
-  { sr_content :: T.Text
-  , sr_disabled :: Bool
-  , sr_name :: T.Text
-  , sr_object_type :: ObjectType
-  , sr_zone_id :: T.Text
-  , sr_zone :: T.Text
-  , sr_type :: T.Text
-  , sr_ttl :: Integer
-  } deriving (Eq, Ord, Show, Generic, NFData, Data)
-
-instance ToJSON SearchResult where
-  toJSON = genericToJSON defaultOptions { fieldLabelModifier = strip "sr_"}
-
-instance FromJSON SearchResult where
-  parseJSON = genericParseJSON defaultOptions { fieldLabelModifier = strip "sr_"}
-
-----------------------------------------------------------------------------------------
 data ObjectType = TyAll
                 | TyZone
                 | TyRecord
                 | TyComment
                 deriving (Eq, Ord, Show, Generic, NFData, Data)
 
-instance ToJSON ObjectType where
-  toJSON = genericToJSON defaultOptions { constructorTagModifier = map1 toLower . strip "Ty"
-                                        , allNullaryToStringTag = True }
-
-instance FromJSON ObjectType where
-  parseJSON = genericParseJSON defaultOptions { constructorTagModifier = map1 toLower . strip "Ty"
-                                              , allNullaryToStringTag = True }
+$(deriveJSON defaultOptions { constructorTagModifier = map1 toLower . strip "Ty"
+                            , allNullaryToStringTag = True } ''ObjectType)
 
 instance FromHttpApiData ObjectType where
   parseQueryParam "all" = Right TyAll
@@ -143,17 +90,37 @@
 
 ----------------------------------------------------------------------------------------
 
+data SearchResult = SearchResult
+  { sr_content :: T.Text
+  , sr_disabled :: Bool
+  , sr_name :: T.Text
+  , sr_object_type :: ObjectType
+  , sr_zone_id :: T.Text
+  , sr_zone :: T.Text
+  , sr_type :: T.Text
+  , sr_ttl :: Integer
+  } deriving (Eq, Ord, Show, Generic, NFData, Data)
+
+$(deriveJSON defaultOptions { fieldLabelModifier = strip "sr_" } ''SearchResult)
+
+----------------------------------------------------------------------------------------
+
 data CacheFlushResult = CacheFlushResult
   { cfr_count :: Integer
   , cfr_result :: T.Text
   } deriving (Eq, Ord, Show, Generic, NFData, Data)
 
-instance ToJSON CacheFlushResult where
-  toJSON = genericToJSON defaultOptions { fieldLabelModifier = strip "cfr_"}
+$(deriveJSON defaultOptions { fieldLabelModifier = strip "cfr_" } ''CacheFlushResult)
 
-instance FromJSON CacheFlushResult where
-  parseJSON = genericParseJSON defaultOptions { fieldLabelModifier = strip "cfr_"}
+----------------------------------------------------------------------------------------
 
+data SimpleStatisticItem = SimpleStatisticItem
+  { ssi_name :: T.Text
+  , ssi_value :: T.Text
+  } deriving (Eq, Ord, Show, Generic, NFData, Data)
+
+$(deriveJSON defaultOptions { fieldLabelModifier = strip "ssi_" } ''SimpleStatisticItem)
+
 ----------------------------------------------------------------------------------------
 
 data AnyStatisticItem = AnyStatisticItem StatisticItem
@@ -211,13 +178,28 @@
   , rsi_value :: [SimpleStatisticItem]
   } deriving (Eq, Ord, Show, Generic, NFData, Data)
 
-data SimpleStatisticItem = SimpleStatisticItem
-  { ssi_name :: T.Text
-  , ssi_value :: T.Text
-  } deriving (Eq, Ord, Show, Generic, NFData, Data)
+----------------------------------------------------------------------------------------
 
-instance ToJSON SimpleStatisticItem where
-  toJSON = genericToJSON defaultOptions { fieldLabelModifier = strip "ssi_"}
+type QueryParamReq = QueryParam' [Required, Strict]
+data ServersAPI f = ServersAPI
+  { apiListServers :: f :- "servers"
+                        :> Get '[JSON] [Server]
 
-instance FromJSON SimpleStatisticItem where
-  parseJSON = genericParseJSON defaultOptions { fieldLabelModifier = strip "ssi_"}
+  , apiGetServer   :: f :- "servers" :> Capture "server_id" T.Text
+                        :> Get '[JSON] Server
+
+  , apiSearch      :: f :- "servers" :> Capture "server_id" T.Text :> "search-data"
+                        :> QueryParamReq "q" T.Text
+                        :> QueryParamReq "max" Integer
+                        :> QueryParam "object_type" ObjectType
+                        :> Get '[JSON] [SearchResult]
+
+  , apiFlushCache  :: f :- "servers" :> Capture "server_id" T.Text
+                        :> QueryParamReq "domain" T.Text
+                        :> Put '[JSON] CacheFlushResult
+
+  , apiStatistics  :: f :- "servers" :> Capture "server_id" T.Text :> "statistics"
+                        :> QueryParam "statistic" T.Text
+                        :> QueryParam "includerings" Bool
+                        :> Get '[JSON] [AnyStatisticItem]
+  } deriving Generic
diff --git a/PowerDNS/API/TSIGKeys.hs b/PowerDNS/API/TSIGKeys.hs
--- a/PowerDNS/API/TSIGKeys.hs
+++ b/PowerDNS/API/TSIGKeys.hs
@@ -12,6 +12,7 @@
 {-# LANGUAGE OverloadedStrings  #-}
 {-# LANGUAGE RecordWildCards    #-}
 {-# LANGUAGE TypeOperators      #-}
+{-# LANGUAGE TemplateHaskell    #-}
 module PowerDNS.API.TSIGKeys
   (
   -- * API
@@ -30,9 +31,10 @@
 
 import           Control.DeepSeq (NFData)
 import           Data.Aeson (FromJSON(..), ToJSON(..), Value(String),
-                             allNullaryToStringTag, constructorTagModifier,
-                             defaultOptions, genericParseJSON, genericToJSON,
                              object, withObject, (.:), (.:?), (.=))
+
+import           Data.Aeson.TH (allNullaryToStringTag, constructorTagModifier,
+                                defaultOptions, deriveJSON)
 import qualified Data.ByteString as BS
 import qualified Data.ByteString.Base64 as BS64
 import qualified Data.Text as T
@@ -71,6 +73,25 @@
   -- ^ Unlike the original PowerDNS API we do not require the key to be base64 encoded.
   } deriving (Eq, Ord, Show, Generic, NFData, Data)
 
+----------------------------------------------------------------------------------------
+
+-- | Supported algorithms according to [PowerDNS TSIG Documentation](https://doc.powerdns.com/authoritative/tsig.html#tsig)
+data TSIGAlgorithm = HMAC_MD5
+                   | HMAC_SHA1
+                   | HMAC_SHA224
+                   | HMAC_SHA256
+                   | HMAC_SHA384
+                   | HMAC_SHA512
+                   deriving (Eq, Ord, Show, Generic, NFData, Data)
+
+$(deriveJSON defaultOptions { allNullaryToStringTag = True
+                            , constructorTagModifier = fmap $ \c ->
+                                if c == '_' then '-' else toLower c
+                            } ''TSIGAlgorithm)
+
+
+----------------------------------------------------------------------------------------
+
 instance ToJSON TSIGKey where
   toJSON key = object [ "name" .= tsk_name key
                       , "id" .= tsk_id key
@@ -94,27 +115,3 @@
 decode64 i = case BS64.decode (T.encodeUtf8 i) of
   Left err -> Fail.fail err
   Right k  -> pure k
-
-----------------------------------------------------------------------------------------
-
--- | Supported algorithms according to [PowerDNS TSIG Documentation](https://doc.powerdns.com/authoritative/tsig.html#tsig)
-data TSIGAlgorithm = HMAC_MD5
-                   | HMAC_SHA1
-                   | HMAC_SHA224
-                   | HMAC_SHA256
-                   | HMAC_SHA384
-                   | HMAC_SHA512
-                   deriving (Eq, Ord, Show, Generic, NFData, Data)
-
-instance ToJSON TSIGAlgorithm where
-  toJSON = genericToJSON defaultOptions { allNullaryToStringTag = True
-                                        , constructorTagModifier = algo
-                                        }
-
-instance FromJSON TSIGAlgorithm where
-  parseJSON = genericParseJSON defaultOptions { allNullaryToStringTag = True
-                                              , constructorTagModifier = algo
-                                              }
-
-algo :: String -> String
-algo = fmap (\c -> if c == '_' then '-' else toLower c)
diff --git a/PowerDNS/API/Version.hs b/PowerDNS/API/Version.hs
--- a/PowerDNS/API/Version.hs
+++ b/PowerDNS/API/Version.hs
@@ -9,6 +9,7 @@
 {-# LANGUAGE DeriveDataTypeable #-}
 {-# LANGUAGE DeriveGeneric      #-}
 {-# LANGUAGE TypeOperators      #-}
+{-# LANGUAGE TemplateHaskell    #-}
 module PowerDNS.API.Version
   (
   -- * API
@@ -22,8 +23,7 @@
 import           Data.Data (Data)
 
 import           Control.DeepSeq (NFData)
-import           Data.Aeson (FromJSON(..), ToJSON(..), defaultOptions, fieldLabelModifier,
-                             genericParseJSON, genericToJSON)
+import           Data.Aeson.TH (defaultOptions, fieldLabelModifier, deriveJSON)
 
 import qualified Data.Text as T
 import           Servant.API
@@ -40,9 +40,5 @@
   , version_url :: T.Text
   } deriving (Eq, Ord, Show, Generic, NFData, Data)
 
-instance ToJSON Version where
-  toJSON = genericToJSON defaultOptions { fieldLabelModifier = strip "version_" }
-
-instance FromJSON Version where
-  parseJSON = genericParseJSON defaultOptions { fieldLabelModifier = strip "version_" }
+$(deriveJSON defaultOptions { fieldLabelModifier = strip "version_" } ''Version)
   
diff --git a/PowerDNS/API/Zones.hs b/PowerDNS/API/Zones.hs
--- a/PowerDNS/API/Zones.hs
+++ b/PowerDNS/API/Zones.hs
@@ -9,6 +9,8 @@
 {-# LANGUAGE DeriveDataTypeable #-}
 {-# LANGUAGE DeriveGeneric      #-}
 {-# LANGUAGE TypeOperators      #-}
+{-# LANGUAGE OverloadedStrings  #-}
+{-# LANGUAGE TemplateHaskell  #-}
 module PowerDNS.API.Zones
   (
   -- * API
@@ -26,6 +28,7 @@
 
   -- * Utilities
   , CIText
+  , Result(..)
   , mkCIText
   , original
   , caseFolded
@@ -41,10 +44,11 @@
 import           Text.Read (readPrec)
 
 import           Control.DeepSeq (NFData(..), deepseq)
-import           Data.Aeson (FromJSON(..), ToJSON(..), allNullaryToStringTag,
-                             constructorTagModifier, defaultOptions,
-                             fieldLabelModifier, genericParseJSON,
-                             genericToJSON, omitNothingFields)
+import           Data.Aeson.TH (allNullaryToStringTag,
+                                constructorTagModifier, defaultOptions,
+                                fieldLabelModifier,
+                                deriveJSON, omitNothingFields)
+import           Data.Aeson (FromJSON(..), ToJSON(..), object, (.:), (.=), withObject)
 import           Data.Hashable (Hashable(..))
 import qualified Data.Text as T
 import           Data.Time.Clock.POSIX (POSIXTime)
@@ -55,114 +59,106 @@
 
 ----------------------------------------------------------------------------------------
 
-data ZonesAPI f = ZonesAPI
-  { apiListZones     :: f :- "servers" :> Capture "server_id" T.Text :> "zones"
-                          :> QueryParam "zone" T.Text
-                          :> QueryParam "dnssec" Bool
-                          :> Get '[JSON] [Zone]
-
-  , apiCreateZone    :: f :- "servers" :> Capture "server_id" T.Text :> "zones"
-                          :> QueryParam "rrset" Bool
-                          :> ReqBody '[JSON] Zone
-                          :> PostCreated '[JSON] Zone
-
-  , apiGetZone       :: f :- "servers" :> Capture "server_id" T.Text :> "zones" :> Capture "zone_id" T.Text
-                          :> QueryParam "rrsets" Bool
-                          :> Get '[JSON] Zone
-
-  , apiDeleteZone    :: f :- "servers" :> Capture "server_id" T.Text :> "zones" :> Capture "zone_id" T.Text
-                          :> DeleteNoContent
-
-  , apiUpdateRecords :: f :- "servers" :> Capture "server_id" T.Text :> "zones" :> Capture "zone_id" T.Text
-                          :> ReqBody '[JSON] RRSets
-                          :> PatchNoContent
-
-  , apiUpdateZone    :: f :- "servers" :> Capture "server_id" T.Text :> "zones" :> Capture "zone_id" T.Text
-                          :> ReqBody '[JSON] Zone
-                          :> PutNoContent
-
-  , apiTriggerAxfr   :: f :- "servers" :> Capture "server_id" T.Text :> "zones" :> Capture "zone_id" T.Text :> "axfr-retrieve"
-                          :> Put '[JSON] NoContent
-
-  , apiNotifySlaves  :: f :- "servers" :> Capture "server_id" T.Text :> "zones" :> Capture "zone_id" T.Text :> "notify"
-                          :> Put '[JSON] NoContent
-
-  , apiGetZoneAxfr   :: f :- "servers" :> Capture "server_id" T.Text :> "zones" :> Capture "zone_id" T.Text :> "export"
-                          :> Get '[JSON] T.Text
-
-  , apiRectifyZone   :: f :- "servers" :> Capture "server_id" T.Text :> "zones" :> Capture "zone_id" T.Text :> "rectify"
-                          :> Put '[JSON] T.Text
+-- | Record according to [PowerDNS Documentation](https://doc.powerdns.com/authoritative/http-api/zone.html#record)
+data Record = Record
+  { record_content :: T.Text
+  , record_disabled :: Bool
+  } deriving (Eq, Ord, Show, Generic, NFData, Data)
 
-  } deriving Generic
+$(deriveJSON defaultOptions { fieldLabelModifier = strip "record_"
+                            , omitNothingFields = True } ''Record)
 
 
 ----------------------------------------------------------------------------------------
 
--- | Zone according to [PowerDNS Documentation](https://doc.powerdns.com/authoritative/http-api/zone.html#zone).
--- All fields are optional because the PowerDNS API differs on which fields are required depending on the endpoint.
---
--- Note that 'Eq' and 'Ord' use limited case-sensitivity on 'zone_name' and equivalently contained rrset names
--- as per [RFC4343](https://datatracker.ietf.org/doc/html/rfc4343)
-data Zone = Zone
-  { zone_id :: Maybe T.Text
-  , zone_name :: Maybe CIText
-  , zone_type :: Maybe T.Text
-  , zone_url :: Maybe T.Text
-  , zone_kind :: Maybe Kind
-  , zone_rrsets :: Maybe [RRSet]
-  , zone_serial :: Maybe Integer
-  , zone_notified_serial :: Maybe Integer
-  , zone_edited_serial :: Maybe Integer
-  , zone_masters :: Maybe [T.Text]
-  , zone_dnssec :: Maybe Bool
-  , zone_nsec3param :: Maybe T.Text
-  , zone_nsec3narrow :: Maybe Bool
-  , zone_presigned :: Maybe Bool
-  , zone_soa_edit :: Maybe T.Text
-  , zone_soa_edit_api :: Maybe T.Text
-  , zone_api_rectify :: Maybe Bool
-  , zone_zone :: Maybe T.Text
-  , zone_account :: Maybe T.Text
-  , zone_nameservers :: Maybe [T.Text]
-  , zone_master_tsig_key_ids :: Maybe [T.Text]
-  , zone_slave_tsig_key_ids :: Maybe [T.Text]
+-- | Comment according to [PowerDNS Documentation](https://doc.powerdns.com/authoritative/http-api/zone.html#comment)
+data Comment = Comment
+  { comment_content :: Maybe T.Text
+  , comment_account :: Maybe T.Text
+  , comment_modified_at :: Maybe POSIXTime
   } deriving (Eq, Ord, Show, Generic, NFData, Data, Empty)
 
-instance ToJSON Zone where
-  toJSON = genericToJSON defaultOptions { fieldLabelModifier = strip "zone_"}
-
-instance FromJSON Zone where
-  parseJSON = genericParseJSON defaultOptions { fieldLabelModifier = strip "zone_"}
+$(deriveJSON defaultOptions { fieldLabelModifier = strip "comment_" } ''Comment)
 
 ----------------------------------------------------------------------------------------
 
-data Kind = Native | Master | Slave
-  deriving (Eq, Ord, Show, Generic, NFData, Data)
+-- | Whether or not an 'RRSet' replace or delete an existing entry.
+-- If the 'ChangeType' is left at @Nothing@ it will create a new domain entry.
+data ChangeType = Replace
+                | Delete
+                deriving (Eq, Ord, Show, Generic, NFData, Data)
 
-instance ToJSON Kind where
-  toJSON = genericToJSON defaultOptions { allNullaryToStringTag = True }
+$(deriveJSON defaultOptions { constructorTagModifier = fmap toUpper
+                            , allNullaryToStringTag = True } ''ChangeType)
 
-instance FromJSON Kind where
-  parseJSON = genericParseJSON defaultOptions { allNullaryToStringTag = True }
 
+
 ----------------------------------------------------------------------------------------
 
--- | A list of RRSets
-data RRSets = RRSets
-  { rrsets :: [RRSet]
-  } deriving (Eq, Ord, Show, Generic, NFData, Data)
+data RecordType = A
+                | AAAA
+                | AFSDB
+                | ALIAS
+                | APL
+                | CAA
+                | CERT
+                | CDNSKEY
+                | CDS
+                | CNAME
+                | DNSKEY
+                | DNAME
+                | DS
+                | HINFO
+                | KEY
+                | LOC
+                | MX
+                | NAPTR
+                | NS
+                | NSEC
+                | NSEC3
+                | NSEC3PARAM
+                | OPENPGPKEY
+                | PTR
+                | RP
+                | RRSIG
+                | SOA
+                | SPF
+                | SSHFP
+                | SRV
+                | TKEY
+                | TSIG
+                | TLSA
+                | SMIMEA
+                | TXT
+                | URI
+                | A6
+                | DHCID
+                | DLV
+                | EUI48
+                | EUI64
+                | IPSECKEY
+                | KX
+                | MAILA
+                | MAILB
+                | MINFO
+                | MR
+                | RKEY
+                | SIG
+                | WKS
+                deriving (Eq, Ord, Show, Generic, NFData, Data)
 
-instance ToJSON RRSets
-instance FromJSON RRSets
+$(deriveJSON defaultOptions { allNullaryToStringTag = True
+                            } ''RecordType)
 
+
 ----------------------------------------------------------------------------------------
 
 -- | A wrapper for 'T.Text' implementing limited case-sensitivity as per [RFC4343](https://datatracker.ietf.org/doc/html/rfc4343).
 -- Use 'mkCIText' for construction.
 --
 -- See 'original' and 'caseFolded' for extracting a 'T.Text' back.
-data CIText = CIText { ciOriginal :: T.Text, ciCaseFolded :: T.Text } deriving Data
 
+data CIText = CIText { ciOriginal :: T.Text, ciCaseFolded :: T.Text } deriving Data
 
 -- | Obtain the original 'T.Text' from a 'CIText'.
 original :: CIText -> T.Text
@@ -219,6 +215,8 @@
            | otherwise
            = x
 
+----------------------------------------------------------------------------------------
+
 -- | RRSet according to [PowerDNS Documentation](https://doc.powerdns.com/authoritative/http-api/zone.html#rrset).
 --
 -- Note that 'Eq' and 'Ord' use limited case-sensitivity on 'rrset_name' as per [RFC4343](https://datatracker.ietf.org/doc/html/rfc4343)
@@ -231,118 +229,107 @@
   , rrset_comments :: Maybe [Comment]
   } deriving (Eq, Ord, Show, Generic, NFData, Data)
 
-instance ToJSON RRSet where
-  toJSON = genericToJSON defaultOptions { fieldLabelModifier = strip "rrset_"
-                                        , omitNothingFields = True }
+$(deriveJSON defaultOptions { fieldLabelModifier = strip "rrset_"
+                            , omitNothingFields = True } ''RRSet)
 
-instance FromJSON RRSet where
-  parseJSON = genericParseJSON defaultOptions { fieldLabelModifier = strip "rrset_"
-                                              , omitNothingFields = True }
+----------------------------------------------------------------------------------------
 
+-- | A list of RRSets
+data RRSets = RRSets
+  { rrsets :: [RRSet]
+  } deriving (Eq, Ord, Show, Generic, NFData, Data)
+
+instance ToJSON RRSets
+instance FromJSON RRSets
+
 ----------------------------------------------------------------------------------------
 
-data RecordType = A
-                | AAAA
-                | AFSDB
-                | ALIAS
-                | APL
-                | CAA
-                | CERT
-                | CDNSKEY
-                | CDS
-                | CNAME
-                | DNSKEY
-                | DNAME
-                | DS
-                | HINFO
-                | KEY
-                | LOC
-                | MX
-                | NAPTR
-                | NS
-                | NSEC
-                | NSEC3
-                | NSEC3PARAM
-                | OPENPGPKEY
-                | PTR
-                | RP
-                | RRSIG
-                | SOA
-                | SPF
-                | SSHFP
-                | SRV
-                | TKEY
-                | TSIG
-                | TLSA
-                | SMIMEA
-                | TXT
-                | URI
-                | A6
-                | DHCID
-                | DLV
-                | EUI48
-                | EUI64
-                | IPSECKEY
-                | KX
-                | MAILA
-                | MAILB
-                | MINFO
-                | MR
-                | RKEY
-                | SIG
-                | WKS
-                deriving (Eq, Ord, Show, Generic, NFData, Data)
+data Kind = Native | Master | Slave
+  deriving (Eq, Ord, Show, Generic, NFData, Data)
 
-instance ToJSON RecordType where
-  toJSON = genericToJSON defaultOptions { allNullaryToStringTag = True
-                                        }
+$(deriveJSON defaultOptions { allNullaryToStringTag = True } ''Kind)
 
-instance FromJSON RecordType where
-  parseJSON = genericParseJSON defaultOptions { allNullaryToStringTag = True
-                                              }
+----------------------------------------------------------------------------------------
 
+-- | Zone according to [PowerDNS Documentation](https://doc.powerdns.com/authoritative/http-api/zone.html#zone).
+-- All fields are optional because the PowerDNS API differs on which fields are required depending on the endpoint.
+--
+-- Note that 'Eq' and 'Ord' use limited case-sensitivity on 'zone_name' and equivalently contained rrset names
+-- as per [RFC4343](https://datatracker.ietf.org/doc/html/rfc4343)
+data Zone = Zone
+  { zone_id :: Maybe T.Text
+  , zone_name :: Maybe CIText
+  , zone_type :: Maybe T.Text
+  , zone_url :: Maybe T.Text
+  , zone_kind :: Maybe Kind
+  , zone_rrsets :: Maybe [RRSet]
+  , zone_serial :: Maybe Integer
+  , zone_notified_serial :: Maybe Integer
+  , zone_edited_serial :: Maybe Integer
+  , zone_masters :: Maybe [T.Text]
+  , zone_dnssec :: Maybe Bool
+  , zone_nsec3param :: Maybe T.Text
+  , zone_nsec3narrow :: Maybe Bool
+  , zone_presigned :: Maybe Bool
+  , zone_soa_edit :: Maybe T.Text
+  , zone_soa_edit_api :: Maybe T.Text
+  , zone_api_rectify :: Maybe Bool
+  , zone_zone :: Maybe T.Text
+  , zone_account :: Maybe T.Text
+  , zone_nameservers :: Maybe [T.Text]
+  , zone_master_tsig_key_ids :: Maybe [T.Text]
+  , zone_slave_tsig_key_ids :: Maybe [T.Text]
+  } deriving (Eq, Ord, Show, Generic, NFData, Data, Empty)
+
+$(deriveJSON defaultOptions { fieldLabelModifier = strip "zone_" } ''Zone)
+
 ----------------------------------------------------------------------------------------
 
--- | Whether or not an 'RRSet' replace or delete an existing entry.
--- If the 'ChangeType' is left at @Nothing@ it will create a new domain entry.
-data ChangeType = Replace
-                | Delete
-                deriving (Eq, Ord, Show, Generic, NFData, Data)
+data ZonesAPI f = ZonesAPI
+  { apiListZones     :: f :- "servers" :> Capture "server_id" T.Text :> "zones"
+                          :> QueryParam "zone" T.Text
+                          :> QueryParam "dnssec" Bool
+                          :> Get '[JSON] [Zone]
 
-instance ToJSON ChangeType where
-  toJSON = genericToJSON defaultOptions { constructorTagModifier = fmap toUpper
-                                        , allNullaryToStringTag = True }
+  , apiCreateZone    :: f :- "servers" :> Capture "server_id" T.Text :> "zones"
+                          :> QueryParam "rrset" Bool
+                          :> ReqBody '[JSON] Zone
+                          :> PostCreated '[JSON] Zone
 
-instance FromJSON ChangeType where
-  parseJSON = genericParseJSON defaultOptions { constructorTagModifier = fmap toUpper
-                                              , allNullaryToStringTag = True }
+  , apiGetZone       :: f :- "servers" :> Capture "server_id" T.Text :> "zones" :> Capture "zone_id" T.Text
+                          :> QueryParam "rrsets" Bool
+                          :> Get '[JSON] Zone
 
-----------------------------------------------------------------------------------------
--- | Record according to [PowerDNS Documentation](https://doc.powerdns.com/authoritative/http-api/zone.html#record)
-data Record = Record
-  { record_content :: T.Text
-  , record_disabled :: Bool
-  } deriving (Eq, Ord, Show, Generic, NFData, Data)
+  , apiDeleteZone    :: f :- "servers" :> Capture "server_id" T.Text :> "zones" :> Capture "zone_id" T.Text
+                          :> DeleteNoContent
 
-instance ToJSON Record where
-  toJSON = genericToJSON defaultOptions { fieldLabelModifier = strip "record_"
-                                        , omitNothingFields = True }
+  , apiUpdateRecords :: f :- "servers" :> Capture "server_id" T.Text :> "zones" :> Capture "zone_id" T.Text
+                          :> ReqBody '[JSON] RRSets
+                          :> PatchNoContent
 
-instance FromJSON Record where
-  parseJSON = genericParseJSON defaultOptions { fieldLabelModifier = strip "record_"
-                                              , omitNothingFields = True }
+  , apiUpdateZone    :: f :- "servers" :> Capture "server_id" T.Text :> "zones" :> Capture "zone_id" T.Text
+                          :> ReqBody '[JSON] Zone
+                          :> PutNoContent
 
-----------------------------------------------------------------------------------------
+  , apiTriggerAxfr   :: f :- "servers" :> Capture "server_id" T.Text :> "zones" :> Capture "zone_id" T.Text :> "axfr-retrieve"
+                          :> Put '[JSON] Result
 
--- | Comment according to [PowerDNS Documentation](https://doc.powerdns.com/authoritative/http-api/zone.html#comment)
-data Comment = Comment
-  { comment_content :: Maybe T.Text
-  , comment_account :: Maybe T.Text
-  , comment_modified_at :: Maybe POSIXTime
-  } deriving (Eq, Ord, Show, Generic, NFData, Data, Empty)
+  , apiNotifySlaves  :: f :- "servers" :> Capture "server_id" T.Text :> "zones" :> Capture "zone_id" T.Text :> "notify"
+                          :> Put '[JSON] Result
 
-instance ToJSON Comment where
-  toJSON = genericToJSON defaultOptions { fieldLabelModifier = strip "comment_" }
+  , apiGetZoneAxfr   :: f :- "servers" :> Capture "server_id" T.Text :> "zones" :> Capture "zone_id" T.Text :> "export"
+                          :> Get '[JSON] Result
 
-instance FromJSON Comment where
-  parseJSON = genericParseJSON defaultOptions { fieldLabelModifier = strip "comment_" }
+  , apiRectifyZone   :: f :- "servers" :> Capture "server_id" T.Text :> "zones" :> Capture "zone_id" T.Text :> "rectify"
+                          :> Put '[JSON] Result
+
+  } deriving Generic
+
+
+data Result = Result T.Text
+
+instance ToJSON Result where
+  toJSON (Result t) = object ["result" .= t]
+
+instance FromJSON Result where
+  parseJSON = withObject "result" $ \o -> Result <$> (o .: "result")
diff --git a/PowerDNS/Client.hs b/PowerDNS/Client.hs
--- a/PowerDNS/Client.hs
+++ b/PowerDNS/Client.hs
@@ -52,6 +52,7 @@
   , Comment(..)
   , ChangeType(..)
   , RecordType(..)
+  , Result(..)
 
   -- * Cryptokeys
   -- | See documentation at [PowerDNS Cryptokeys API](https://doc.powerdns.com/authoritative/http-api/cryptokey.html)
@@ -208,25 +209,25 @@
 -- | Trigger zone transfer on a slave. See [Zones API Documentation](https://doc.powerdns.com/authoritative/http-api/zone.html#put--servers-server_id-zones-zone_id-axfr-retrieve)
 triggerAxfr :: T.Text       -- ^ Server name
             -> T.Text       -- ^ Zone ID
-            -> ClientM NoContent
+            -> ClientM Result
 triggerAxfr = apiTriggerAxfr zonesClient
 
 -- | Send DNS notify to slaves. See [Zones API Documentation](https://doc.powerdns.com/authoritative/http-api/zone.html#put--servers-server_id-zones-zone_id-notify)
 notifySlaves :: T.Text       -- ^ Server name
              -> T.Text       -- ^ Zone ID
-             -> ClientM NoContent
+             -> ClientM Result
 notifySlaves = apiNotifySlaves zonesClient
 
 -- | Return zone in AXFR format. See [Zones API Documentation](https://doc.powerdns.com/authoritative/http-api/zone.html#get--servers-server_id-zones-zone_id-export)
 getZoneAxfr :: T.Text         -- ^ Server name
             -> T.Text         -- ^ Zone ID
-            -> ClientM T.Text -- ^ Zone in AXFR format
+            -> ClientM Result -- ^ Zone in AXFR format
 getZoneAxfr = apiGetZoneAxfr zonesClient
 
 -- | Rectify the zone data. See [Zones API Documentation](https://doc.powerdns.com/authoritative/http-api/zone.html#put--servers-server_id-zones-zone_id-rectify)
 rectifyZone :: T.Text       -- ^ Server name
             -> T.Text       -- ^ Zone ID
-            -> ClientM T.Text
+            -> ClientM Result
 rectifyZone = apiRectifyZone zonesClient
 
 ----------------------------------------------------------------------------------------
diff --git a/powerdns.cabal b/powerdns.cabal
--- a/powerdns.cabal
+++ b/powerdns.cabal
@@ -1,6 +1,6 @@
 cabal-version:      3.0
 name:               powerdns
-version:            0.4.1
+version:            0.4.2
 license:            BSD-3-Clause
 license-file:       LICENSE
 copyright:          (c) 2021 Victor Nawothnig
@@ -12,12 +12,12 @@
 description:
     PowerDNS API allows programmatic manipulation of zones and other metadata. This
     library is a thin wrapper, exposing most of the idiosyncracies directly.
-    .
+
     Users are advised to refer to the PowerDNS documentation and its source code for
     the exact semantics.
-    .
+
     All exposed API endpoints are provided.
-    .
+
     > import qualified PowerDNS.Client as P
     > import           Network.HTTP.Client (newManager, defaultManagerSettings)
     > import           Servant.Client (runClientM, mkClientEnv, parseBarseUrl)
@@ -58,7 +58,7 @@
     ghc-options:      -Wall -Wcompat
     build-depends:
         aeson ^>= { 1.5.6, 2.0.3.0 },
-        bytestring ^>= { 0.10.10 },
+        bytestring ^>= { 0.10.10, 0.11.0 },
         deepseq ^>= { 1.4.4 },
         containers ^>= { 0.6.2 },
         hashable ^>= { 1.3.0.0 },
diff --git a/spec/Spec.hs b/spec/Spec.hs
--- a/spec/Spec.hs
+++ b/spec/Spec.hs
@@ -97,6 +97,12 @@
     step "Add record to zone"
     runOk (updateZone "localhost" zoneId (patch added))
 
+    step "Trigger notify"
+    runOk (notifySlaves "localhost" zoneId)
+
+    step "Trigger rectify"
+    runOk (rectifyZone "localhost" zoneId)
+
     step "Delete a record"
     runOk (updateZone "localhost" zoneId (patch deleted))
 
