Working with storage units and compartments
Working with storage units and compartments
Storage units (freezers, cabinets, equipment) and their compartments (shelves, racks, sample boxes) are modelled as two related resources in the API. This guide covers how to create, find, and navigate them, and answers the most common question: when to use storageID versus storageLayerID.
Concepts
A storage unit — represented by a storageID — is the top-level object (e.g., a freezer). Every storage unit contains a hierarchy of compartments, each identified by a storageLayerID. When a storage unit is created, the API automatically creates a root compartment at the top of its hierarchy.
A storage unit is not itself a compartment. You cannot call
/storageLayers/{id}with astorageID— the two ID spaces are separate. A storage unit has a root compartment (the auto-created one), and most operations that feel like they act on "the unit's contents" — including settingaltID— act on that root compartment.
Storage unit (storageID)
└── Root compartment (storageLayerID, auto-created)
├── Shelf (storageLayerID)
│ └── Sample box (storageLayerID)
│ └── Samples
└── Shelf (storageLayerID)
└── ...
storageID is used for operations that apply to the unit itself — its type, managers, validations, status, reports, meta fields, and so on. storageLayerID is used for anything inside the unit — adding a compartment, placing samples, creating a reservation, or reading the compartment's logs.
storageID vs storageLayerID — quick reference
storageID vs storageLayerID — quick referenceUse storageID for | Use storageLayerID for |
|---|---|
GET /storage/{storageID} | GET /storageLayers/{storageLayerID} |
PATCH /storage/{storageID} | PATCH /storageLayers/{storageLayerID} |
PUT /storage/{storageID}/status | POST /storageLayers/{storageLayerID}/childLayers |
GET /storage/{storageID}/statistics | GET /storageLayers/{storageLayerID}/samples |
POST /storage/{storageID}/managers | POST /storageLayers/{storageLayerID}/reservations |
POST /storage/{storageID}/meta | GET /storageLayers/{storageLayerID}/logs |
POST /storage/{storageID}/validations | GET /storageLayers/{storageLayerID}/ancestry |
Creating a storage unit
Create a storage unit with POST /storage and a storageTypeID. The response returns both identifiers — the storageID of the unit and the storageLayerID of its auto-created root compartment.
POST /api/v1/storage{
"storageTypeID": 42,
"name": "My -80°C Freezer",
"department": "Lab A",
"building": "Main Hall"
}Response:
{
"storageID": 1234,
"storageLayerID": 5678
}Keep both values: you'll use storageID for unit-level settings, and storageLayerID as the starting point to add compartments below.
Adding compartments
Compartments are created inside a parent compartment via POST /storageLayers/{parentStorageLayerID}/childLayers. The parent is usually the root compartment returned when the unit was created, or another compartment you added later.
POST /api/v1/storageLayers/5678/childLayers{
"name": "Top shelf",
"storageLayerDefinitionID": 7,
"icon": "shelf"
}The storageLayerDefinitionID points to a compartment template that defines the compartment's dimensions and whether it's a grid (sample box) or a simple container. Create templates first via POST /storage/{storageID}/storageLayerDefinitions.
Valid icon values are unknown, shelf, samplebox, or a custom instrument icon name. If omitted, the icon is inherited from the storage layer definition.
To create many compartments at once, use POST /storageLayers/{parentStorageLayerID}/childLayers/bulk with an array of StorageLayerNew objects.
Finding a compartment by barcode
Every compartment has a system-generated barcode based on its storageLayerID. You can also attach an external/custom barcode by setting altID on the compartment — useful when migrating from an existing system or bridging to third-party equipment.
GET /storageLayers/forBarcodes searches both the system barcodes and the custom altID values:
GET /api/v1/storageLayers/forBarcodes?barcodes=RACK-A-007,MY-CUSTOM-BOX-12&$expand=storageThe ?$expand=storage expand includes the parent storage unit (and its storageID) on every returned compartment — useful when a scanner gives you a barcode but you don't yet know which unit it belongs to.
Retrieving storageID from a storageLayerID
storageID from a storageLayerIDThe storageLayerID of any compartment can be resolved to its parent storageID via the storage expand:
GET /api/v1/storageLayers/{storageLayerID}?$expand=storageThe response includes a storage object with the parent unit's storageID, name, type, and other fields. This is the canonical path — there is no separate "look up storage by layer" endpoint.
Attaching an external barcode to a storage unit
altID is stored on the compartment, not on the storage unit itself. To give a storage unit an external barcode, set altID on its root compartment.
If you only have the storageID (e.g., you picked one out of GET /storage), first read the unit to obtain the root compartment's storageLayerID:
GET /api/v1/storage/1234{
"storageID": 1234,
"storageLayerID": 5678,
"name": "My -80°C Freezer",
"storageType": { "...": "..." }
}Then PATCH the root compartment with the external barcode:
PATCH /api/v1/storageLayers/5678{
"altID": "FREEZER-A-007"
}A successful call returns 204 No Content. Afterwards, GET /storageLayers/forBarcodes?barcodes=FREEZER-A-007 will resolve the barcode back to storageLayerID 5678, and expanding ?$expand=storage on the result will give you the parent storageID 1234 again.
The same pattern — read the unit, then PATCH /storageLayers/{rootStorageLayerID} — works for any field that lives on the compartment record (e.g., renaming the root compartment). Fields that live on the unit record (name, department, building, storageTypeID, status, etc.) are updated via PATCH /storage/{storageID} instead.
Moving samples into compartments
Samples are placed into compartments via the sample's storageLayerID field on Create a new sample or Update a sample's properties. To find where a sample is currently located, call Get samples with ?$expand=location.
Archive and delete
DELETE /storageLayers/{storageLayerID} archives a compartment. When the compartment contains samples, use the deleteStorageLayerSamplesBehaviour query parameter to specify archive (archive the samples) or moveToLayer (move them to a parent).
DELETE /storage/{storageID} archives the entire storage unit and all compartments inside it. Archived units and compartments can be restored via the relevant restore endpoints.
Further reading
- Pagination — most list endpoints above return a paginated response.
- Expand and Sort — how
$expandand$sortwork on list endpoints. - Error handling — how the API signals errors and how to interpret them.
Updated 3 days ago