diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,11 @@
 # Changelog
 
+## [0.2.2.0] - 2023-11-20
+
+### Added
+
+* `HasCodec Integer` and `HasCodec Natural` instances.
+
 ## [0.2.1.0] - 2023-10-06
 
 ### Added
diff --git a/autodocodec.cabal b/autodocodec.cabal
--- a/autodocodec.cabal
+++ b/autodocodec.cabal
@@ -5,7 +5,7 @@
 -- see: https://github.com/sol/hpack
 
 name:           autodocodec
-version:        0.2.1.0
+version:        0.2.2.0
 synopsis:       Self-documenting encoder and decoder
 homepage:       https://github.com/NorfairKing/autodocodec#readme
 bug-reports:    https://github.com/NorfairKing/autodocodec/issues
diff --git a/doctest/DocTest.hs b/doctest/DocTest.hs
--- a/doctest/DocTest.hs
+++ b/doctest/DocTest.hs
@@ -3,4 +3,4 @@
 import Test.DocTest
 
 main :: IO ()
-main = doctest ["-isrc", "src/Autodocodec"]
+main = doctest ["-isrc", "src"]
diff --git a/src/Autodocodec.hs b/src/Autodocodec.hs
--- a/src/Autodocodec.hs
+++ b/src/Autodocodec.hs
@@ -81,6 +81,10 @@
     -- *** Integral codecs
     boundedIntegralCodec,
     boundedIntegralNumberBounds,
+    integerCodec,
+    unsafeUnboundedIntegerCodec,
+    naturalCodec,
+    unsafeUnboundedNaturalCodec,
 
     -- *** Literal value codecs
     literalTextCodec,
diff --git a/src/Autodocodec/Class.hs b/src/Autodocodec/Class.hs
--- a/src/Autodocodec/Class.hs
+++ b/src/Autodocodec/Class.hs
@@ -12,6 +12,7 @@
 import Autodocodec.Codec
 import Data.Aeson (FromJSONKey, ToJSONKey)
 import qualified Data.Aeson as JSON
+import Numeric.Natural
 #if MIN_VERSION_aeson(2,0,0)
 import Data.Aeson.KeyMap (KeyMap)
 #endif
@@ -92,6 +93,10 @@
 instance HasCodec Int64 where
   codec = boundedIntegralCodec
 
+-- | This instance uses the "safe" 'integerCodec'.
+instance HasCodec Integer where
+  codec = integerCodec
+
 instance HasCodec Word where
   codec = boundedIntegralCodec
 
@@ -106,6 +111,10 @@
 
 instance HasCodec Word64 where
   codec = boundedIntegralCodec
+
+-- | This instance uses the "safe" 'naturalCodec'.
+instance HasCodec Natural where
+  codec = naturalCodec
 
 instance HasCodec JSON.Value where
   codec = ValueCodec
diff --git a/src/Autodocodec/Codec.hs b/src/Autodocodec/Codec.hs
--- a/src/Autodocodec/Codec.hs
+++ b/src/Autodocodec/Codec.hs
@@ -42,6 +42,7 @@
 import qualified Data.Vector as V
 import Data.Void
 import GHC.Generics (Generic)
+import Numeric.Natural
 
 -- $setup
 -- >>> import Autodocodec.Aeson (toJSONVia, toJSONViaCodec, toJSONObjectVia, toJSONObjectViaCodec, parseJSONVia, parseJSONViaCodec, parseJSONObjectVia, parseJSONObjectViaCodec)
@@ -1340,6 +1341,84 @@
     { numberBoundsLower = fromIntegral (minBound :: i),
       numberBoundsUpper = fromIntegral (maxBound :: i)
     }
+
+-- | A safe codec for 'Integer'.
+--
+-- This codec does a bounds check for the range [-10^1024, 10^1024] it can safely parse very large numbers.
+--
+-- For a codec without this protection, see 'unsafeUnboundedIntegerCodec'.
+--
+-- === Example usage
+--
+-- >>> toJSONVia integerCodec 5
+-- Number 5.0
+-- >>> toJSONVia integerCodec (-1000000000000)
+-- Number (-1.0e12)
+-- >>> JSON.parseMaybe (parseJSONVia integerCodec) (Number (-4.0))
+-- Just (-4)
+-- >>> JSON.parseMaybe (parseJSONVia integerCodec) (Number (scientific 1 100000000))
+-- Nothing
+integerCodec :: JSONCodec Integer
+integerCodec =
+  bimapCodec go fromIntegral $
+    scientificWithBoundsCodec
+      ( NumberBounds
+          { numberBoundsLower = scientific (-1) 1024,
+            numberBoundsUpper = scientific 1 1024
+          }
+      )
+  where
+    go s = case Scientific.floatingOrInteger s :: Either Float Integer of
+      Right i -> Right i
+      Left _ -> Left ("Number is not an integer: " <> show s)
+
+-- | This is an unsafe (unchecked) version of 'integerCodec'.
+unsafeUnboundedIntegerCodec :: JSONCodec Integer
+unsafeUnboundedIntegerCodec =
+  bimapCodec go fromIntegral scientificCodec
+  where
+    go s = case Scientific.floatingOrInteger s :: Either Float Integer of
+      Right i -> Right i
+      Left _ -> Left ("Number is not an integer: " <> show s)
+
+-- | A safe codec for 'Natural'.
+--
+-- This codec does a bounds check for the range [0, 10^1024] it can safely parse very large numbers.
+--
+-- For a codec without this protection, see 'unsafeUnboundedNaturalCodec'.
+--
+-- === Example usage
+--
+-- >>> toJSONVia naturalCodec 5
+-- Number 5.0
+-- >>> toJSONVia naturalCodec (1000000000000)
+-- Number 1.0e12
+-- >>> JSON.parseMaybe (parseJSONVia naturalCodec) (Number 4.0)
+-- Just 4
+-- >>> JSON.parseMaybe (parseJSONVia naturalCodec) (Number (scientific 1 100000000))
+-- Nothing
+naturalCodec :: JSONCodec Natural
+naturalCodec =
+  bimapCodec go fromIntegral $
+    scientificWithBoundsCodec
+      ( NumberBounds
+          { numberBoundsLower = scientific 0 0,
+            numberBoundsUpper = scientific 1 1024
+          }
+      )
+  where
+    go s = case Scientific.floatingOrInteger s :: Either Float Natural of
+      Right i -> Right i
+      Left _ -> Left ("Number is not an integer: " <> show s)
+
+-- | This is an unsafe (unchecked) version of 'naturalCodec'.
+unsafeUnboundedNaturalCodec :: JSONCodec Natural
+unsafeUnboundedNaturalCodec =
+  bimapCodec go fromIntegral scientificCodec
+  where
+    go s = case Scientific.floatingOrInteger s :: Either Float Natural of
+      Right i -> Right i
+      Left _ -> Left ("Number is not an integer: " <> show s)
 
 -- | A codec for a literal piece of 'Text'.
 --
