diff --git a/src/_secureaccesstokenauthorizer/model.py b/src/_secureaccesstokenauthorizer/model.py
index bcdc4d636432856fc03015ff2d03a1152dfbfb50..f6da6946b47ea83945d174d18c52b9a9b6bc2d90 100644
--- a/src/_secureaccesstokenauthorizer/model.py
+++ b/src/_secureaccesstokenauthorizer/model.py
@@ -26,7 +26,7 @@ from json import (
 )
 
 from sqlite3 import (
-    connect,
+    connect as _connect,
 )
 
 import attr
@@ -52,7 +52,26 @@ class SchemaError(TypeError):
 
 CONFIG_DB_NAME = u"privatestorageio-satauthz-v1.sqlite3"
 
-def open_and_initialize(path):
+def open_and_initialize(path, required_schema_version, connect=None):
+    """
+    Open a SQLite3 database for use as a payment reference store.
+
+    Create the database and populate it with a schema, if it does not already
+    exist.
+
+    :param FilePath path: The location of the SQLite3 database file.
+
+    :param int required_schema_version: The schema version which must be
+        present in the database in order for a SQLite3 connection to be
+        returned.
+
+    :raise SchemaError: If the schema in the database does not match the
+        required schema version.
+
+    :return: A SQLite3 connection object for the database at the given path.
+    """
+    if connect is None:
+        connect = _connect
     try:
         path.parent().makedirs(ignoreExistingDirectory=True)
     except OSError as e:
