diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,14 @@
 The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
 and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
 
+## 0.23.1
+### Added
+- Allow xpub eviction from cache via API.
+- Clarify cache address addition code.
+
+### Fixed
+- Balances were incorrectly computed in cache when new transactions arrived.
+
 ## 0.23.0
 ### Added
 - Support for Redis transactions.
diff --git a/haskoin-store.cabal b/haskoin-store.cabal
--- a/haskoin-store.cabal
+++ b/haskoin-store.cabal
@@ -4,10 +4,10 @@
 --
 -- see: https://github.com/sol/hpack
 --
--- hash: 48de78f8abbf3329c05bf1a04f570321fafd1840f48c22f42955091321a6dbca
+-- hash: 9d22c35aa5ef0720ae62cf77e32895f6ef50a8622058d59995ee46d909929821
 
 name:           haskoin-store
-version:        0.23.0
+version:        0.23.1
 synopsis:       Storage and index for Bitcoin and Bitcoin Cash
 description:    Store and index Bitcoin or Bitcoin Cash blocks, transactions, balances and unspent outputs.
                 All data is available via REST API in JSON or binary format.
diff --git a/src/Haskoin/Store.hs b/src/Haskoin/Store.hs
--- a/src/Haskoin/Store.hs
+++ b/src/Haskoin/Store.hs
@@ -36,7 +36,7 @@
     , StoreEvent (..)
     , PubExcept (..)
     , TxId (..)
-    , TxAfterHeight (..)
+    , GenericResult (..)
 
     , StoreWrite (..)
 
diff --git a/src/Haskoin/Store/Cache.hs b/src/Haskoin/Store/Cache.hs
--- a/src/Haskoin/Store/Cache.hs
+++ b/src/Haskoin/Store/Cache.hs
@@ -19,13 +19,14 @@
     , CacheWriterInbox
     , CacheWriterMessage (..)
     , cacheWriter
+    , isXPubCached
+    , delXPubKeys
     ) where
 
 import           Control.DeepSeq           (NFData)
-import           Control.Monad             (forM, forM_, forever, unless, void,
-                                            when)
-import           Control.Monad.Logger      (MonadLoggerIO, logDebugS, logErrorS,
-                                            logInfoS, logWarnS)
+import           Control.Monad             (forM, forM_, forever, void)
+import           Control.Monad.Logger      (MonadLoggerIO, logErrorS, logInfoS,
+                                            logWarnS)
 import           Control.Monad.Reader      (ReaderT (..), asks)
 import           Control.Monad.Trans       (lift)
 import           Control.Monad.Trans.Maybe (MaybeT (..), runMaybeT)
@@ -33,10 +34,10 @@
 import           Data.ByteString           (ByteString)
 import qualified Data.ByteString.Short     as BSS
 import           Data.Either               (rights)
+import           Data.HashMap.Strict       (HashMap)
 import qualified Data.HashMap.Strict       as HashMap
 import qualified Data.IntMap.Strict        as IntMap
 import           Data.List                 (nub, sort)
-import           Data.Map.Strict           (Map)
 import qualified Data.Map.Strict           as Map
 import           Data.Maybe                (catMaybes, mapMaybe)
 import           Data.Serialize            (decode, encode)
@@ -176,11 +177,8 @@
     isXPubCached xpub >>= \case
         True -> do
             txs <- cacheGetXPubTxs xpub start offset limit
-            $(logDebugS) "Cache" $
-                "Cache hit for " <> cs (show (length txs)) <> " xpub txs"
             return txs
         False -> do
-            $(logDebugS) "Cache" $ "Cache miss for xpub txs request"
             newXPubC xpub >>= \(bals, t) ->
                 if t
                     then cacheGetXPubTxs xpub start offset limit
@@ -197,13 +195,8 @@
     isXPubCached xpub >>= \case
         True -> do
             bals <- cacheGetXPubBalances xpub
-            $(logDebugS) "Cache" $
-                "Cache hit for unspents on an xpub with " <>
-                cs (show (length bals)) <>
-                " balances"
             process bals
         False -> do
-            $(logDebugS) "Cache" $ "Cache miss for xpub unspents request"
             newXPubC xpub >>= \(bals, t) ->
                 if t
                     then process bals
@@ -238,11 +231,8 @@
     isXPubCached xpub >>= \case
         True -> do
             bals <- cacheGetXPubBalances xpub
