diff --git a/notebooks/DynamicFF/Characterize_DynamicFF_NBC.ipynb b/notebooks/DynamicFF/Characterize_DynamicFF_NBC.ipynb
index e9595656c8fe6624f0e3d91ff8e27a49af416df6..9339eae9c535260072335592a462bbcff1d162e6 100644
--- a/notebooks/DynamicFF/Characterize_DynamicFF_NBC.ipynb
+++ b/notebooks/DynamicFF/Characterize_DynamicFF_NBC.ipynb
@@ -64,10 +64,12 @@
     "from cal_tools.step_timing import StepTimer\n",
     "from cal_tools.tools import (\n",
     "    get_dir_creation_date,\n",
+    "    run_prop_seq_from_path,\n",
     "    save_dict_to_hdf5\n",
     ")\n",
     "from cal_tools.restful_config import calibration_client, extra_calibration_client\n",
     "from cal_tools.shimadzu import ShimadzuHPVX2\n",
+    "from cal_tools.constants import write_ccv, inject_ccv\n",
     "\n",
     "import dynflatfield as dffc\n",
     "from dynflatfield.draw import plot_images, plot_camera_image"
@@ -168,7 +170,7 @@
     "    module_constants = constants.setdefault(meta[\"db_module\"], {})\n",
     "    module_constants[\"Offset\"] = dict(\n",
     "        conditions=conditions, data=dark, pdu_no=meta[\"pdu_no\"],\n",
-    "        creation_time=dark_creation_time\n",
+    "        creation_time=dark_creation_time, dims=['ss', 'fs']\n",
     "    )\n",
     "    step_timer.done_step(\"Process dark images\")\n",
     "    display()\n",
@@ -243,7 +245,7 @@
     "    module_constants = constants.setdefault(meta[\"db_module\"], {})\n",
     "    module_constants[\"DynamicFF\"] = dict(\n",
     "        conditions=conditions, data=flat_data, pdu_no=meta[\"pdu_no\"],\n",
-    "        creation_time=flat_creation_time\n",
+    "        creation_time=flat_creation_time, dims=['component', 'ss', 'fs']\n",
     "    )\n",
     "    step_timer.done_step(\"Process flat-field images\")\n",
     "\n",