@@ -65,6 +84,8 @@ def open_and_initialize(path):
     with conn:
         cursor = conn.cursor()
         cursor.execute(
+            # This code knows how to create schema version 1.  This is
+            # regardless of what the caller *wants* to find in the database.
             """
             CREATE TABLE IF NOT EXISTS [version] AS SELECT 1 AS [version]
             """
@@ -74,22 +95,21 @@ def open_and_initialize(path):
             SELECT [version] FROM [version]
             """
         )
-        expected = [(1,)]
-        version = cursor.fetchall()
-        if version != expected:
+        [(actual_version,)] = cursor.fetchall()
+        if actual_version != required_schema_version:
             raise SchemaError(
-                "Unexpected database schema version.  Expected {}.  Got {}.".format(
-                    expected,
-                    version,
+                "Unexpected database schema version.  Required {}.  Got {}.".format(
+                    required_schema_version,
+                    actual_version,
                 ),
             )
 
         cursor.execute(
             """
             CREATE TABLE IF NOT EXISTS [payment-references] (
-                number text,
+                [number] text,
 
-                PRIMARY KEY(number)
+                PRIMARY KEY([number])
             )
             """,
         )
@@ -104,6 +124,13 @@ def with_cursor(f):
     return with_cursor
 
 
+def memory_connect(path, *a, **kw):
+    """
+    Always connect to an in-memory SQLite3 database.
+    """
+    return _connect(":memory:", *a, **kw)
+
+
 @attr.s(frozen=True)
 class PaymentReferenceStore(object):
     """
@@ -116,10 +143,12 @@ class PaymentReferenceStore(object):
     _connection = attr.ib()
 
     @classmethod
-    def from_node_config(cls, node_config):
+    def from_node_config(cls, node_config, connect=None):
         db_path = FilePath(node_config.get_private_path(CONFIG_DB_NAME))
         conn = open_and_initialize(
             db_path,
+            required_schema_version=1,
+            connect=connect,
         )
         return cls(
             db_path,
diff --git a/src/_secureaccesstokenauthorizer/resource.py b/src/_secureaccesstokenauthorizer/resource.py
index cd9b06b9eef7e8fb771d88a9c794f6f15aa39a8a..9c4d60ec8ac7ab1b24d3189e19983884f1cd2779 100644
--- a/src/_secureaccesstokenauthorizer/resource.py
+++ b/src/_secureaccesstokenauthorizer/resource.py
@@ -44,7 +44,7 @@ from .controller import (
     PaymentController,
 )
 
-def from_configuration(node_config):
+def from_configuration(node_config, store=None):
     """
     Instantiate the plugin root resource using data from its configuration
     section in the Tahoe-LAFS configuration file::
@@ -57,10 +57,14 @@ def from_configuration(node_config):
         This is also used to read and write files in the private storage area
         of the node's persistent state location.
 
+    :param PaymentReferenceStore store: The store to use.  If ``None`` a
+        sensible one is constructed.
+
     :return IResource: The root of the resource hierarchy presented by the
         client side of the plugin.
     """
-    store = PaymentReferenceStore.from_node_config(node_config)
+    if store is None:
+        store = PaymentReferenceStore.from_node_config(node_config)
     controller = PaymentController(store)
     root = Resource()
     root.putChild(
@@ -97,6 +101,8 @@ class _PaymentReferenceNumberCollection(Resource):
         prn = payload[u"payment-reference-number"]
         if not isinstance(prn, unicode):
             return bad_request().render(request)
+        if not prn.strip():
+            return bad_request().render(request)
         try:
             urlsafe_b64decode(prn.encode("ascii"))
         except Exception:
diff --git a/src/_secureaccesstokenauthorizer/tests/test_client_resource.py b/src/_secureaccesstokenauthorizer/tests/test_client_resource.py
index 32c8c7731c91c576aac8a54874f7cd07e41bbcc6..d8a8d6852832bdd9ef4e167932e0b59cda65ae2f 100644
--- a/src/_secureaccesstokenauthorizer/tests/test_client_resource.py
+++ b/src/_secureaccesstokenauthorizer/tests/test_client_resource.py
@@ -55,6 +55,7 @@ from fixtures import (
 
 from hypothesis import (
     given,
+    note,
 )
 from hypothesis.strategies import (
     one_of,
@@ -87,6 +88,10 @@ from treq.testing import (
     RequestTraversalAgent,
 )
 
+from ..model import (
+    PaymentReferenceStore,
+    memory_connect,
+)
 from ..resource import (
     from_configuration,
 )
@@ -139,6 +144,8 @@ def is_urlsafe_base64(text):
         return False
     return True
 
+
+
 def invalid_bodies():
     """
     Build byte strings that ``PUT /payment-reference-number`` considers
@@ -163,6 +170,17 @@ def invalid_bodies():
         binary().filter(is_not_json),
     )
 
+
+def root_from_config(config):
+    return from_configuration(
+        config,
+        PaymentReferenceStore.from_node_config(
+            config,
+            memory_connect,
+        ),
+    )
+
+
 class PaymentReferenceNumberTests(TestCase):
     """
     Tests relating to ``/payment-reference-number`` as implemented by the
@@ -171,7 +189,6 @@ class PaymentReferenceNumberTests(TestCase):
     """
     def setUp(self):
         super(PaymentReferenceNumberTests, self).setUp()
-        self.tempdir = self.useFixture(TempDir())
         self.useFixture(CaptureTwistedLogs())
 
 
@@ -181,10 +198,9 @@ class PaymentReferenceNumberTests(TestCase):
         A resource is reachable at the ``payment-reference-number`` child of a the
         resource returned by ``from_configuration``.
         """
-        root = from_configuration(
-            get_config(self.tempdir.join(b"tahoe.ini"), b"tub.port"),
-        )
-
+        tempdir = self.useFixture(TempDir())
+        config = get_config(tempdir.join(b"tahoe.ini"), b"tub.port")
+        root = root_from_config(config)
         self.assertThat(
             getChildForRequest(root, request),
             Provides([IResource]),
@@ -198,9 +214,9 @@ class PaymentReferenceNumberTests(TestCase):
         is passed in to the PRN redemption model object for handling and an
         ``OK`` response is returned.
         """
-        root = from_configuration(
-            get_config(self.tempdir.join(b"tahoe.ini"), b"tub.port"),
-        )
+        tempdir = self.useFixture(TempDir())
+        config = get_config(tempdir.join(b"tahoe.ini"), b"tub.port")
+        root = root_from_config(config)
         agent = RequestTraversalAgent(root)
         producer = FileBodyProducer(
             BytesIO(dumps({u"payment-reference-number": prn})),
@@ -229,9 +245,9 @@ class PaymentReferenceNumberTests(TestCase):
         consist of an object with a single *payment-reference-number* property
         then the response is *BAD REQUEST*.
         """
-        root = from_configuration(
-            get_config(self.tempdir.join(b"tahoe.ini"), b"tub.port"),
-        )
+        tempdir = self.useFixture(TempDir())
+        config = get_config(tempdir.join(b"tahoe.ini"), b"tub.port")
+        root = root_from_config(config)
         agent = RequestTraversalAgent(root)
         producer = FileBodyProducer(
             BytesIO(body),
@@ -259,11 +275,10 @@ class PaymentReferenceNumberTests(TestCase):
         When a syntactically invalid PRN is requested with a ``GET`` to a child of
         ``PaymentReferenceNumberCollection`` the response is **BAD REQUEST**.
         """
+        tempdir = self.useFixture(TempDir())
         not_prn = prn[1:]
-        root = from_configuration(
-            get_config(self.tempdir.join(b"tahoe.ini"), b"tub.port"),
-        )
-
+        config = get_config(tempdir.join(b"tahoe.ini"), b"tub.port")
+        root = root_from_config(config)
         agent = RequestTraversalAgent(root)
         requesting = agent.request(
             b"GET",
@@ -284,10 +299,9 @@ class PaymentReferenceNumberTests(TestCase):
         ``PaymentReferenceNumberCollection`` the response is **NOT FOUND** if
         the PRN hasn't previously been submitted with a ``PUT``.
         """
-        root = from_configuration(
-            get_config(self.tempdir.join(b"tahoe.ini"), b"tub.port"),
-        )
-
+        tempdir = self.useFixture(TempDir())
+        config = get_config(tempdir.join(b"tahoe.ini"), b"tub.port")
+        root = root_from_config(config)
         agent = RequestTraversalAgent(root)
         requesting = agent.request(
             b"GET",
@@ -308,10 +322,9 @@ class PaymentReferenceNumberTests(TestCase):
         same PRN then the response code is **OK** and details about the PRN
         are included in a json-encoded response body.
         """
-        root = from_configuration(
-            get_config(self.tempdir.join(b"tahoe.ini"), b"tub.port"),
-        )
-
+        tempdir = self.useFixture(TempDir())
+        config = get_config(tempdir.join(b"tahoe.ini"), b"tub.port")
+        root = root_from_config(config)
         agent = RequestTraversalAgent(root)
 
         producer = FileBodyProducer(
@@ -364,12 +377,12 @@ class PaymentReferenceNumberTests(TestCase):
         # directory for every Hypothesis iteration because this test leaves
         # state behind that invalidates future iterations.
         tempdir = self.useFixture(TempDir())
-        root = from_configuration(
-            get_config(tempdir.join(b"tahoe.ini"), b"tub.port"),
-        )
-
+        config = get_config(tempdir.join(b"tahoe.ini"), b"tub.port")
+        root = root_from_config(config)
         agent = RequestTraversalAgent(root)
 
+        note("{} PRNs".format(len(prns)))
+
         for prn in prns:
             producer = FileBodyProducer(
                 BytesIO(dumps({u"payment-reference-number": prn})),
diff --git a/src/_secureaccesstokenauthorizer/tests/test_model.py b/src/_secureaccesstokenauthorizer/tests/test_model.py
index 0d3772afe2e2873baa520bf0998fb79df28b183c..2e7ba782120c41acc861705a74ffc238058435bd 100644
--- a/src/_secureaccesstokenauthorizer/tests/test_model.py
+++ b/src/_secureaccesstokenauthorizer/tests/test_model.py
@@ -42,16 +42,21 @@ from fixtures import (
 
 from hypothesis import (
     given,
-    assume,
 )
 from hypothesis.strategies import (
     lists,
 )
 
+from twisted.python.filepath import (
+    FilePath,
+)
+
 from ..model import (
+    SchemaError,
     StoreDirectoryError,
-    StoreAddError,
     PaymentReferenceStore,
+    open_and_initialize,
+    memory_connect,
 )
 
 from .strategies import (
@@ -64,6 +69,22 @@ class PaymentReferenceStoreTests(TestCase):
     """
     Tests for ``PaymentReferenceStore``.
     """
+    def test_create_mismatched_schema(self):
+        """
+        ``open_and_initialize`` raises ``SchemaError`` if asked for a database
+        with a schema version other than it can create.
+        """
+        tempdir = self.useFixture(TempDir())
+        dbpath = tempdir.join(b"db.sqlite3")
+        self.assertThat(
+            lambda: open_and_initialize(
+                FilePath(dbpath),
+                required_schema_version=100,
+            ),
+            raises(SchemaError),
+        )
+
+
     @given(tahoe_configs(), payment_reference_numbers())
     def test_get_missing(self, get_config, prn):
         """
@@ -72,7 +93,10 @@ class PaymentReferenceStoreTests(TestCase):
         """
         tempdir = self.useFixture(TempDir())
         config = get_config(tempdir.join(b"node"), b"tub.port")
-        store = PaymentReferenceStore.from_node_config(config)
+        store = PaymentReferenceStore.from_node_config(
+            config,
+            memory_connect,
+        )
         self.assertThat(
             lambda: store.get(prn),
             raises(KeyError),
@@ -87,7 +111,10 @@ class PaymentReferenceStoreTests(TestCase):
         """
         tempdir = self.useFixture(TempDir())
         config = get_config(tempdir.join(b"node"), b"tub.port")
-        store = PaymentReferenceStore.from_node_config(config)
+        store = PaymentReferenceStore.from_node_config(
+            config,
+            memory_connect,
+        )
         store.add(prn)
         payment_reference = store.get(prn)
         self.assertThat(
@@ -105,7 +132,10 @@ class PaymentReferenceStoreTests(TestCase):
         """
         tempdir = self.useFixture(TempDir())
         config = get_config(tempdir.join(b"node"), b"tub.port")
-        store = PaymentReferenceStore.from_node_config(config)
+        store = PaymentReferenceStore.from_node_config(
+            config,
+            memory_connect,
+        )
         store.add(prn)
         store.add(prn)
         payment_reference = store.get(prn)
@@ -127,7 +157,10 @@ class PaymentReferenceStoreTests(TestCase):
         tempdir = self.useFixture(TempDir())
         nodedir = tempdir.join(b"node")
         config = get_config(nodedir, b"tub.port")
-        store = PaymentReferenceStore.from_node_config(config)
+        store = PaymentReferenceStore.from_node_config(
+            config,
+            memory_connect,
+        )
 
         for prn in prns:
             store.add(prn)
@@ -158,7 +191,10 @@ class PaymentReferenceStoreTests(TestCase):
         config = get_config(nodedir, b"tub.port")
 
         self.assertThat(
-            lambda: PaymentReferenceStore.from_node_config(config),
+            lambda: PaymentReferenceStore.from_node_config(
+                config,
+                memory_connect,
+            ),
             Raises(
                 AfterPreprocessing(
                     lambda (type, exc, tb): exc,