-            $(logDebugS) "Cache" $
-                "Cache hit for " <> cs (show (length bals)) <> " xpub balances"
             return bals
         False -> do
-            $(logDebugS) "Cache" "Cache miss for xpub balances request"
             fst <$> newXPubC xpub
 
 isXPubCached :: MonadIO m => XPubSpec -> CacheT m Bool
@@ -445,21 +435,21 @@
     => CacheConfig
     -> CacheWriterInbox
     -> m ()
-cacheWriter cfg inbox =
-    runReaderT
-        (newBlockC >> forever (pruneDB >> receive inbox >>= cacheWriterReact))
-        cfg
+cacheWriter cfg inbox = runReaderT go cfg
+  where
+    go = do
+        newBlockC
+        forever $ do
+            pruneDB
+            x <- receive inbox
+            cacheWriterReact x
 
 pruneDB :: (MonadLoggerIO m, StoreRead m) => CacheT m Integer
 pruneDB = do
     x <- asks cacheMax
     s <- runRedis Redis.dbsize
     if s > x
-        then do
-            n <- flush (s - x)
-            when (n > 0) $
-                $(logDebugS) "Cache" $ "Pruned " <> cs (show n) <> " keys"
-            return n
+        then flush (s - x)
         else return 0
   where
     flush n =
@@ -505,13 +495,9 @@
     let n = lenNotNull bals
     if x <= n
         then do
-            $(logDebugS) "Cache" $
-                "Caching xpub with " <> cs (show n) <> " used addresses"
             go bals
             return (bals, True)
         else do
-            $(logDebugS) "Cache" $
-                "Not caching xpub with " <> cs (show n) <> " used addresses"
             return (bals, False)
   where
     op XPubUnspent {xPubUnspent = u} = (unspentPoint u, unspentBlock u)
@@ -626,39 +612,40 @@
 importMultiTxC :: (StoreRead m, MonadLoggerIO m) => [TxData] -> CacheT m ()
 importMultiTxC txs = do
     addrmap <-
-        Map.fromList . catMaybes . zipWith (\a -> fmap (a, )) alladdrs <$>
+        HashMap.fromList . catMaybes . zipWith (\a -> fmap (a, )) alladdrs <$>
         cacheGetAddrsInfo alladdrs
+    let addrs = HashMap.keys addrmap
     balmap <-
-        Map.fromList . zipWith (,) alladdrs <$>
-        mapM (lift . getBalance) (Map.keys addrmap)
+        HashMap.fromList . zipWith (,) addrs <$> mapM (lift . getBalance) addrs
     unspentmap <-
-        Map.fromList . catMaybes . zipWith (\p -> fmap (p, )) allops <$>
+        HashMap.fromList . catMaybes . zipWith (\p -> fmap (p, )) allops <$>
         lift (mapM getUnspent allops)
     gap <- getMaxGap
     now <- systemSeconds <$> liftIO getSystemTime
