diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,8 @@
+# 0.2.0.0
+
+- Remove `Data.Buffer` module
+- Expand version bounds to include bytestring v0.12.
+
 # 0.1.0.3
 
 - Expand version bounds to include http-client v0.7.
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -4,7 +4,5 @@
 
 The library is low-level and provides a faithful representation of version 5 of the [Bugsnag error reporting API][] payload. Almost all documentation comments in this code come from that API's documentation. The intent is for this library to make no assumptions about the structure of the application using it.
 
-The one higher-level functionality this library provides is help batching Bugsnag events together to make fewer HTTP requests, but the use of this functionality is optional.
-
 [bugsnag]: https://www.bugsnag.com/
 [bugsnag error reporting api]: https://bugsnagerrorreportingapi.docs.apiary.io/#reference
diff --git a/bugsnag-hs.cabal b/bugsnag-hs.cabal
--- a/bugsnag-hs.cabal
+++ b/bugsnag-hs.cabal
@@ -4,10 +4,10 @@
 --
 -- see: https://github.com/sol/hpack
 --
--- hash: 7caac2dd8372f186bc786e2c0c35b6f70284087a246e937655343f3b6105231e
+-- hash: 67c246cc1a26f9b2a1ad07fe282ddbf1c55256e19cff590e9e00cd34999909a5
 
 name:           bugsnag-hs
-version:        0.1.0.3
+version:        0.2.0.0
 synopsis:       A Bugsnag client for Haskell.
 description:    Please see the README at <https://github.com/jwoudenberg/bugsnag-hs>.
 category:       Web
@@ -32,7 +32,6 @@
 library
   exposed-modules:
       Network.Bugsnag
-      Data.Buffer
   other-modules:
       Paths_bugsnag_hs
   hs-source-dirs:
@@ -41,7 +40,7 @@
       aeson >=1.2.4.0 && <1.6
     , auto-update >=0.1.4 && <0.2
     , base >=4.10.1.0 && <5
-    , bytestring >=0.10.8.2 && <0.11
+    , bytestring >=0.10.8.2 && <0.12
     , http-client >=0.5.10 && <0.8
     , stm >=2.4.5.0 && <2.6
     , text >=1.2.3.0 && <1.3
@@ -53,7 +52,6 @@
   type: exitcode-stdio-1.0
   main-is: Main.hs
   other-modules:
-      Spec.Data.Buffer
       Spec.Network.Bugsnag
       Paths_bugsnag_hs
   hs-source-dirs:
