diff --git a/docs/narr/install.rst b/docs/narr/install.rst
index 33e7cd2..bceda1c 100644
--- a/docs/narr/install.rst
+++ b/docs/narr/install.rst
@@ -12,8 +12,7 @@ Install the Wutta-COREPOS package to your virtual environment:
    pip install Wutta-COREPOS
 
 Edit your :term:`config file` to add CORE-POS DB connection info, and
-related settings.  Note that so far, only CORE Office DB connections
-are supported.
+related settings.
 
 .. code-block:: ini
 
@@ -29,4 +28,14 @@ are supported.
    [corepos.db.office_arch]
    default.url = mysql+mysqlconnector://localhost/trans_archive
 
+   [corepos.db.lane_op]
+   keys = 01, 02
+   01.url = mysql+mysqlconnector://lane01/opdata
+   02.url = mysql+mysqlconnector://lane02/opdata
+
+   [corepos.db.lane_trans]
+   keys = 01, 02
+   01.url = mysql+mysqlconnector://lane01/translog
+   02.url = mysql+mysqlconnector://lane02/translog
+
 And that's it, the CORE-POS integration is configured.
diff --git a/src/wutta_corepos/conf.py b/src/wutta_corepos/conf.py
index 77bb6cc..7c3affb 100644
--- a/src/wutta_corepos/conf.py
+++ b/src/wutta_corepos/conf.py
@@ -74,6 +74,34 @@ class WuttaCoreposConfigExtension(WuttaConfigExtension):
        Dict of ``office_arch`` DB engines.  May be empty if no config
        is found; otherwise there should at least be a ``default`` key
        defined, corresonding to :data:`core_office_arch_engine`.
+
+    .. data:: core_lane_op_engine
+
+       Primary engine for the ``lane_op`` DB.  May be null if no
+       "default" engine is configured - which is *typical* for a
+       multi-lane environment.  See :data:`core_lane_op_engines` for
+       the full set.
+
+    .. data:: core_lane_op_engines
+
+       Dict of ``lane_op`` DB engines.  May be empty if no config is
+       found; otherwise keys are typically like ``01`` and ``02`` etc.
+       If present, the ``default`` key will correspond to
+       :data:`core_lane_op_engine`.
+
+    .. data:: core_lane_trans_engine
+
+       Primary engine for the ``lane_trans`` DB.  May be null if no
+       "default" engine is configured - which is *typical* for a
+       multi-lane environment.  See :data:`core_lane_trans_engines`
+       for the full set.
+
+    .. data:: core_lane_trans_engines
+
+       Dict of ``lane_trans`` DB engines.  May be empty if no config
+       is found; otherwise keys are typically like ``01`` and ``02``
+       etc.  If present, the ``default`` key will correspond to
+       :data:`core_lane_trans_engine`.
     """
     key = 'wutta_corepos'
 
@@ -101,6 +129,20 @@ class WuttaCoreposConfigExtension(WuttaConfigExtension):
         config.core_office_arch_engine = engines.get('default')
         Session.configure(bind=config.core_office_arch_engine)
 
+        # lane_op
+        from corepos.db.lane_op import Session
+        engines = get_engines(config, 'corepos.db.lane_op')
+        config.core_lane_op_engines = engines
+        config.core_lane_op_engine = engines.get('default')
+        Session.configure(bind=config.core_lane_op_engine)
+
+        # lane_trans
+        from corepos.db.lane_trans import Session
+        engines = get_engines(config, 'corepos.db.lane_trans')
+        config.core_lane_trans_engines = engines
+        config.core_lane_trans_engine = engines.get('default')
+        Session.configure(bind=config.core_lane_trans_engine)
+
         # define some schema columns "late" unless not supported
         if config.get_bool('corepos.db.office_op.use_latest_columns',
                           default=True, usedb=False):
diff --git a/src/wutta_corepos/handler.py b/src/wutta_corepos/handler.py
index 8b39795..f52ef8e 100644
--- a/src/wutta_corepos/handler.py
+++ b/src/wutta_corepos/handler.py
@@ -60,6 +60,24 @@ class CoreposHandler(GenericHandler):
 
         return model
 
+    def get_model_lane_op(self):
+        """
+        Returns the :term:`data model` module for CORE Lane 'op' DB,
+        i.e. :mod:`pycorepos:corepos.db.lane_op.model`.
+        """
+        from corepos.db.lane_op import model
+
+        return model
+
+    def get_model_lane_trans(self):
+        """
+        Returns the :term:`data model` module for CORE Lane 'trans'
+        DB, i.e. :mod:`pycorepos:corepos.db.lane_trans.model`.
+        """
+        from corepos.db.lane_trans import model
+
+        return model
+
     def make_session_office_op(self, dbkey='default', **kwargs):
         """
         Make a new :term:`db session` for the CORE Office 'op' DB.