-    newaddrs <-
-        runRedisTx (redisWatchXPubCached (allxpubs addrmap)) $ \ys ->
-            if or ys
-                then do
-                    let xpubs = map fst . filter snd $ zip (allxpubs addrmap) ys
-                        addrmap' = faddrmap xpubs addrmap
-                    x <- redisImportMultiTx addrmap' unspentmap txs
-                    y <- redisUpdateBalances addrmap' balmap
-                    z <- redisTouchKeys now (allxpubs addrmap')
-                    n <- redisGetNewAddrs gap addrmap'
-                    return $ x >> y >> z >> n
-                else return (pure Map.empty)
-    unless (Map.null newaddrs) $ cacheAddAddresses newaddrs
+    addrs' <-
+        runRedisTx (watchRedisXPubBalances (allxpubs addrmap)) $ \bals -> do
+            let xmap = HashMap.filter (not . null) (HashMap.fromList bals)
+                addrmap' = faddrmap (HashMap.keysSet xmap) addrmap
+            x <-
+                if not (HashMap.null xmap)
+                    then do
+                        x <- redisImportMultiTx addrmap' unspentmap txs
+                        y <- redisUpdateBalances addrmap' balmap
+                        z <- redisTouchKeys now (allxpubs addrmap')
+                        return $ x >> y >> z >> return ()
+                    else return (pure ())
+            return $ x >> return (getNewAddrs gap xmap (HashMap.elems addrmap'))
+    cacheAddAddresses addrs'
   where
-    faddrmap xpubs = Map.filter ((`elem` xpubs) . addressXPubSpec)
+    faddrmap xpubs = HashMap.filter ((`elem` xpubs) . addressXPubSpec)
     allops = map snd $ concatMap txInputs txs <> concatMap txOutputs txs
     alladdrs = nub . map fst $ concatMap txInputs txs <> concatMap txOutputs txs
-    allxpubs addrmap = nub . map addressXPubSpec $ Map.elems addrmap
+    allxpubs addrmap = nub . map addressXPubSpec $ HashMap.elems addrmap
 
 redisImportMultiTx ::
        (Monad f, RedisCtx m f)
-    => Map Address AddressXPub
-    -> Map OutPoint Unspent
+    => HashMap Address AddressXPub
+    -> HashMap OutPoint Unspent
     -> [TxData]
     -> m (f ())
 redisImportMultiTx addrmap unspentmap txs = do
@@ -666,12 +653,12 @@
     return $ sequence xs >> return ()
   where
     uns p i =
-        case Map.lookup p unspentmap of
+        case HashMap.lookup p unspentmap of
             Just u ->
                 redisAddXPubUnspents (addressXPubSpec i) [(p, unspentBlock u)]
             Nothing -> redisRemXPubUnspents (addressXPubSpec i) [p]
     addtx tx a p =
-        case Map.lookup a addrmap of
+        case HashMap.lookup a addrmap of
             Just i -> do
                 x <-
                     redisAddXPubTxs
@@ -685,7 +672,7 @@
                 return $ x >> y >> return ()
             Nothing -> return (pure ())
     remtx tx a p =
-        case Map.lookup a addrmap of
+        case HashMap.lookup a addrmap of
             Just i -> do
                 x <- redisRemXPubTxs (addressXPubSpec i) [txHash (txData tx)]
                 y <- uns p i
@@ -715,12 +702,12 @@
 
 redisUpdateBalances ::
        (Monad f, RedisCtx m f)
-    => Map Address AddressXPub
-    -> Map Address Balance
+    => HashMap Address AddressXPub
+    -> HashMap Address Balance
     -> m (f ())
 redisUpdateBalances addrmap balmap =
-    fmap (void . sequence) . forM (Map.keys addrmap) $ \a ->
-        case (Map.lookup a addrmap, Map.lookup a balmap) of
+    fmap (fmap mconcat . sequence) . forM (HashMap.keys addrmap) $ \a ->
+        case (HashMap.lookup a addrmap, HashMap.lookup a balmap) of
             (Just ainfo, Just bal) ->
                 redisAddXPubBalances (addressXPubSpec ainfo) [xpubbal ainfo bal]
             _ -> return (pure ())
@@ -730,125 +717,74 @@
 
 cacheAddAddresses ::
        (StoreRead m, MonadLoggerIO m)
-    => Map Address AddressXPub
+    => [(Address, AddressXPub)]
     -> CacheT m ()
-cacheAddAddresses addrmap = do
+cacheAddAddresses [] = return ()
+cacheAddAddresses addrs = do
     gap <- getMaxGap
-    newmap <- runRedis (redisGetNewAddrs gap addrmap)
-    balmap <- Map.fromList <$> mapM getbal (Map.keys newmap)
-    utxomap <- Map.fromList <$> mapM getutxo (Map.keys newmap)
-    txmap <- Map.fromList <$> mapM gettxmap (Map.keys newmap)
-    let notnulls = getnotnull newmap balmap
-        xpubbals = getxpubbals newmap balmap
-        unspents = getunspents newmap utxomap
-        txs = gettxs newmap txmap
-        xpubs = map addressXPubSpec (Map.elems addrmap)
-    newaddrs <-
-        runRedisTx (redisWatchXPubCached xpubs) $ \ys -> do
-            let xpubs' = map fst . filter snd $ zip xpubs ys
-                xpubbals' =
-                    HashMap.filterWithKey (\x _ -> x `elem` xpubs') xpubbals
-                unspents' =
-                    HashMap.filterWithKey (\x _ -> x `elem` xpubs') unspents
-                txs' = HashMap.filterWithKey (\x _ -> x `elem` xpubs') txs
-                notnulls' =
-                    Map.filter (\x -> addressXPubSpec x `elem` xpubs') notnulls
+    balmap' <- HashMap.fromListWith (<>) <$> mapM (uncurry getbal) addrs
+    utxomap' <- HashMap.fromListWith (<>) <$> mapM (uncurry getutxo) addrs
+    txmap' <- HashMap.fromListWith (<>) <$> mapM (uncurry gettxmap) addrs
+    let xpubs' = nub (map addressXPubSpec (Map.elems amap))
+    addrs' <-
+        runRedisTx (watchRedisXPubBalances xpubs') $ \bals -> do
+            let xmap = HashMap.filter (not . null) (HashMap.fromList bals)
+                xpubs = HashMap.keysSet xmap
+                balmap = HashMap.filterWithKey (\k _ -> k `elem` xpubs) balmap'
+                utxomap =
+                    HashMap.filterWithKey (\k _ -> k `elem` xpubs) utxomap'
+                txmap = HashMap.filterWithKey (\k _ -> k `elem` xpubs) txmap'
+                notnulls = getnotnull balmap
             x' <-
-                forM (HashMap.toList xpubbals') $ \(x, bs) ->
+                forM (HashMap.toList balmap) $ \(x, bs) ->
                     redisAddXPubBalances x bs
             y' <-
-                forM (HashMap.toList unspents') $ \(x, us) ->
-                    redisAddXPubUnspents x (map uns us)
-            z' <- forM (HashMap.toList txs') $ \(x, ts) -> redisAddXPubTxs x ts
-            new <- redisGetNewAddrs gap notnulls'
+                forM (HashMap.toList utxomap) $ \(x, us) ->
+                    redisAddXPubUnspents x us
+            z' <- forM (HashMap.toList txmap) $ \(x, ts) -> redisAddXPubTxs x ts
             return $ do
                 _ <- sequence x'
                 _ <- sequence y'
                 _ <- sequence z'
-                new
-    unless (null newaddrs) $ cacheAddAddresses newaddrs
+                return $ getNewAddrs gap xmap notnulls
+    cacheAddAddresses addrs'
   where
-    uns u = (unspentPoint u, unspentBlock u)
-    gettxs newmap txmap =
-        let f a ts =
-                case Map.lookup a newmap of
-                    Nothing -> Nothing
-                    Just i  -> Just (addressXPubSpec i, ts)
-            g m (x, ts) = HashMap.insertWith (<>) x ts m
-         in foldl g HashMap.empty (mapMaybe (uncurry f) (Map.toList txmap))
-    getunspents newmap utxomap =
-        let f a us =
-                case Map.lookup a newmap of
-                    Nothing -> Nothing
-                    Just i  -> Just (addressXPubSpec i, us)
-            g m (x, us) = HashMap.insertWith (<>) x us m
-         in foldl g HashMap.empty (mapMaybe (uncurry f) (Map.toList utxomap))
-    getxpubbals newmap balmap =
-        let f a b =
-                case Map.lookup a newmap of
-                    Nothing -> Nothing
-                    Just i ->
-                        Just
-                            ( addressXPubSpec i
-                            , XPubBal
-                                  {xPubBal = b, xPubBalPath = addressXPubPath i})
-            g m (x, b) = HashMap.insertWith (<>) x [b] m
-         in foldl g HashMap.empty (mapMaybe (uncurry f) (Map.toList balmap))
-    getnotnull newmap balmap =
-        let f a _ =
-                case Map.lookup a newmap of
-                    Nothing -> Nothing
-                    Just i  -> Just (a, i)
-         in Map.fromList . mapMaybe (uncurry f) . Map.toList $
-            Map.filter (not . nullBalance) balmap
-    getbal a = (a, ) <$> lift (getBalance a)
-    getutxo a = (a, ) <$> lift (getAddressUnspents a Nothing Nothing)
-    gettxmap a = (a, ) <$> lift (getAddressTxs a Nothing Nothing)
+    amap = Map.fromList addrs
+    getnotnull =
+        let f xpub =
+                map $ \bal ->
+                    AddressXPub
+                        { addressXPubSpec = xpub
+                        , addressXPubPath = xPubBalPath bal
+                        }
+            g = filter (not . nullBalance . xPubBal)
+         in concatMap (uncurry f) . HashMap.toList . HashMap.map g
+    getbal a i =
+        let f b =
+                ( addressXPubSpec i
+                , [XPubBal {xPubBal = b, xPubBalPath = addressXPubPath i}])
+         in f <$> lift (getBalance a)
+    getutxo a i =
+        let f us =
+                ( addressXPubSpec i
+                , map (\u -> (unspentPoint u, unspentBlock u)) us)
+         in f <$> lift (getAddressUnspents a Nothing Nothing)
+    gettxmap a i =
+        let f ts = (addressXPubSpec i, ts)
+         in f <$> lift (getAddressTxs a Nothing Nothing)
 
-redisGetNewAddrs ::
-       (Monad f, RedisCtx m f)
-    => KeyIndex
-    -> Map Address AddressXPub
-    -> m (f (Map Address AddressXPub))
-redisGetNewAddrs gap addrmap =
-    xbalmap >>= \xbalmap' ->
-        return $ do
-            xbmap' <- xbalmap'
-            return . Map.fromList $
-                concatMap (uncurry newaddrs) (HashMap.toList xbmap')
+
+getNewAddrs ::
+       KeyIndex
+    -> HashMap XPubSpec [XPubBal]
+    -> [AddressXPub]
+    -> [(Address, AddressXPub)]
+getNewAddrs gap xpubs = concatMap f
   where
-    xbalmap = do
-        xbs <-
-            forM xpubs $ \xpub -> do
-                bals <- redisGetXPubBalances xpub
-                return $ bals >>= return . (xpub, )
-        return $ do
-            xbs' <- sequence xbs
-            return $ HashMap.fromList xbs'
-    newaddrs xpub bals =
-        let paths = HashMap.lookupDefault [] xpub xpubmap
-            ext = maximum . (0 :) . map (head . tail) $ filter ((== 0) . head) paths
-            chg = maximum . (0 :) . map (head . tail) $ filter ((== 1) . head) paths
-            extnew =
-                addrsToAdd
-                    bals
-                    gap
-                    AddressXPub
-                        {addressXPubSpec = xpub, addressXPubPath = [0, ext]}
-            intnew =
-                addrsToAdd
-                    bals
-                    gap
-                    AddressXPub
-                        {addressXPubSpec = xpub, addressXPubPath = [1, chg]}
-         in extnew <> intnew
-    xpubs = HashMap.keys xpubmap
-    xpubmap =
-        let f xmap ainfo =
-                let xpub = addressXPubSpec ainfo
-                    path = addressXPubPath ainfo
-                 in HashMap.insertWith (<>) xpub [path] xmap
-         in foldl f HashMap.empty (Map.elems addrmap)
+    f a =
+        case HashMap.lookup (addressXPubSpec a) xpubs of
+            Nothing   -> []
+            Just bals -> addrsToAdd gap bals a
 
 syncMempoolC :: (MonadLoggerIO m, StoreRead m) => CacheT m ()
 syncMempoolC = do
@@ -972,32 +908,26 @@
         is' <- sequence is
         return $ map (eitherToMaybe . decode =<<) is'
 
-addrsToAdd ::
-       [XPubBal]
-    -> KeyIndex
-    -> AddressXPub
-    -> [(Address, AddressXPub)]
-addrsToAdd xbals gap addrinfo =
-    let headi = head (addressXPubPath addrinfo)
-        maxi =
-            maximum . (0 :) . map (head . tail . xPubBalPath) $
-            filter ((== headi) . head . xPubBalPath) xbals
-        xpub = addressXPubSpec addrinfo
-        newi = head (tail (addressXPubPath addrinfo))
-        genixs =
-            if maxi - newi < gap
-                then [maxi + 1 .. newi + gap]
-                else []
-        paths = map (Deriv :/ headi :/) genixs
-        keys = map (\p -> derivePubPath p (xPubSpecKey xpub)) paths
-        list = map pathToList paths
-        xpubf = xPubAddrFunction (xPubDeriveType xpub)
-        addrs = map xpubf keys
-     in zipWith
-            (\a p ->
-                 (a, AddressXPub {addressXPubSpec = xpub, addressXPubPath = p}))
-            addrs
-            list
+addrsToAdd :: KeyIndex -> [XPubBal] -> AddressXPub -> [(Address, AddressXPub)]
+addrsToAdd gap xbals addrinfo
+    | null fbals = []
+    | otherwise = zipWith f addrs list
+  where
+    f a p = (a, AddressXPub {addressXPubSpec = xpub, addressXPubPath = p})
+    dchain = head (addressXPubPath addrinfo)
+    fbals = filter ((== dchain) . head . xPubBalPath) xbals
+    maxidx = maximum (map (head . tail . xPubBalPath) fbals)
+    xpub = addressXPubSpec addrinfo
+    aidx = (head . tail) (addressXPubPath addrinfo)
+    ixs =
+        if gap > maxidx - aidx
+            then [maxidx + 1 .. aidx + gap]
+            else []
+    paths = map (Deriv :/ dchain :/) ixs
+    keys = map (\p -> derivePubPath p (xPubSpecKey xpub)) paths
+    list = map pathToList paths
+    xpubf = xPubAddrFunction (xPubDeriveType xpub)
+    addrs = map xpubf keys
 
 sortTxData :: [TxData] -> [TxData]
 sortTxData tds =
diff --git a/src/Haskoin/Store/Common.hs b/src/Haskoin/Store/Common.hs
--- a/src/Haskoin/Store/Common.hs
+++ b/src/Haskoin/Store/Common.hs
@@ -34,7 +34,7 @@
     , transactionData
     , fromTransaction
     , toTransaction
-    , TxAfterHeight(..)
+    , GenericResult(..)
     , TxId(..)
     , PeerInformation(..)
     , XPubBal(..)
@@ -1164,16 +1164,16 @@
                     return $ EventBlock i
                 _ -> fail $ "Could not recognize event type: " <> t
 
-newtype TxAfterHeight = TxAfterHeight
-    { txAfterHeight :: Maybe Bool
+newtype GenericResult a = GenericResult
+    { getResult :: a
     } deriving (Show, Eq, Generic, Serialize, NFData)
 
-instance ToJSON TxAfterHeight where
-    toJSON (TxAfterHeight b) = object ["result" .= b]
+instance ToJSON a => ToJSON (GenericResult a) where
+    toJSON (GenericResult b) = object ["result" .= b]
 
-instance FromJSON TxAfterHeight where
+instance FromJSON a => FromJSON (GenericResult a) where
     parseJSON =
-        A.withObject "txafterheight" $ \o -> TxAfterHeight <$> o .: "result"
+        A.withObject "result" $ \o -> GenericResult <$> o .: "result"
 
 newtype TxId =
     TxId TxHash
diff --git a/src/Haskoin/Store/Web.hs b/src/Haskoin/Store/Web.hs
--- a/src/Haskoin/Store/Web.hs
+++ b/src/Haskoin/Store/Web.hs
@@ -64,7 +64,7 @@
 import           Haskoin.Node                  (Chain, Manager, OnlinePeer (..),
                                                 chainGetBest, managerGetPeers,
                                                 sendMessage)
-import           Haskoin.Store.Cache           (CacheT, withCache)
+import           Haskoin.Store.Cache           (CacheT, withCache, delXPubKeys)
 import           Haskoin.Store.Common          (BlockData (..), BlockRef (..),
                                                 BlockTx (..), DeriveType (..),
                                                 Event (..), HealthCheck (..),
@@ -73,7 +73,7 @@
                                                 PubExcept (..), StoreEvent (..),
                                                 StoreInput (..), StoreRead (..),
                                                 Transaction (..),
-                                                TxAfterHeight (..), TxData (..),
+                                                GenericResult (..), TxData (..),
                                                 TxId (..), UnixTime, Unspent,
                                                 XPubBal (..), XPubSpec (..),
                                                 applyOffset, blockAtOrBefore,
@@ -138,11 +138,11 @@
 
 data WebLimits =
     WebLimits
-        { maxLimitCount   :: !Word32
-        , maxLimitFull    :: !Word32
-        , maxLimitOffset  :: !Word32
-        , maxLimitDefault :: !Word32
-        , maxLimitGap     :: !Word32
+        { maxLimitCount      :: !Word32
+        , maxLimitFull       :: !Word32
+        , maxLimitOffset     :: !Word32
+        , maxLimitDefault    :: !Word32
+        , maxLimitGap        :: !Word32
         , maxLimitInitialGap :: !Word32
         }
     deriving (Eq, Show)
@@ -616,6 +616,18 @@
             protoSerialNet proto txs'
         else protoSerial proto txs
 
+scottyXpubEvict :: MonadLoggerIO m => WebT m ()
+scottyXpubEvict =
+    lift (asks (storeCache . webStore)) >>= \case
+        Nothing -> S.raise ThingNotFound
+        Just cache -> do
+            setHeaders
+            xpub <- parseXpub
+            proto <- setupBin
+            n <- withCache cache (delXPubKeys [xpub])
+            protoSerial proto (GenericResult (n > 0))
+
+
 scottyXpubUnspents :: MonadLoggerIO m => WebT m ()
 scottyXpubUnspents = do
     setHeaders
@@ -764,6 +776,7 @@
         S.get "/xpub/:xpub/transactions" $ scottyXpubTxs False
         S.get "/xpub/:xpub/transactions/full" $ scottyXpubTxs True
         S.get "/xpub/:xpub/unspent" scottyXpubUnspents
+        S.get "/xpub/:xpub/evict" scottyXpubEvict
         S.get "/xpub/:xpub" scottyXpubSummary
         S.post "/transactions" scottyPostTx
         S.get "/dbstats" scottyDbStats
@@ -1015,12 +1028,12 @@
     => Int -- ^ how many ancestors to test before giving up
     -> BlockHeight
     -> TxHash
-    -> m TxAfterHeight
+    -> m (GenericResult (Maybe Bool))
 cbAfterHeight d h t
-    | d <= 0 = return $ TxAfterHeight Nothing
+    | d <= 0 = return $ GenericResult Nothing
     | otherwise = do
         x <- fmap snd <$> tst d t
-        return $ TxAfterHeight x
+        return $ GenericResult x
   where
     tst e x
         | e <= 0 = return Nothing
diff --git a/test/Haskoin/Store/CommonSpec.hs b/test/Haskoin/Store/CommonSpec.hs
--- a/test/Haskoin/Store/CommonSpec.hs
+++ b/test/Haskoin/Store/CommonSpec.hs
@@ -20,10 +20,10 @@
                                           PeerInformation (..), Prev (..),
                                           PubExcept (..), Spender (..),
                                           StoreInput (..), StoreOutput (..),
-                                          Transaction (..), TxAfterHeight (..),
-                                          TxData (..), TxId (..), Unspent (..),
-                                          XPubBal (..), XPubSpec (..),
-                                          XPubSummary (..), XPubUnspent (..))
+                                          Transaction (..), TxData (..),
+                                          TxId (..), Unspent (..), XPubBal (..),
+                                          XPubSpec (..), XPubSummary (..),
+                                          XPubUnspent (..))
 import           Network.Haskoin.Test    (arbitraryAddress, arbitraryBlockHash,
                                           arbitraryBlockHeader,
                                           arbitraryOutPoint,
@@ -59,8 +59,6 @@
         prop "identity for xpub summary" $ \x -> testSerial (x :: XPubSummary)
         prop "identity for health check" $ \x -> testSerial (x :: HealthCheck)
         prop "identity for event" $ \x -> testSerial (x :: Event)
-        prop "identity for tx after height" $ \x ->
-            testSerial (x :: TxAfterHeight)
         prop "identity for txid" $ \x -> testSerial (x :: TxId)
         prop "identity for publish exception" $ \x ->
             testSerial (x :: PubExcept)
@@ -79,8 +77,6 @@
         prop "identity for health check" $ \x -> testJSON (x :: HealthCheck)
         prop "identity for event" $ \x -> testJSON (x :: Event)
         prop "identity for txid" $ \x -> testJSON (x :: TxId)
-        prop "identity for tx after height" $ \x ->
-            testJSON (x :: TxAfterHeight)
         prop "identity for peer information" $ \x ->
             testJSON (x :: PeerInformation)
 
@@ -112,9 +108,6 @@
 
 testSerial :: (Eq a, Show a, Serialize a) => a -> Expectation
 testSerial input = (decode . encode) input `shouldBe` Right input
-
-instance Arbitrary TxAfterHeight where
-    arbitrary = TxAfterHeight <$> arbitrary
 
 instance Arbitrary DeriveType where
     arbitrary = elements [DeriveNormal, DeriveP2SH, DeriveP2WPKH]