diff --git a/src/Data/Buffer.hs b/src/Data/Buffer.hs
deleted file mode 100644
--- a/src/Data/Buffer.hs
+++ /dev/null
@@ -1,79 +0,0 @@
-{-# LANGUAGE NamedFieldPuns #-}
-
--- |
--- A buffer for batched write operations. Push individual items into the buffer
--- and provide an operation that writes out batches of them.
-module Data.Buffer
-  ( -- * Buffer
-    Buffer,
-    new,
-    push,
-    flush,
-
-    -- * Settings
-    Settings,
-    defaultSettings,
-    write,
-    size,
-    frequencyInMicroSeconds,
-  )
-where
-
-import qualified Control.Concurrent.STM as STM
-import qualified Control.Debounce as Debounce
-import qualified Data.List.NonEmpty as NonEmpty
-import GHC.Natural (Natural)
-
--- | A buffer for write operations.
-data Buffer a
-  = Buffer
-      { -- | Push a new item into the buffer.
-        push :: a -> IO (),
-        -- | Flush the current contents of the buffer.
-        flush :: IO ()
-      }
-
--- | Configuration settings for a new 'Buffer'.
-data Settings a
-  = Settings
-      { -- | Function to write a batch of items.
-        write :: NonEmpty.NonEmpty a -> IO (),
-        -- | The maximum amount of items to write in a single batch.
-        size :: Natural,
-        -- | The frequency with which the buffer gets flushed automatically.
-        frequencyInMicroSeconds :: Int
-      }
-
--- | Default 'Buffer' settings. A buffer created by these settings has a size
--- of 1 and writes items out as soon as they come in.
-defaultSettings :: Settings a
-defaultSettings =
-  Settings
-    { write = \_ -> pure (),
-      size = 1,
-      frequencyInMicroSeconds = 0
-    }
-
--- | Creates a new 'Buffer'.
-new :: Settings a -> IO (Buffer a)
-new settings = do
-  queue <- STM.atomically $ STM.newTBQueue (fromIntegral (size settings))
-  let writeList xs = maybe (pure ()) (write settings) (NonEmpty.nonEmpty xs)
-  let flush = writeList =<< STM.atomically (STM.flushTBQueue queue)
-  scheduleFlush <-
-    Debounce.mkDebounce
-      Debounce.defaultDebounceSettings
-        { Debounce.debounceAction = flush,
-          Debounce.debounceFreq = frequencyInMicroSeconds settings
-        }
-  let push x = do
-        overflow <- STM.atomically $ do
-          full <- STM.isFullTBQueue queue
-          toFlush <- if full then STM.flushTBQueue queue else pure []
-          STM.writeTBQueue queue x
-          pure toFlush
-        -- Flush the items that overflow the queue immediately.
-        writeList overflow
-        -- Schedule a regular flush for the rest.
-        scheduleFlush
-  pure Buffer {push, flush}
diff --git a/src/Network/Bugsnag.hs b/src/Network/Bugsnag.hs
--- a/src/Network/Bugsnag.hs
+++ b/src/Network/Bugsnag.hs
@@ -8,10 +8,6 @@
 module Network.Bugsnag
   ( -- * Sending reports
     sendEvents,
-    queueSingleEvent,
-    Batcher,
-    newBatcher,
-    flushBatcher,
 
     -- ** ApiKey
     ApiKey,
@@ -290,7 +286,6 @@
 import Control.Exception (try)
 import Control.Monad (void)
 import qualified Data.Aeson
-import qualified Data.Buffer as Buffer
 import qualified Data.ByteString.Char8
 import Data.Foldable (toList)
 import Data.HashMap.Strict (HashMap)
@@ -302,9 +297,6 @@
 import qualified Network.HTTP.Client as HTTP
 
 -- | Send a batch of 'Event's to Rollbar using a single HTTP request.
---
--- If you only get your hands on one event at a time then 'queueSingleEvent' is
--- probably going to be more efficient.
 sendEvents :: HTTP.Manager -> ApiKey -> [Event] -> IO (Either HTTP.HttpException ())
 sendEvents manager apiKey events = do
   send manager apiKey Report
@@ -313,35 +305,6 @@
       report_notifier = thisNotifier,
       report_events = events
     }
-
--- | Helps you batch Bugsnag 'Event's together so you make fewer HTTP request.
-newtype Batcher = Batcher (Buffer.Buffer Event)
-
--- | Create a batcher, which you need to use the 'queueSingleEvent' function.
-newBatcher :: HTTP.Manager -> ApiKey -> (HTTP.HttpException -> IO ()) -> IO Batcher
-newBatcher manager apiKey onError = do
-  buffer <-
-    Buffer.new
-      Buffer.defaultSettings
-        { Buffer.write = \batch -> either onError pure =<< sendEvents manager apiKey (toList batch),
-          Buffer.size = 100, -- Bugsnag limits requests to 1MB, so this allows for 10KB per event.
-          Buffer.frequencyInMicroSeconds = 5000000 -- 5 seconds
-        }
-  pure (Batcher buffer)
-
--- | Queue a single 'Event' for submission to Bugsnag. If multiple events are
--- queued around the same moment they will be batched together and sent in a
--- single HTTP request.
-queueSingleEvent :: Batcher -> Event -> IO ()
-queueSingleEvent (Batcher buffer) = Buffer.push buffer
-
--- | When passing an 'Event' to 'queueSingleEvent' we wait briefly before
--- sending it to Bugsnag, to see if other 'Event's get queued we can send to
--- Bugsnag in a single HTTP request. This function allows you to immediately
--- send any 'Event's that are being held. You might use it when shutting down
--- your application.
-flushBatcher :: Batcher -> IO ()
-flushBatcher (Batcher buffer) = Buffer.flush buffer
 
 send :: HTTP.Manager -> ApiKey -> Report -> IO (Either HTTP.HttpException ())
 send manager (ApiKey apiKey) report = do
diff --git a/test/Main.hs b/test/Main.hs
--- a/test/Main.hs
+++ b/test/Main.hs
@@ -3,10 +3,8 @@
   )
 where
 