@@ -99,6 +117,32 @@ class CoreposHandler(GenericHandler):
             kwargs['bind'] = self.config.core_office_arch_engines[dbkey]
         return Session(**kwargs)
 
+    def make_session_lane_op(self, dbkey='default', **kwargs):
+        """
+        Make a new :term:`db session` for the CORE Lane 'op' DB.
+
+        :returns: Instance of
+           :class:`pycorepos:corepos.db.lane_op.Session`.
+        """
+        from corepos.db.lane_op import Session
+
+        if 'bind' not in kwargs:
+            kwargs['bind'] = self.config.core_lane_op_engines[dbkey]
+        return Session(**kwargs)
+
+    def make_session_lane_trans(self, dbkey='default', **kwargs):
+        """
+        Make a new :term:`db session` for the CORE Lane 'trans' DB.
+
+        :returns: Instance of
+           :class:`pycorepos:corepos.db.lane_trans.Session`.
+        """
+        from corepos.db.lane_trans import Session
+
+        if 'bind' not in kwargs:
+            kwargs['bind'] = self.config.core_lane_trans_engines[dbkey]
+        return Session(**kwargs)
+
     def get_office_url(self, require=False):
         """
         Returns the base URL for the CORE Office web app.
@@ -136,6 +180,28 @@ class CoreposHandler(GenericHandler):
         if office_url:
             return f'{office_url}/item/departments/DepartmentEditor.php?did={dept_id}'
 
+    def get_office_employee_url(
+            self,
+            employee_id,
+            office_url=None,
+            require=False):
+        """
+        Returns the CORE Office URL for an Employee.
+
+        :param employee_id: Employee ID for the URL.
+
+        :param office_url: Root URL from :meth:`get_office_url()`.
+
+        :param require: If true, an error is raised when URL cannot be
+           determined.
+
+        :returns: URL as string.
+        """
+        if not office_url:
+            office_url = self.get_office_url(require=require)
+        if office_url:
+            return f'{office_url}/admin/Cashiers/CashierEditor.php?emp_no={employee_id}'
+
     def get_office_likecode_url(
             self,
             likecode_id,
diff --git a/src/wutta_corepos/web/db.py b/src/wutta_corepos/web/db.py
index 7faeff2..4c9e292 100644
--- a/src/wutta_corepos/web/db.py
+++ b/src/wutta_corepos/web/db.py
@@ -49,6 +49,22 @@ in general.
 .. class:: ExtraCoreArchSessions
 
    Dict of secondary CORE Office 'arch' DB sessions, if applicable.
+
+.. class:: CoreLaneOpSession
+
+   Primary web app :term:`db session` for CORE Lane 'op' DB.
+
+.. class:: CoreLaneTransSession
+
+   Primary web app :term:`db session` for CORE Lane 'trans' DB.
+
+.. class:: ExtraCoreLaneOpSessions
+
+   Dict of secondary CORE Lane 'op' DB sessions, if applicable.
+
+.. class:: ExtraCoreLaneTransSessions
+
+   Dict of secondary CORE Lane 'trans' DB sessions, if applicable.
 """
 
 from sqlalchemy.orm import sessionmaker, scoped_session
@@ -64,7 +80,15 @@ register(CoreTransSession)
 CoreArchSession = scoped_session(sessionmaker())
 register(CoreArchSession)
 
+CoreLaneOpSession = scoped_session(sessionmaker())
+register(CoreLaneOpSession)
+
+CoreLaneTransSession = scoped_session(sessionmaker())
+register(CoreLaneTransSession)
+
 # nb. these start out empty but may be populated on app startup
 ExtraCoreOpSessions = {}
 ExtraCoreTransSessions = {}
 ExtraCoreArchSessions = {}