@@ -283,39 +285,27 @@
    "source": [
     "step_timer.start()\n",
     "\n",
+    "_, proposal, _ = run_prop_seq_from_path(in_folder)\n",
+    "\n",
     "# Output Folder Creation:\n",
     "if local_output:\n",
     "    os.makedirs(out_folder, exist_ok=True)\n",
     "\n",
-    "def inject_ccv(in_folder, metadata_folder, runs, calibration, cond, pdu, const_input, begin_at):\n",
-    "    print(\"* Send to db:\", const_input)\n",
-    "    print(\"  - in folder:\", in_folder)\n",
-    "    print(\"  - metadata folder:\", metadata_folder)\n",
-    "    print(\"  - runs:\", runs)\n",
-    "    print(\"  -\", calibration)\n",
-    "    print(\"  -\", cond)\n",
-    "    print(\"  -\", begin_at)\n",
-    "\n",
     "for db_module, module_constants in constants.items():\n",
     "    for constant_name, constant in module_constants.items():\n",
     "        conditions = constant[\"conditions\"]\n",
-    "        conditions_dict = conditions.make_dict(\n",
-    "            conditions.calibration_types[constant_name])\n",
-    "\n",
-    "        data_to_store = {db_module: {constant_name: {'0': {\n",
-    "            'conditions': conditions_dict,\n",
-    "            'data': constant[\"data\"],\n",
-    "        }}}}\n",
+    "        pdu = pdus[\"data\"][constant[\"pdu_no\"]]\n",
     "\n",
     "        with NamedTemporaryFile() as tempf:\n",
-    "            save_dict_to_hdf5(data_to_store, tempf)\n",
+    "            ccv_root = write_ccv(\n",
+    "                tempf.name,\n",
+    "                pdu['physical_name'], pdu['uuid'], pdu['detector_type']['name'],\n",
+    "                constant_name, conditions, constant['creation_time'],\n",
+    "                proposal, [dark_run, flat_run],\n",
+    "                constant[\"data\"], constant['dims'])\n",
     "            \n",
     "            if db_output:\n",
-    "                inject_ccv(\n",
-    "                    in_folder, metadata_folder, [dark_run, flat_run],\n",
-    "                    constant_name, conditions, pdus[\"data\"][constant[\"pdu_no\"]],\n",
-    "                    ofile, constant[\"creation_time\"]\n",
-    "                )\n",
+    "                inject_ccv(tempf.name, ccv_root, metadata_folder)\n",
     "                \n",
     "            if local_output:\n",
     "                ofile = f\"{out_folder}/const_{constant_name}_{db_module}.h5\"\n",
diff --git a/notebooks/DynamicFF/Correct_DynamicFF_NBC.ipynb b/notebooks/DynamicFF/Correct_DynamicFF_NBC.ipynb
index 258c3712daea0e707b6346deff7f404a982d193c..3e6a1875c027ef1796d7f5687588becf8539fdf1 100644
--- a/notebooks/DynamicFF/Correct_DynamicFF_NBC.ipynb
+++ b/notebooks/DynamicFF/Correct_DynamicFF_NBC.ipynb
@@ -146,9 +146,8 @@
     "corrections = {}\n",
     "for da in modules:\n",
     "    try:\n",
-    "        # !!! REMOVE caldb_root for production\n",
-    "        dark = caldata[\"Offset\", da].ndarray(caldb_root=caldb_root)\n",
-    "        flat = caldata[\"DynamicFF\", da].ndarray(caldb_root=caldb_root)\n",
+    "        dark = caldata[\"Offset\", da].ndarray()\n",
+    "        flat = caldata[\"DynamicFF\", da].ndarray()\n",
     "        \n",
     "        components = flat[1:][:n_components]\n",
     "        flat = flat[0]\n",
diff --git a/src/cal_tools/constants.py b/src/cal_tools/constants.py
new file mode 100644
index 0000000000000000000000000000000000000000..cd4abb00f819ef75f2da7b3315adaf4f863bd3c6
--- /dev/null
+++ b/src/cal_tools/constants.py
@@ -0,0 +1,199 @@
+
+from datetime import datetime, timezone
+from struct import pack, unpack
+from pathlib import Path
+from shutil import copyfile
+from hashlib import md5
+import binascii
+import time
+
+import numpy as np
+import h5py
+
+from calibration_client import CalibrationClient
+from cal_tools.calcat_interface2 import _get_default_caldb_root, get_client
+from cal_tools.tools import run_prop_seq_from_path
+from cal_tools.restful_config import calibration_client
+
+
+def write_ccv(
+    const_path,
+    pdu_name, pdu_uuid, detector_type,
+    calibration, conditions, created_at, proposal, runs,
+    data, dims, key='0'
+):
+    """Write CCV data file.
+
+    Args:
+        const_path (os.PathLike): Path to CCV file to write
+        pdu_name (str): Physical detector unit name
+        pdu_uuid (int): Physical detector unit UUID
+        detector_type (str): Detector type name
+        calibration (str): Calibration name
+        conditions (ConditionsBase): Detector operating conditions
+        created_at (datetime): Validity start for calibration
+        proposal (int): Raw data proposal the calibration data is
+            generated from
+        runs (Iterable of int): Raw data runs the calibration data is
+            generated from
+        data (ndarray): Calibration constant data
+        dims (Iterable of str):
+        key (str, optional):
+
+    Returns:
+        (str) CCV HDF group name.
+
+    """
+
+    if data.ndim != len(dims):
+        raise ValueError('data.ndims != len(dims)')
+
+    with h5py.File(const_path, 'a') as const_file:
+        const_file.attrs['version'] = 0
+
+        pdu_group = const_file.require_group(pdu_name)
+        pdu_group.attrs['uuid'] = pdu_uuid
+        pdu_group.attrs['detector_type'] = detector_type
+
+        calibration_group = pdu_group.require_group(calibration)
+
+        if key is None:
+            key = str(len(calibration_group))
+
+        ccv_group = calibration_group.create_group(key)
+        ccv_group.attrs['begin_at'] = created_at.isoformat()
+        ccv_group.attrs['proposal'] = proposal
+        ccv_group.attrs['runs'] = np.array(runs, dtype=np.int32)
+        ccv_group_name = ccv_group.name
+
+        opcond_group = ccv_group.create_group('operating_condition')
+        opcond_dict = conditions.make_dict(
+            conditions.calibration_types[calibration])
+        for db_name, value in opcond_dict.items():
+            key = db_name.lower().replace(' ', '_')
+            dset = opcond_group.create_dataset(key, data=value,
+                                               dtype=np.float64)
+            dset.attrs['lower_deviation'] = 0.0
+            dset.attrs['upper_deviation'] = 0.0
+            dset.attrs['database_name'] = db_name
+
+        dset = ccv_group.create_dataset('data', data=data)
+        dset.attrs['dims'] = dims
+
+    return ccv_group_name
+
+
+def inject_ccv(const_src, ccv_root, report_to=None):
+    """Inject new CCV into CalCat.
+
+    Args:
+        const_path (str or Path): Path to CCV data file.
+        ccv_root (str): CCV HDF group name.
+        report_to (str): Metadata location.
+
+    Returns:
+        None
+
+    Raises:
+        RuntimeError: If CalCat POST request fails.
+    """
+
+    pdu_name, calibration, key = ccv_root.lstrip('/').split('/')
+
+    with h5py.File(const_src, 'r') as const_file:
+        pdu_group = const_file[pdu_name]
+        pdu_uuid = pdu_group.attrs['uuid']
+        detector_type = pdu_group.attrs['detector_type']
+
+        ccv_group = const_file[ccv_root]
+        proposal, runs = ccv_group.attrs['proposal'], ccv_group.attrs['runs']
+        begin_at_str = ccv_group.attrs['begin_at']
+
+        condition_group = ccv_group['operating_condition']
+
+        cond_params = []
+
+        # It's really not ideal we're mixing conditionS and condition now.
+        for parameter in condition_group:
+            param_dset = condition_group[parameter]
+            cond_params.append({
+                'parameter_name': param_dset.attrs['database_name'],
+                'value': float(param_dset[()]),
+                'lower_deviation_value': param_dset.attrs['lower_deviation'],
+                'upper_deviation_value': param_dset.attrs['upper_deviation'],
+                'flg_available': True
+            })
+
+    const_rel_path = f'xfel/cal/{detector_type.lower()}/{pdu_name.lower()}'
+    const_filename = f'cal.{time.time()}.h5'
+
+    if proposal and len(runs) > 0:
+        raw_data_location = 'proposal:{} runs: {}'.format(
+            proposal, ' '.join([str(x) for x in runs]))
+    else:
+        pass  # Fallback for non-run based constants
+
+    # Generate condition name.
+    unique_name = detector_type[:detector_type.index('-Type')] + ' Def'
+    cond_hash = md5(pdu_name.encode())
+    cond_hash.update(int(pdu_uuid).to_bytes(
+        length=8, byteorder='little', signed=False))
+
+    for param_dict in cond_params:
+        cond_hash.update(str(param_dict['parameter_name']).encode())
+        cond_hash.update(str(param_dict['value']).encode())
+
+    unique_name += binascii.b2a_base64(cond_hash.digest()).decode()
+    unique_name = unique_name[:60]
+
+    # Add PDU "UUID" to parameters.
+    cond_params.append({
+        'parameter_name': 'Detector UUID',
+        'value': unpack('d', pack('q', pdu_uuid))[0],
+        'lower_deviation_value': 0.0,
+        'upper_deviation_value': 0.0,
+        'flg_available': True
+    })
+
+    inject_h = {
+        'detector_condition': {
+            'name': unique_name,
+            'parameters': cond_params
+        },
+        'calibration_constant': {
+            'calibration_name': calibration,
+            'detector_type_name': detector_type,
+            'flg_auto_approve': True
+        },
+        'calibration_constant_version': {
+            'raw_data_location': raw_data_location,
+            'file_name': const_filename,
+            'path_to_file': const_rel_path,
+            'data_set_name': f'{pdu_name}/{calibration}/0',
+            'start_idx': '0',
+            'end_idx': '0',
+            'begin_validity_at': begin_at_str,
+            'end_validity_at': '',
+            'begin_at': begin_at_str,
+            'pdu_physical_name': pdu_name,
+            'flg_good_quality': True
+        }
+    }
+
+    if report_to:
+        report_path = Path(report_to).absolute().with_suffix('.pdf')
+        inject_h['report'] = {
+            'name': report_path.stem,
+            'file_path': str(report_path)
+        }
+
+    const_dest = _get_default_caldb_root() / const_rel_path / const_filename
+    const_dest.parent.mkdir(parents=True, exist_ok=True)
+    copyfile(const_src, const_dest)
+
+    resp = CalibrationClient.inject_new_calibration_constant_version(
+        calibration_client(), inject_h)
+
+    if not resp['success']:
+        const_dest.unlink()  # Delete already copied CCV file.
+        raise RuntimeError(resp)