Evidence
SDS Field Coverage Matrix: Sections 1-16
Which SDS section lands in which JSON key, what each section usually contains, and how to measure coverage on your own documents.
Last updated: 2026-10-24
What is fixed and what is not
The response carries one JSON object per SDS section under outputs.json. The 16 section keys below are part of the contract. Inside each section, the OpenAPI contract describes the content as an object and does not enumerate its fields, and the sub-fields shown here come from a sample response. Field names inside a section can vary with the document, so map defensively and validate against your own sample set.
Section to key matrix
| SDS section | Name | Key in outputs.json | Typically contains | Sub-fields in our sample response |
|---|---|---|---|---|
| 1 | Identification | product_identification | Product identifier, supplier details, emergency contact, recommended use | product_name recommended_use supplier_name |
| 2 | Hazard identification | hazards_identification | Classification, label elements (signal word, hazard and precautionary statements), other hazards | ghs_classification signal_word h_statements p_statements |
| 3 | Composition / information on ingredients | composition | Substances and mixture components, CAS and EC numbers, concentration ranges | substance_name cas_number concentration_percent |
| 4 | First-aid measures | first_aid | Measures by route of exposure, symptoms, need for medical attention | inhalation skin_contact eye_contact |
| 5 | Firefighting measures | fire_fighting | Extinguishing media, special hazards, advice for firefighters | suitable_extinguishing_media |
| 6 | Accidental release measures | accidental_release | Personal precautions, environmental precautions, containment and cleanup | spill_response |
| 7 | Handling and storage | handling_storage | Safe handling precautions, storage conditions, incompatibilities | handling_precautions storage_conditions |
| 8 | Exposure controls / personal protection | exposure_controls_ppe | Occupational exposure limits, engineering controls, personal protective equipment | exposure_limits ppe |
| 9 | Physical and chemical properties | physical_chemical_properties | Appearance, odour, flash point, other measured properties | appearance odor flash_point_c |
| 10 | Stability and reactivity | stability_reactivity | Reactivity, chemical stability, conditions and materials to avoid | stability |
| 11 | Toxicological information | toxicological_information | Acute and chronic health effects, routes of exposure | acute_toxicity |
| 12 | Ecological information | ecological_information | Ecotoxicity, persistence, bioaccumulation | aquatic_toxicity |
| 13 | Disposal considerations | disposal_considerations | Waste treatment and disposal methods | disposal_method |
| 14 | Transport information | transport_information | UN number, proper shipping name, hazard class, packing group | un_number proper_shipping_name hazard_class packing_group |
| 15 | Regulatory information | regulatory_information | Safety, health and environmental regulations specific to the product | tsca |
| 16 | Other information | revision_metadata | Revision date, version, other information | revision_date version |
What coverage does and does not mean
- A section being present as a key does not mean the source document contained it. Information missing from the source is expected to come back as null, empty strings or empty arrays.
confidence_scoreandwarningsdescribe the document as a whole. We do not publish per-field or per-section coverage percentages.- H and P statement codes, CAS numbers and UN numbers are standardized identifiers, so they are the easiest values to check against the source.
- Language does not change the keys. See multilingual extraction for what we do and do not claim by language.
Measure coverage on your own documents
Run a representative folder of SDS PDFs through the API and count how often each section is filled. This uses the Python client:
import collections, glob, os
from safetydatasheetapi import Client
SECTIONS = [
"product_identification", "hazards_identification", "composition", "first_aid", "fire_fighting",
"accidental_release", "handling_storage", "exposure_controls_ppe", "physical_chemical_properties",
"stability_reactivity", "toxicological_information", "ecological_information", "disposal_considerations",
"transport_information", "regulatory_information", "revision_metadata",
]
client = Client(api_key=os.environ["SDS_API_KEY"])
filled, documents = collections.Counter(), 0
for path in glob.glob("sample-sds/*.pdf"):
record = client.extract(path)["outputs"]["json"]
documents += 1
for section in SECTIONS:
if record.get(section) not in (None, "", [], {}):
filled[section] += 1
for section in SECTIONS:
print(f"{section:32} {filled[section]}/{documents}")
Treat the result as a measurement of your document mix, not a product guarantee. Re-run it when your suppliers or languages change.
FAQ
Does the API always return all 16 sections?
The 16 section keys are the contract. Sections the source document does not contain are expected to come back empty.
Are the fields inside each section guaranteed?
The contract guarantees the section keys, not the field names inside them. Use the sample set approach above to see what your documents produce.
Can I get coverage numbers per section?
We do not publish them. The script above measures them on your own documents.
Related pages
- Output contract in the API docs
- MSDS to JSON API
- GHS classification extraction
- UN number extraction
- Schema versioning