diff --git a/nixos/modules/issuer.nix b/nixos/modules/issuer.nix
index c9424785ba94d9c6c16f5e5e636706240b316b2d..b032100f1f20f04f174aa8f03faf5bf22a97b226 100644
--- a/nixos/modules/issuer.nix
+++ b/nixos/modules/issuer.nix
@@ -38,6 +38,15 @@ in {
         algorithm or Ristretto for Ristretto-flavored PrivacyPass.
       '';
     };
+    services.private-storage-issuer.tokensPerVoucher = lib.mkOption {
+      default = null;
+      type = lib.types.nullOr lib.types.int;
+      example = 50000;
+      description = ''
+        If not null, a value to pass to PaymentServer for
+        ``--tokens-per-voucher``.
+      '';
+    };
     services.private-storage-issuer.ristrettoSigningKeyPath = lib.mkOption {
       default = null;
       type = lib.types.path;
@@ -210,8 +219,10 @@ in {
             "--stripe-endpoint-domain ${cfg.stripeEndpointDomain} " +
             "--stripe-endpoint-scheme ${cfg.stripeEndpointScheme} " +
             "--stripe-endpoint-port ${toString cfg.stripeEndpointPort}";
+
+          redemptionConfig = lib.optionalString (cfg.tokensPerVoucher != null) "--tokens-per-voucher ${builtins.toString cfg.tokensPerVoucher}";
         in
-          "${cfg.package.exePath} ${originArgs} ${issuerArgs} ${databaseArgs} ${httpArgs} ${stripeArgs}";
+          "${cfg.package.exePath} ${originArgs} ${issuerArgs} ${databaseArgs} ${httpArgs} ${stripeArgs} ${redemptionConfig}";
     };
 
     # PaymentServer runs as this user and group by default
diff --git a/nixos/pkgs/zkapissuer/repo.json b/nixos/pkgs/zkapissuer/repo.json
index c995e4e607a4a2e215b403c5fc0e316058b24cb0..2963aafabef1503608195f7903fe202f11dd70a8 100644
--- a/nixos/pkgs/zkapissuer/repo.json
+++ b/nixos/pkgs/zkapissuer/repo.json
@@ -1,8 +1,8 @@
 {
   "owner": "PrivateStorageio",
   "repo": "PaymentServer",
-  "rev": "dcb400968bee2d42b293531317d42d31593d4224",
+  "rev": "b1bd39ffb7269e5334bf068263733472b27b38ef",
   "branch": "main",
   "outputHashAlgo": "sha512",
-  "outputHash": "14iwy71izijdgws9lvqb0jzhpa2imq47h0mb8s4sdk15anh5dci3m5zxxad8bpc5gxmai71pz297880nph2f52i538gjxs6n1m6vrl7"
+  "outputHash": "1jncsdyz83xphairk4rx47wrlkdn7s48dk8l3mnimal4h4x7zb34lyx2anm1nhxm7s52jv28rv4mvggc2dhsa21dsqhga3qggcpfi2m"
 }
\ No newline at end of file
diff --git a/nixos/tests/private-storage.nix b/nixos/tests/private-storage.nix
index b17b8f32ed494c0823f349166f9a28f1e3dcb876..e02f9c49550d7fa4994c3d6099eda1e9374a278c 100644
--- a/nixos/tests/private-storage.nix
+++ b/nixos/tests/private-storage.nix
@@ -19,6 +19,7 @@ let
   issuerURL = "http://issuer/";
 
   voucher = "xyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxy";
+  tokenCount = 1000;
 
   # The issuer's signing key.  Notionally, this is a secret key.  This is only
   # the value for this system test though so I don't care if it leaks to the
@@ -117,6 +118,7 @@ in {
         tls = false;
         issuer = "Ristretto";
         inherit ristrettoSigningKeyPath;
+        tokensPerVoucher = tokenCount;
         letsEncryptAdminEmail = "user@example.invalid";
         allowedChargeOrigins = [ "http://unused.invalid" ];
 
@@ -157,8 +159,7 @@ in {
   testScript = ourpkgs.lib.testing.makeTestScript {
     testpath = ./test_privatestorage.py;
     kwargs = {
-      inherit sshPrivateKeyFile pemFile introducerPort introducerFURL issuerURL ristrettoPublicKey voucher;
-
+      inherit sshPrivateKeyFile pemFile introducerPort introducerFURL issuerURL ristrettoPublicKey voucher tokenCount;
       # Supply some helper programs to help the tests stay a bit higher level.
       run_introducer = ./run-introducer.py;
       run_client = ./run-client.py;
diff --git a/nixos/tests/run-client.py b/nixos/tests/run-client.py
index df37bb48901a8c97dbe6889c86af2b40d52b22f3..8d3d82720ec94b4b91e6af8791aadc58cd7ce2ad 100755
--- a/nixos/tests/run-client.py
+++ b/nixos/tests/run-client.py
@@ -12,7 +12,7 @@ from subprocess import check_output
 from configparser import ConfigParser
 
 def main():
-    (nodePath, introducerFURL, issuerURL, publicKey) = argv[1:]
+    (nodePath, introducerFURL, issuerURL, publicKey, tokenCount) = argv[1:]
 
     run(["tahoe", "--version"])
     run([
@@ -34,10 +34,7 @@ def main():
     config.set(u"storageclient.plugins.privatestorageio-zkapauthz-v1", u"redeemer", u"ristretto")
     config.set(u"storageclient.plugins.privatestorageio-zkapauthz-v1", u"ristretto-issuer-root-url", issuerURL)
     config.set(u"storageclient.plugins.privatestorageio-zkapauthz-v1", u"allowed-public-keys", publicKey)
-    # This has to agree with the PaymentServer configuration at the configured
-    # issuer location.  Presently PaymentServer has 50000 hard-coded as the
-    # correct value.
-    config.set(u"storageclient.plugins.privatestorageio-zkapauthz-v1", u"default-token-count", u"50000")
+    config.set(u"storageclient.plugins.privatestorageio-zkapauthz-v1", u"default-token-count", tokenCount)
 
     with open("/tmp/client/tahoe.cfg", "wt") as cfg:
         config.write(cfg)
diff --git a/nixos/tests/test_privatestorage.py b/nixos/tests/test_privatestorage.py
index e1f34fa4f1b0f603168fe825871d8cb81f52d8ce..df2aeb9372042d9368736579090e70ab90097f43 100644
--- a/nixos/tests/test_privatestorage.py
+++ b/nixos/tests/test_privatestorage.py
@@ -37,6 +37,7 @@ def test(
         issuerURL,
         ristrettoPublicKey,
         voucher,
+        tokenCount,
 ):
     """
     """
@@ -92,15 +93,18 @@ def test(
     # It should have Eliot logging turned on as well.
     storage.succeed('[ -e /var/db/tahoe-lafs/storage/logs/eliot.json ]')
 
+    # Make sure the issuer is ready to accept connections.
+    issuer.wait_for_open_port(80)
+
     #
     # Storage appears to be working so try to get a client to speak with it.
     #
-    runOnNode(client, [run_client, "/tmp/client", introducerFURL, issuerURL, ristrettoPublicKey])
+    runOnNode(client, [run_client, "/tmp/client", introducerFURL, issuerURL, ristrettoPublicKey, str(tokenCount)])
     client.wait_for_open_port(3456)
 
     # Make sure the fake Stripe API server is ready for requests.
     try:
-        api_stripe_com.wait_for_unit("api.stripe.com")
+        api_stripe_com.wait_for_open_port(80)
     except:
         code, output = api_stripe_com.execute('journalctl -u api.stripe.com')
         api_stripe_com.log(output)
@@ -118,8 +122,9 @@ def test(
     except:
         # Dump the fake Stripe API server logs, too, since the error may arise
         # from a PaymentServer/Stripe interaction.
-        code, output = api_stripe_com.execute('journalctl -u api.stripe.com')
-        api_stripe_com.log(output)
+        for node, unit in [(api_stripe_com, "api.stripe.com"), (issuer, "zkapissuer")]:
+            code, output = node.execute(f'journalctl -u {unit}')
+            node.log(output)
 
         raise