-import qualified Spec.Data.Buffer
 import qualified Spec.Network.Bugsnag
 
 main :: IO ()
 main = do
   Spec.Network.Bugsnag.tests
-  Spec.Data.Buffer.tests
diff --git a/test/Spec/Data/Buffer.hs b/test/Spec/Data/Buffer.hs
deleted file mode 100644
--- a/test/Spec/Data/Buffer.hs
+++ /dev/null
@@ -1,110 +0,0 @@
-{-# LANGUAGE NamedFieldPuns #-}
-{-# LANGUAGE OverloadedStrings #-}
-
-module Spec.Data.Buffer
-  ( tests,
-  )
-where
-
-import qualified Control.Concurrent
-import qualified Control.Concurrent.STM as STM
-import qualified Data.Buffer as Buffer
-import qualified Data.Foldable
-import qualified Data.List
-import qualified Data.List.NonEmpty as NonEmpty
-import qualified Data.Maybe
-import GHC.Natural (Natural)
-import Hedgehog
-import qualified Hedgehog.Gen as Gen
-import qualified Hedgehog.Range as Range
-import qualified System.Exit
-
-tests :: IO ()
-tests = do
-  res <- tests'
-  if res
-    then pure ()
-    else System.Exit.die "Spec.Data.Buffer tests failed"
-
-tests' :: IO Bool
-tests' =
-  checkParallel $
-    Group
-      "Spec.Data.Buffer"
-      [ ("all items get sent", allItemsGetSent)
-      ]
-
-allItemsGetSent :: Property
-allItemsGetSent = property $ do
-  steps <- forAll $ numberItems <$> Gen.list (Range.linear 0 100) step
-  size <- forAll $ fromIntegral <$> Gen.int (Range.linear 1 10)
-  frequencyInMicroSeconds <- forAll $ waitMicroS
-  actualOutput <- evalIO (run size frequencyInMicroSeconds steps)
-  let expectedOutput = Data.Maybe.mapMaybe toItem steps
-  Data.List.sort actualOutput === Data.List.sort expectedOutput
-
-data Step
-  = Push Item
-  | WaitMicroS Int
-  | Flush
-  deriving (Show)
-
-newtype Item = Item Int
-  deriving (Eq, Ord, Show)
-
-step :: Gen Step
-step =
-  Gen.frequency
-    [ (5, Gen.constant (Push (Item 0))),
-      (5, WaitMicroS <$> waitMicroS),
-      (1, Gen.constant Flush)
-    ]
-
-numberItems :: [Step] -> [Step]
-numberItems = snd . Data.List.mapAccumL numberItem 0
-
-numberItem :: Int -> Step -> (Int, Step)
-numberItem counter step =
-  case step of
-    Push (Item _) -> (counter + 1, Push (Item counter))
-    _ -> (counter, step)
-
-waitMicroS :: Gen Int
-waitMicroS = Gen.int (Range.linear 0 maxWaitMicroS)
-
-maxWaitMicroS :: Int
-maxWaitMicroS = 10000
-
-toItem :: Step -> Maybe Item
-toItem step =
-  case step of
-    Push item -> Just item
-    WaitMicroS _ -> Nothing
-    Flush -> Nothing
-
-run :: Natural -> Int -> [Step] -> IO [Item]
-run size frequencyInMicroSeconds steps = do
-  -- Setup the buffer to play the steps through.
-  resultQueue <- STM.newTQueueIO
-  buffer <-
-    Buffer.new
-      Buffer.defaultSettings
-        { Buffer.write = writeToQueue resultQueue,
-          Buffer.size,
-          Buffer.frequencyInMicroSeconds
-        }
-  -- Play the steps one by one.
-  Data.Foldable.traverse_ (play buffer) steps
-  -- Give the queue the opportunity to flush by itself.
-  Control.Concurrent.threadDelay (2 * maxWaitMicroS)
-  mconcat <$> STM.atomically (STM.flushTQueue resultQueue)
-
-play :: Buffer.Buffer Item -> Step -> IO ()
-play buffer step =
-  case step of
-    Push item -> Buffer.push buffer item
-    WaitMicroS delay -> Control.Concurrent.threadDelay delay
-    Flush -> Buffer.flush buffer
-
-writeToQueue :: STM.TQueue [a] -> NonEmpty.NonEmpty a -> IO ()
-writeToQueue queue list = STM.atomically (STM.writeTQueue queue (NonEmpty.toList list))
