Register the materials in your lab#

Five lines per material — create it, save it into your library, keep the IRI:

from battinfo.api import create_material_spec, save_material_spec

nmc = create_material_spec(name="NMC811", material_class="active_material",
                           electrode_polarity="positive", formula="LiNi0.8Mn0.1Co0.1O2")
saved = save_material_spec(nmc, source_root="my-library", mode="upsert")
NMC811_IRI = saved["id"]   # e.g. https://w3id.org/battinfo/spec/3ypr-gngx-x28c-rarf

source_root is the folder that holds your record library (records land in my-library/material-spec/). mode="upsert" makes the call safe to re-run: the same material converges on the same record instead of erroring as a duplicate.

Variants#

A binder, a conductive additive, a salt, a solvent — same five lines, different material_class:

pvdf = save_material_spec(create_material_spec(
    name="PVDF", material_class="binder", formula="(C2H2F2)n"),
    source_root="my-library", mode="upsert")

salt = save_material_spec(create_material_spec(
    name="LiPF6", material_class="electrolyte_salt", formula="LiPF6"),
    source_root="my-library", mode="upsert")

Valid material_class values: active_material, binder, conductive_additive, current_collector, separator_material, electrolyte_salt, electrolyte_solvent, electrolyte_additive, metal_electrode, coating, other.

With a manufacturer and a datasheet number:

graphite = save_material_spec(create_material_spec(
    name="Graphite", material_class="active_material", electrode_polarity="negative",
    formula="C", manufacturer="Targray",
    property={"specific_capacity": {"value": 355, "unit": "mAh/g"}}),
    source_root="my-library", mode="upsert")

Quantities are always {"value": ..., "unit": ...} maps; a measured value can also carry the conditions it was measured under — see Materials for the property and composition reference.

Find them again#

Query your own library by passing its directory explicitly — with no argument, query_material_specs() reads the example records packaged with BattINFO, not yours:

from battinfo.api import query_material_specs

mine = query_material_specs(material_class="active_material",
                            directory="my-library/material-spec")
print(sorted(m["name"] for m in mine))   # ['Graphite', 'NMC811']

Log a physical lot#

The spec is the datasheet; a material record is the jar on the shelf:

from battinfo.api import create_material, save_material

lot = create_material(material_spec_id=NMC811_IRI, lot_id="CANRUD-NMC-2026-07")
save_material(lot, source_root="my-library", mode="upsert")

What just happened#

Each save wrote one plain-JSON record into your library and minted it a permanent https://w3id.org/battinfo/spec/ IRI. That IRI is how everything else refers to the material: electrode recipes reference it (see Build a cell from components), and the saved record validates against the material-spec schema before it lands. Re-saving with mode="upsert" updates in place — same IRI, never a duplicate.