diff --git a/docs/source/interface.rst b/docs/source/interface.rst
index 81435b1f0c9267cb42561ffcf1844afd9d1eb197..d3223d6fe60e9a9af9a009050a8a2b181816fe9d 100644
--- a/docs/source/interface.rst
+++ b/docs/source/interface.rst
@@ -154,12 +154,14 @@ This endpoint accepts no request body.
 The response is **OK** with ``application/json`` content-type response body like::
 
   { "total": <integer>
+  , "spendable": <integer>
   , "unblinded-tokens": [<unblinded token string>, ...]
   , "lease-maintenance-spending": <spending object>
   }
 
 The value associated with ``total`` gives the total number of unblinded tokens in the node's database
 (independent of any limit placed on this query).
+The value associated with ``spendable`` gives the number of unblinded tokens in the node's database which can actually be spent.
 The value associated with ``unblinded-tokens`` gives the requested list of unblinded tokens.
 
 The ``<spending object>`` may be ``null`` if the lease maintenance process has never run.
diff --git a/src/_zkapauthorizer/resource.py b/src/_zkapauthorizer/resource.py
index e675ed204ad829444b6ad9d0818e2a1b09073e32..1663b0c291d030e16614f894e54104f0a4dc73fe 100644
--- a/src/_zkapauthorizer/resource.py
+++ b/src/_zkapauthorizer/resource.py
@@ -370,6 +370,7 @@ class _UnblindedTokenCollection(Resource):
 
         return dumps({
             u"total": len(unblinded_tokens),
+            u"spendable": self._store.count_unblinded_tokens(),
             u"unblinded-tokens": list(islice((
                 token
                 for token
diff --git a/src/_zkapauthorizer/tests/test_client_resource.py b/src/_zkapauthorizer/tests/test_client_resource.py
index 5bee598c5c935b48ce61c1ce09669ee39daf2d44..09e1bf0f527bc7b80ebda5143f8097c8e48334b3 100644
--- a/src/_zkapauthorizer/tests/test_client_resource.py
+++ b/src/_zkapauthorizer/tests/test_client_resource.py
@@ -762,6 +762,7 @@ class UnblindedTokenTests(TestCase):
             requesting,
             succeeded_with_unblinded_tokens_with_matcher(
                 num_tokens,
+                Equals(num_tokens),
                 AllMatch(
                     MatchesAll(
                         GreaterThan(position),
@@ -896,6 +897,7 @@ class UnblindedTokenTests(TestCase):
 
 def succeeded_with_unblinded_tokens_with_matcher(
         all_token_count,
+        match_spendable_token_count,
         match_unblinded_tokens,
         match_lease_maint_spending,
 ):
@@ -920,6 +922,7 @@ def succeeded_with_unblinded_tokens_with_matcher(
                 succeeded(
                     ContainsDict({
                         u"total": Equals(all_token_count),
+                        u"spendable": match_spendable_token_count,
                         u"unblinded-tokens": match_unblinded_tokens,
                         u"lease-maintenance-spending": match_lease_maint_spending,
                     }),
@@ -941,11 +944,12 @@ def succeeded_with_unblinded_tokens(all_token_count, returned_token_count):
     """
     return succeeded_with_unblinded_tokens_with_matcher(
         all_token_count,
-        MatchesAll(
+        match_spendable_token_count=Equals(all_token_count),
+        match_unblinded_tokens=MatchesAll(
             HasLength(returned_token_count),
             AllMatch(IsInstance(unicode)),
         ),
-        matches_lease_maintenance_spending(),
+        match_lease_maint_spending=matches_lease_maintenance_spending(),
     )
 
 def matches_lease_maintenance_spending():