diff --git a/morph/grid.config.json b/morph/grid.config.json
index c6ee26422d3af52d7618ffc84add6fc825e3f4d4..1df905600e25c75423070c7aede376d95ba9e4e2 100644
--- a/morph/grid.config.json
+++ b/morph/grid.config.json
@@ -3,4 +3,8 @@
 , "stripeSecretKeyPath": "../../PrivateStorageSecrets/stripe.secret"
 , "issuerDomain": "payments.privatestorage.io"
 , "letsEncryptAdminEmail": "jean-paul@privatestorage.io"
+, "allowedChargeOrigins": [
+    "https://privatestorage.io"
+  , "https://www.privatestorage.io"
+  ]
 }
diff --git a/morph/issuer.nix b/morph/issuer.nix
index 57ffd009d58064830a30d30af926263962dcc5d7..98d10d38cd49d1c0dda8a630ef7b622d5ea62284 100644
--- a/morph/issuer.nix
+++ b/morph/issuer.nix
@@ -3,6 +3,7 @@
 , stripeSecretKeyPath
 , issuerDomain
 , letsEncryptAdminEmail
+, allowedChargeOrigins
 , stateVersion
 , ...
 }: {
@@ -26,13 +27,14 @@
 
   services.private-storage-issuer = {
     enable = true;
-    # XXX This should be passed as a path.
-    ristrettoSigningKey = builtins.readFile (./.. + ristrettoSigningKeyPath);
+    tls = true;
+    ristrettoSigningKeyPath = ./.. + ristrettoSigningKeyPath;
     stripeSecretKeyPath = ./.. + stripeSecretKeyPath;
     database = "SQLite3";
     databasePath = "/var/db/vouchers.sqlite3";
     inherit letsEncryptAdminEmail;
     domain = issuerDomain;
+    inherit allowedChargeOrigins;
   };
 
   system.stateVersion = stateVersion;
diff --git a/morph/testing-grid.config.json b/morph/testing-grid.config.json
index 46cf4ff25c5eb0c6dffdba01f774c7862e300aa3..eca13fe1dd76fb37ea0a7b900b725217d33b970e 100644
--- a/morph/testing-grid.config.json
+++ b/morph/testing-grid.config.json
@@ -1,6 +1,11 @@
 { "publicStoragePort": 8898
 , "ristrettoSigningKeyPath": "../../PrivateStorageSecrets/ristretto.signing-key"
-, "stripeSecretKeyPath": "../../PrivateStorageSecrets/stripe.secret"
+, "stripeSecretKeyPath": "../../PrivateStorageSecrets/privatestorageio-testing-stripe.secret"
 , "issuerDomain": "payments.privatestorage-staging.com"
 , "letsEncryptAdminEmail": "jean-paul@privatestorage.io"
+, "allowedChargeOrigins": [
+    "http://localhost:5000"
+  , "https://privatestorage-staging.com"
+  , "https://www.privatestorage-staging.com"
+  ]
 }
diff --git a/nixos/modules/issuer.nix b/nixos/modules/issuer.nix
index b22cb07f749d85daed41bd4dcd59652bf266a37c..a65eed5a3539f2d5ba67870782635a1ae7209582 100644
--- a/nixos/modules/issuer.nix
+++ b/nixos/modules/issuer.nix
@@ -41,12 +41,12 @@ in {
         algorithm or Ristretto for Ristretto-flavored PrivacyPass.
       '';
     };
-    services.private-storage-issuer.ristrettoSigningKey = lib.mkOption {
+    services.private-storage-issuer.ristrettoSigningKeyPath = lib.mkOption {
       default = null;
-      type = lib.types.str;
+      type = lib.types.path;
       description = ''
-        The Ristretto signing key to use.  Required if the issuer is
-        ``Ristretto``.
+        The path to a file containing the Ristretto signing key to use.
+        Required if the issuer is ``Ristretto``.
       '';
     };
     services.private-storage-issuer.stripeSecretKeyPath = lib.mkOption {
@@ -56,6 +56,27 @@ in {
         and payment management.
       '';
     };
+    services.private-storage-issuer.stripeEndpointDomain = lib.mkOption {
+      type = lib.types.str;
+      description = ''
+        The domain name for the Stripe API HTTP endpoint.
+      '';
+      default = "api.stripe.com";
+    };
+    services.private-storage-issuer.stripeEndpointScheme = lib.mkOption {
+      type = lib.types.enum [ "HTTP" "HTTPS" ];
+      description = ''
+        Whether to use HTTP or HTTPS for the Stripe API.
+      '';
+      default = "HTTPS";
+    };
+    services.private-storage-issuer.stripeEndpointPort = lib.mkOption {
+      type = lib.types.int;
+      description = ''
+        The port number for the Stripe API HTTP endpoint.
+      '';
+      default = 443;
+    };
     services.private-storage-issuer.database = lib.mkOption {
       default = "Memory";
       type = lib.types.enum [ "Memory" "SQLite3" ];
@@ -78,6 +99,14 @@ in {
         for the service's TLS certificate.
       '';
     };
+    services.private-storage-issuer.allowedChargeOrigins = lib.mkOption {
+      type = lib.types.listOf lib.types.str;
+      description = ''
+        The CORS "Origin" values which are allowed to submit charges to the
+        payment server.  Note this is not currently enforced by the
+        PaymentServer.  It just controls the CORS headers served.
+      '';
+    };
   };
 
   config =
@@ -116,7 +145,7 @@ in {
           issuerArgs =
             if cfg.issuer == "Trivial"
               then "--issuer Trivial"
-              else "--issuer Ristretto --signing-key ${cfg.ristrettoSigningKey}";
+              else "--issuer Ristretto --signing-key-path ${cfg.ristrettoSigningKeyPath}";
           databaseArgs =
             if cfg.database == "Memory"
               then "--database Memory"
@@ -131,9 +160,18 @@ in {
             else
               # Only for automated testing.
               "--http-port 80";
-          stripeArgs = "--stripe-key ${builtins.readFile cfg.stripeSecretKeyPath}";
+
+          prefixOption = s: "--cors-origin=" + s;
+          originStrings = map prefixOption cfg.allowedChargeOrigins;
+          originArgs = builtins.concatStringsSep " " originStrings;
+
+          stripeArgs =
+            "--stripe-key-path ${cfg.stripeSecretKeyPath} " +
+            "--stripe-endpoint-domain ${cfg.stripeEndpointDomain} " +
+            "--stripe-endpoint-scheme ${cfg.stripeEndpointScheme} " +
+            "--stripe-endpoint-port ${toString cfg.stripeEndpointPort}";
         in
-          "${cfg.package}/bin/PaymentServer-exe ${issuerArgs} ${databaseArgs} ${httpsArgs} ${stripeArgs}";
+          "${cfg.package}/bin/PaymentServer-exe ${originArgs} ${issuerArgs} ${databaseArgs} ${httpsArgs} ${stripeArgs}";
     };
 
     # Certificate renewal.  We must declare that we *require* it in our
diff --git a/nixos/modules/tests/get-passes.py b/nixos/modules/tests/get-passes.py
index d76ce3ccbf703bfabd08e120f84ed39063339297..96875713233b7c46abae0cfc3f0d946628bf8cc2 100755
--- a/nixos/modules/tests/get-passes.py
+++ b/nixos/modules/tests/get-passes.py
@@ -12,23 +12,25 @@ from json import dumps
 from time import sleep
 
 def main():
-    clientAPIRoot, issuerAPIRoot = argv[1:]
+    if len(argv) != 4:
+        raise SystemExit(
+            "usage: %s <client api root> <issuer api root> <voucher>",
+        )
+    clientAPIRoot, issuerAPIRoot, voucher = argv[1:]
     if not clientAPIRoot.endswith("/"):
         clientAPIRoot += "/"
     if not issuerAPIRoot.endswith("/"):
         issuerAPIRoot += "/"
 
-    # Construct a voucher that's acceptable to various parts of the system.
-    voucher = "a" * 44
-
     zkapauthz = clientAPIRoot + "storage-plugins/privatestorageio-zkapauthz-v1"
 
-    # Simulate a payment for a voucher.
-    post(
-        issuerAPIRoot + "v1/stripe/webhook",
-        dumps(charge_succeeded_json(voucher)),
+    # Submit a charge to the issuer (which is also the PaymentServer).
+    charge_response = post(
+        issuerAPIRoot + "v1/stripe/charge",
+        dumps(charge_json(voucher)),
         headers={"content-type": "application/json"},
     )
+    charge_response.raise_for_status()
 
     # Tell the client to redeem the voucher.
     response = put(
@@ -64,141 +66,13 @@ def retry(description, f):
     raise ValueError("failed to {} after many tries".format(description))
 
 
-def charge_succeeded_json(voucher):
-    # This structure copy/pasted from Stripe webhook web interface.
-    base_payload = {
-        "id": "evt_1FKSX2DeTd13VRuuhPaUDA2f",
-        "object": "event",
-        "api_version": "2016-07-06",
-        "created": 1568910660,
-        "data": {
-            "object": {
-                "id": "ch_1FKSX2DeTd13VRuuG9BXbqji",
-                "object": "charge",
-                "amount": 999,
-                "amount_refunded": 0,
-                "application": None,
-                "application_fee": None,
-                "application_fee_amount": None,
-                "balance_transaction": "txn_1FKSX2DeTd13VRuuqO1CJZ1e",
-                "billing_details": {
-                    "address": {
-                        "city": None,
-                        "country": None,
-                        "line1": None,
-                        "line2": None,
-                        "postal_code": None,
-                        "state": None
-                    },
-                    "email": None,
-                    "name": None,
-                    "phone": None
-                },
-                "captured": True,
-                "created": 1568910660,
-                "currency": "usd",
-                "customer": None,
-                "description": None,
-                "destination": None,
-                "dispute": None,
-                "failure_code": None,
-                "failure_message": None,
-                "fraud_details": {
-                },
-                "invoice": None,
-                "livemode": False,
-                "metadata": {
-                    "Voucher": None,
-                },
-                "on_behalf_of": None,
-                "order": None,
-                "outcome": {
-                    "network_status": "approved_by_network",
-                    "reason": None,
-                    "risk_level": "normal",
-                    "risk_score": 44,
-                    "seller_message": "Payment complete.",
-                    "type": "authorized"
-                },
-                "paid": True,
-                "payment_intent": None,
-                "payment_method": "card_1FKSX2DeTd13VRuus5VEjmjG",
-                "payment_method_details": {
-                    "card": {
-                        "brand": "visa",
-                        "checks": {
-                            "address_line1_check": None,
-                            "address_postal_code_check": None,
-                            "cvc_check": None
-                        },
-                        "country": "US",
-                        "exp_month": 9,
-                        "exp_year": 2020,
-                        "fingerprint": "HTJeRR4MXhAAkctF",
-                        "funding": "credit",
-                        "last4": "4242",
-                        "three_d_secure": None,
-                        "wallet": None
-                    },
-                    "type": "card"
-                },
-                "receipt_email": None,
-                "receipt_number": None,
-                "receipt_url": "https://pay.stripe.com/receipts/acct_198xN4DeTd13VRuu/ch_1FKSX2DeTd13VRuuG9BXbqji/rcpt_Fq8oAItSiNmcm0beiie6lUYin920E7a",
-                "refunded": False,
-                "refunds": {
-                    "object": "list",
-                    "data": [
-                    ],
-                    "has_more": False,
-                    "total_count": 0,
-                    "url": "/v1/charges/ch_1FKSX2DeTd13VRuuG9BXbqji/refunds"
-                },
-                "review": None,
-                "shipping": None,
-                "source": {
-                    "id": "card_1FKSX2DeTd13VRuus5VEjmjG",
-                    "object": "card",
-                    "address_city": None,
-                    "address_country": None,
-                    "address_line1": None,
-                    "address_line1_check": None,
-                    "address_line2": None,
-                    "address_state": None,
-                    "address_zip": None,
-                    "address_zip_check": None,
-                    "brand": "Visa",
-                    "country": "US",
-                    "customer": None,
-                    "cvc_check": None,
-                    "dynamic_last4": None,
-                    "exp_month": 9,
-                    "exp_year": 2020,
-                    "fingerprint": "HTJeRR4MXhAAkctF",
-                    "funding": "credit",
-                    "last4": "4242",
-                    "metadata": {
-                    },
-                    "name": None,
-                    "tokenization_method": None
-                },
-                "source_transfer": None,
-                "statement_descriptor": None,
-                "statement_descriptor_suffix": None,
-                "status": "succeeded",
-                "transfer_data": None,
-                "transfer_group": None
-            }
-        },
-        "livemode": False,
-        "pending_webhooks": 2,
-        "request": "req_5ozjOIAcOkvVUK",
-        "type": "charge.succeeded"
+def charge_json(voucher):
+    return {
+        "token": "tok_abcdef",
+        "voucher": voucher,
+        "amount": "100",
+        "currency": "USD",
     }
-    # Indicate the voucher the payment references.
-    base_payload["data"]["object"]["metadata"]["Voucher"] = voucher
-    return base_payload
-
 
 if __name__ == '__main__':
     main()
diff --git a/nixos/modules/tests/private-storage.nix b/nixos/modules/tests/private-storage.nix
index 9028691fc8edb133b5c048291cd5f0741f6f4ea1..1fe55c1302b35aeb9e5645bbc1cb60053fc6e97c 100644
--- a/nixos/modules/tests/private-storage.nix
+++ b/nixos/modules/tests/private-storage.nix
@@ -9,16 +9,33 @@ let
   get-passes = ./get-passes.py;
   exercise-storage = ./exercise-storage.py;
 
+  # This is a test double of the Stripe API server.  It is extremely simple.
+  # It barely knows how to respond to exactly the API endpoints we use,
+  # exactly how we use them.
+  stripe-api-double = ./stripe-api-double.py;
+
   # The root URL of the Ristretto-flavored PrivacyPass issuer API.
   issuerURL = "http://issuer/";
 
+  voucher = "xyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxy";
+
   # 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
   # world at large.
-  ristrettoSigningKey = "wumQAfSsJlQKDDSaFN/PZ3EbgBit8roVgfzllfCK2gQ=";
-
-  # Ugh.
-  stripeSecretKey = "sk_test_blubblub";
+  ristrettoSigningKeyPath =
+    let
+      key = "wumQAfSsJlQKDDSaFN/PZ3EbgBit8roVgfzllfCK2gQ=";
+      basename = "signing-key.private";
+    in
+      pkgs.writeText basename key;
+
+  stripeSecretKeyPath =
+    let
+      # Ugh.
+      key = "sk_test_blubblub";
+      basename = "stripe.secret";
+    in
+      pkgs.writeText basename key;
 
   # Here are the preconstructed secrets which we can assign to the introducer.
   # This is a lot easier than having the introducer generate them and then
@@ -42,6 +59,22 @@ let
     networking.firewall.enable = false;
     networking.dhcpcd.enable = false;
   };
+
+  # Return a Perl program fragment to run a shell command on one of the nodes.
+  # The first argument is the name of the node.  The second is a list of the
+  # argv to run.
+  #
+  # The program's output is piped to systemd-cat and the Perl fragment
+  # evaluates to success if the command exits with a success status.
+  runOnNode = node: argv:
+    let
+      command = builtins.concatStringsSep " " argv;
+    in
+      "
+      \$${node}->succeed('set -eo pipefail; ${command} | systemd-cat');
+      # succeed() is not success but 1 is.
+      1;
+      ";
 in
 # https://nixos.org/nixos/manual/index.html#sec-nixos-tests
 import <nixpkgs/nixos/tests/make-test.nix> {
@@ -69,11 +102,13 @@ import <nixpkgs/nixos/tests/make-test.nix> {
       { imports =
         [ ../private-storage.nix
         ];
-        services.private-storage.enable = true;
-        services.private-storage.publicIPv4 = "storage";
-        services.private-storage.introducerFURL = introducerFURL;
-        services.private-storage.issuerRootURL = issuerURL;
-        services.private-storage.ristrettoSigningKeyPath = pkgs.writeText "signing-key.private" ristrettoSigningKey;
+        services.private-storage = {
+          enable = true;
+          publicIPv4 = "storage";
+          introducerFURL = introducerFURL;
+          issuerRootURL = issuerURL;
+          inherit ristrettoSigningKeyPath;
+        };
       } // networkConfig;
 
     # Operate an issuer as well.
@@ -87,11 +122,41 @@ import <nixpkgs/nixos/tests/make-test.nix> {
         domain = "issuer";
         tls = false;
         issuer = "Ristretto";
-        inherit ristrettoSigningKey;
-        stripeSecretKeyPath = pkgs.writeText "stripe.secret" stripeSecretKey;
+        inherit ristrettoSigningKeyPath;
         letsEncryptAdminEmail = "user@example.invalid";
+        allowedChargeOrigins = [ "http://unused.invalid" ];
+
+        inherit stripeSecretKeyPath;
+        stripeEndpointDomain = "api_stripe_com";
+        stripeEndpointScheme = "HTTP";
+        stripeEndpointPort = 80;
       };
     } // networkConfig;
+
+    # Also run a fake Stripe API endpoint server.  Nodes in these tests run on
+    # a network without outside access so we can't easily use the real Stripe
+    # API endpoint and with this one we have greater control over the
+    # behavior, anyway, without all of the unintentional transient network
+    # errors that come from the public internet.  These tests *aren't* meant
+    # to prove PaymentServer correctly interacts with the real Stripe API
+    # server so this is an unverified fake.  The PaymentServer test suite
+    # needs to take care of any actual Stripe API integration testing.
+    "api_stripe_com" =
+    { config, pkgs, ... }:
+      let python = pkgs.python3.withPackages (ps: [ ps.twisted ]);
+      in networkConfig // {
+        environment.systemPackages = [
+          python
+          pkgs.curl
+        ];
+
+        systemd.services."api.stripe.com" = {
+          enable = true;
+          wantedBy = [ "multi-user.target" ];
+          after = [ "network.target" ];
+          script = "${python}/bin/python ${stripe-api-double} tcp:80";
+        };
+      };
   };
 
   # Test the machines with a Perl program (sobbing).
@@ -107,13 +172,7 @@ import <nixpkgs/nixos/tests/make-test.nix> {
       );
 
       eval {
-        $introducer->succeed(
-          'set -eo pipefail; ' .
-          '${run-introducer} /tmp/node.pem ${toString introducerPort} ${introducerFURL} | ' .
-          'systemd-cat'
-        );
-        # Signal success. :/
-        1;
+      ${runOnNode "introducer" [ run-introducer "/tmp/node.pem" (toString introducerPort) introducerFURL ]}
       } or do {
         my $error = $@ || 'Unknown failure';
         my ($code, $log) = $introducer->execute('cat /tmp/stdout /tmp/stderr');
@@ -142,26 +201,37 @@ import <nixpkgs/nixos/tests/make-test.nix> {
       #
       # Storage appears to be working so try to get a client to speak with it.
       #
-      $client->succeed('set -eo pipefail; ${run-client} ${introducerFURL} ${issuerURL} | systemd-cat');
+      ${runOnNode "client"  [ run-client introducerFURL issuerURL ]}
       $client->waitForOpenPort(3456);
 
-      # Get some ZKAPs from the issuer.
+      # Make sure the fake Stripe API server is ready for requests.
       eval {
-        $client->succeed('set -eo pipefail; ${get-passes} http://127.0.0.1:3456 ${issuerURL} | systemd-cat');
-        # succeed() is not success but 1 is.
+        $api_stripe_com->waitForUnit("api.stripe.com");
         1;
+      } or do {
+        my ($code, $log) = $api_stripe_com->execute('journalctl -u api.stripe.com');
+        $api_stripe_com->log($log);
+        die $@;
+      };
+
+      # Get some ZKAPs from the issuer.
+      eval {
+        ${runOnNode "client" [ get-passes "http://127.0.0.1:3456" issuerURL voucher ]}
       } or do {
         my $error = $@ || 'Unknown failure';
         my ($code, $log) = $client->execute('cat /tmp/stdout /tmp/stderr');
         $client->log($log);
+
+        # Dump the fake Stripe API server logs, too, since the error may arise
+        # from a PaymentServer/Stripe interaction.
+        my ($code, $log) = $api_stripe_com->execute('journalctl -u api.stripe.com');
+        $api_stripe_com->log($log);
         die $@;
       };
 
       # The client should be prepped now.  Make it try to use some storage.
       eval {
-        $client->succeed('set -eo pipefail; ${exercise-storage} /tmp/client | systemd-cat');
-        # nothing succeeds like ... 1.
-        1;
+        ${runOnNode "client" [ exercise-storage "/tmp/client" ]}
       } or do {
         my $error = $@ || 'Unknown failure';
         my ($code, $log) = $client->execute('cat /tmp/stdout /tmp/stderr');
diff --git a/nixos/modules/tests/stripe-api-double.py b/nixos/modules/tests/stripe-api-double.py
new file mode 100755
index 0000000000000000000000000000000000000000..5b96c0befe2a9434560bdd357f3d8e8dc2a92bc5
--- /dev/null
+++ b/nixos/modules/tests/stripe-api-double.py
@@ -0,0 +1,101 @@
+#!/usr/bin/env python3
+
+from sys import stdout, argv
+from json import dumps
+
+from twisted.internet.defer import Deferred
+from twisted.internet.endpoints import serverFromString
+from twisted.internet.task import react
+from twisted.web.resource import Resource
+from twisted.web.server import Site
+from twisted.python.log import startLogging
+
+class Charges(Resource):
+    def render_POST(self, request):
+        voucher = request.args[b"metadata[Voucher]"][0].decode("utf-8")
+        card = request.args[b"card"][0].decode("utf-8")
+        amount = int(request.args[b"amount"][0])
+        currency = request.args[b"currency"][0].decode("utf-8")
+        response = dumps(charge(card, amount, currency, {u"Voucher": voucher}))
+        return response.encode("utf-8")
+
+def main(reactor, listenEndpoint):
+    charges = Charges()
+    v1 = Resource()
+    v1.putChild(b"charges", charges)
+    root = Resource()
+    root.putChild(b"v1", v1)
+
+    return serverFromString(reactor, listenEndpoint).listen(
+        Site(root),
+    ).addCallback(
+        lambda ignored: Deferred()
+    )
+
+def charge(source, amount, currency, metadata):
+    return {
+        "id": "ch_1Fj8frBHXBAMm9bPkekylvAq",
+        "object": "charge",
+        "amount": amount,
+        "amount_refunded": 0,
+        "application": None,
+        "application_fee": None,
+        "application_fee_amount": None,
+        "balance_transaction": "txn_1Fj8fr2eZvKYlo2CC5JzIGj5",
+        "billing_details": {
+            "address": {
+                "city": None,
+                "country": None,
+                "line1": None,
+                "line2": None,
+                "postal_code": None,
+                "state": None
+            },
+            "email": None,
+            "name": None,
+            "phone": None
+        },
+        "captured": False,
+        "created": 1574792527,
+        "currency": currency,
+        "customer": None,
+        "description": None,
+        "dispute": None,
+        "disputed": False,
+        "failure_code": None,
+        "failure_message": None,
+        "fraud_details": {},
+        "invoice": None,
+        "livemode": False,
+        "metadata": metadata,
+        "on_behalf_of": None,
+        "order": None,
+        "outcome": None,
+        "paid": True,
+        "payment_intent": None,
+        "payment_method": source,
+        "payment_method_details": {},
+        "receipt_email": None,
+        "receipt_number": None,
+        "receipt_url": "https://pay.stripe.com/receipts/acct_1FhhxTBHXBAMm9bP/ch_1Fj8frBHXBAMm9bPkekylvAq/rcpt_GFdxYuDoGKfYgokh9YA11XhnYC7Gnxp",
+        "refunded": False,
+        "refunds": {
+            "object": "list",
+            "data": [],
+            "has_more": False,
+            "url": "/v1/charges/ch_1Fj8frBHXBAMm9bPkekylvAq/refunds"
+        },
+        "review": None,
+        "shipping": None,
+        "source_transfer": None,
+        "statement_descriptor": None,
+        "statement_descriptor_suffix": None,
+        "status": "succeeded",
+        "transfer_data": None,
+        "transfer_group": None,
+        "source": source,
+    }
+
+if __name__ == '__main__':
+    startLogging(stdout)
+    react(main, argv[1:])
diff --git a/nixos/pkgs/zkapissuer-repo.nix b/nixos/pkgs/zkapissuer-repo.nix
index af0eda33aeccbe01d71407123129330326d7b6ba..a252d3a9b31cc83ef879e1a1f9561f0480860d1f 100644
--- a/nixos/pkgs/zkapissuer-repo.nix
+++ b/nixos/pkgs/zkapissuer-repo.nix
@@ -4,6 +4,6 @@ in
   pkgs.fetchFromGitHub {
     owner = "PrivateStorageio";
     repo = "PaymentServer";
-    rev = "c5651f58ff564f00cfcdb4c73584817b9197f7a6";
-    sha256 = "1gmx4c82h95lkmqdklak3kpj6gkpp57hwc309h4798sclgvp287b";
+    rev = "1130b17e85392efd9f6be733308542b50bded1e3";
+    sha256 = "1ivcy3xcakxs0yfvbnvizq9pchp15g2wdprh5r5rq4fkqk8k6nbf";
   }
\ No newline at end of file