+ExtraCoreLaneOpSessions = {}
+ExtraCoreLaneTransSessions = {}
diff --git a/tests/test_conf.py b/tests/test_conf.py
index c957dce..10f97a0 100644
--- a/tests/test_conf.py
+++ b/tests/test_conf.py
@@ -16,14 +16,21 @@ class TestWuttaCoreposConfigExtension(TestCase):
         self.assertFalse(hasattr(config, 'core_office_op_engine'))
         self.assertFalse(hasattr(config, 'core_office_trans_engine'))
         self.assertFalse(hasattr(config, 'core_office_arch_engine'))
+        self.assertFalse(hasattr(config, 'core_lane_op_engine'))
+        self.assertFalse(hasattr(config, 'core_lane_trans_engine'))
         ext = mod.WuttaCoreposConfigExtension()
         ext.configure(config)
         self.assertIsNone(config.core_office_op_engine)
         self.assertIsNone(config.core_office_trans_engine)
         self.assertIsNone(config.core_office_arch_engine)
+        self.assertIsNone(config.core_lane_op_engine)
+        self.assertIsNone(config.core_lane_trans_engine)
 
         # but config can change that
         config.setdefault('corepos.db.office_op.default.url', 'sqlite://')
+        config.setdefault('corepos.db.lane_trans.default.url', 'sqlite://')
         ext.configure(config)
         self.assertIsNotNone(config.core_office_op_engine)
         self.assertEqual(str(config.core_office_op_engine.url), 'sqlite://')
+        self.assertIsNotNone(config.core_lane_trans_engine)
+        self.assertEqual(str(config.core_lane_trans_engine.url), 'sqlite://')
diff --git a/tests/test_handler.py b/tests/test_handler.py
index 6dc5077..f751f22 100644
--- a/tests/test_handler.py
+++ b/tests/test_handler.py
@@ -34,6 +34,18 @@ class TestCoreposHandler(ConfigTestCase):
         arch_model = handler.get_model_office_arch()
         self.assertIs(arch_model, model)
 
+    def test_get_model_lane_op(self):
+        from corepos.db.lane_op import model
+        handler = self.make_handler()
+        op_model = handler.get_model_lane_op()
+        self.assertIs(op_model, model)
+
+    def test_get_model_lane_trans(self):
+        from corepos.db.lane_trans import model
+        handler = self.make_handler()
+        trans_model = handler.get_model_lane_trans()
+        self.assertIs(trans_model, model)
+
     def test_make_session_office_op(self):
         handler = self.make_handler()
         engine = sa.create_engine('sqlite://')
@@ -61,6 +73,24 @@ class TestCoreposHandler(ConfigTestCase):
             self.assertIsInstance(arch_session, orm.Session)
             self.assertIs(arch_session.bind, engine)
 
+    def test_make_session_lane_op(self):
+        handler = self.make_handler()
+        engine = sa.create_engine('sqlite://')
+        with patch.object(self.config, 'core_lane_op_engines', create=True,
+                          new={'default': engine}):
+            op_session = handler.make_session_lane_op()
+            self.assertIsInstance(op_session, orm.Session)
+            self.assertIs(op_session.bind, engine)
+
+    def test_make_session_lane_trans(self):
+        handler = self.make_handler()
+        engine = sa.create_engine('sqlite://')
+        with patch.object(self.config, 'core_lane_trans_engines', create=True,
+                          new={'default': engine}):
+            trans_session = handler.make_session_lane_trans()
+            self.assertIsInstance(trans_session, orm.Session)
+            self.assertIs(trans_session.bind, engine)
+
     def test_get_office_url(self):
         handler = self.make_handler()
 
@@ -85,6 +115,16 @@ class TestCoreposHandler(ConfigTestCase):
         self.config.setdefault('corepos.office.url', 'http://localhost/fannie/')
         self.assertEqual(handler.get_office_department_url(7), 'http://localhost/fannie/item/departments/DepartmentEditor.php?did=7')
 
+    def test_get_office_employee_url(self):
+        handler = self.make_handler()
+
+        # null
+        self.assertIsNone(handler.get_office_employee_url(7))
+
+        # typical
+        self.config.setdefault('corepos.office.url', 'http://localhost/fannie/')
+        self.assertEqual(handler.get_office_employee_url(7), 'http://localhost/fannie/admin/Cashiers/CashierEditor.php?emp_no=7')
+
     def test_get_office_likecode_url(self):
         handler = self.make_handler()