curl --request POST \
--url https://api.ionworks.com/cell_instances/{cell_instance_id}/cell_measurements/create \
--header 'Content-Type: application/json' \
--data '
{
"name": "<string>",
"properties": {},
"protocol": {},
"start_time": "2023-11-07T05:31:56Z",
"end_time": "2023-11-07T05:31:56Z",
"estimated_end_time": "2023-11-07T05:31:56Z",
"estimated_end_time_note": "<string>",
"estimated_end_time_calculated_at": "2023-11-07T05:31:56Z",
"test_setup": {},
"step_labels_validated": false,
"notes": "<string>",
"measurement_type": "properties",
"file_metadata": {},
"channel_id": "<string>",
"protocol_id": "<string>",
"program_id": "<string>"
}
'import requests
url = "https://api.ionworks.com/cell_instances/{cell_instance_id}/cell_measurements/create"
payload = {
"name": "<string>",
"properties": {},
"protocol": {},
"start_time": "2023-11-07T05:31:56Z",
"end_time": "2023-11-07T05:31:56Z",
"estimated_end_time": "2023-11-07T05:31:56Z",
"estimated_end_time_note": "<string>",
"estimated_end_time_calculated_at": "2023-11-07T05:31:56Z",
"test_setup": {},
"step_labels_validated": False,
"notes": "<string>",
"measurement_type": "properties",
"file_metadata": {},
"channel_id": "<string>",
"protocol_id": "<string>",
"program_id": "<string>"
}
headers = {"Content-Type": "application/json"}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
name: '<string>',
properties: {},
protocol: {},
start_time: '2023-11-07T05:31:56Z',
end_time: '2023-11-07T05:31:56Z',
estimated_end_time: '2023-11-07T05:31:56Z',
estimated_end_time_note: '<string>',
estimated_end_time_calculated_at: '2023-11-07T05:31:56Z',
test_setup: {},
step_labels_validated: false,
notes: '<string>',
measurement_type: 'properties',
file_metadata: {},
channel_id: '<string>',
protocol_id: '<string>',
program_id: '<string>'
})
};
fetch('https://api.ionworks.com/cell_instances/{cell_instance_id}/cell_measurements/create', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.ionworks.com/cell_instances/{cell_instance_id}/cell_measurements/create",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'name' => '<string>',
'properties' => [
],
'protocol' => [
],
'start_time' => '2023-11-07T05:31:56Z',
'end_time' => '2023-11-07T05:31:56Z',
'estimated_end_time' => '2023-11-07T05:31:56Z',
'estimated_end_time_note' => '<string>',
'estimated_end_time_calculated_at' => '2023-11-07T05:31:56Z',
'test_setup' => [
],
'step_labels_validated' => false,
'notes' => '<string>',
'measurement_type' => 'properties',
'file_metadata' => [
],
'channel_id' => '<string>',
'protocol_id' => '<string>',
'program_id' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.ionworks.com/cell_instances/{cell_instance_id}/cell_measurements/create"
payload := strings.NewReader("{\n \"name\": \"<string>\",\n \"properties\": {},\n \"protocol\": {},\n \"start_time\": \"2023-11-07T05:31:56Z\",\n \"end_time\": \"2023-11-07T05:31:56Z\",\n \"estimated_end_time\": \"2023-11-07T05:31:56Z\",\n \"estimated_end_time_note\": \"<string>\",\n \"estimated_end_time_calculated_at\": \"2023-11-07T05:31:56Z\",\n \"test_setup\": {},\n \"step_labels_validated\": false,\n \"notes\": \"<string>\",\n \"measurement_type\": \"properties\",\n \"file_metadata\": {},\n \"channel_id\": \"<string>\",\n \"protocol_id\": \"<string>\",\n \"program_id\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.ionworks.com/cell_instances/{cell_instance_id}/cell_measurements/create")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"<string>\",\n \"properties\": {},\n \"protocol\": {},\n \"start_time\": \"2023-11-07T05:31:56Z\",\n \"end_time\": \"2023-11-07T05:31:56Z\",\n \"estimated_end_time\": \"2023-11-07T05:31:56Z\",\n \"estimated_end_time_note\": \"<string>\",\n \"estimated_end_time_calculated_at\": \"2023-11-07T05:31:56Z\",\n \"test_setup\": {},\n \"step_labels_validated\": false,\n \"notes\": \"<string>\",\n \"measurement_type\": \"properties\",\n \"file_metadata\": {},\n \"channel_id\": \"<string>\",\n \"protocol_id\": \"<string>\",\n \"program_id\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.ionworks.com/cell_instances/{cell_instance_id}/cell_measurements/create")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\n \"name\": \"<string>\",\n \"properties\": {},\n \"protocol\": {},\n \"start_time\": \"2023-11-07T05:31:56Z\",\n \"end_time\": \"2023-11-07T05:31:56Z\",\n \"estimated_end_time\": \"2023-11-07T05:31:56Z\",\n \"estimated_end_time_note\": \"<string>\",\n \"estimated_end_time_calculated_at\": \"2023-11-07T05:31:56Z\",\n \"test_setup\": {},\n \"step_labels_validated\": false,\n \"notes\": \"<string>\",\n \"measurement_type\": \"properties\",\n \"file_metadata\": {},\n \"channel_id\": \"<string>\",\n \"protocol_id\": \"<string>\",\n \"program_id\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"name": "<string>",
"id": "<string>",
"cell_instance_id": "<string>",
"organization_id": "<string>",
"project_id": "<string>",
"created_at": "2023-11-07T05:31:56Z",
"updated_at": "2023-11-07T05:31:56Z",
"protocol": {},
"start_time": "2023-11-07T05:31:56Z",
"end_time": "2023-11-07T05:31:56Z",
"estimated_end_time": "2023-11-07T05:31:56Z",
"estimated_end_time_note": "<string>",
"estimated_end_time_calculated_at": "2023-11-07T05:31:56Z",
"test_setup": {},
"step_labels_validated": false,
"notes": "<string>",
"measurement_type": "time_series",
"properties": {},
"file_metadata": {},
"channel_id": "<string>",
"protocol_id": "<string>",
"program_id": "<string>",
"created_by": "<string>",
"created_by_email": "<string>",
"processing_status": "ready",
"processing_error": "<string>",
"source_etag": "<string>",
"row_count": 123,
"time_series_bytes": 123,
"recorded_duration_s": 123,
"estimated_end_time_status": "estimating",
"estimated_end_time_job_id": "<string>",
"extend_claim_id": "<string>",
"extend_in_progress_at": "2023-11-07T05:31:56Z",
"extend_claimed_at": "2023-11-07T05:31:56Z"
}{
"detail": [
{
"loc": [
"<string>"
],
"msg": "<string>",
"type": "<string>",
"input": "<unknown>",
"ctx": {}
}
]
}Create a properties-type measurement directly
Create a properties-type measurement without the upload flow.
Use this for manual measurements like thickness, weight, etc.
curl --request POST \
--url https://api.ionworks.com/cell_instances/{cell_instance_id}/cell_measurements/create \
--header 'Content-Type: application/json' \
--data '
{
"name": "<string>",
"properties": {},
"protocol": {},
"start_time": "2023-11-07T05:31:56Z",
"end_time": "2023-11-07T05:31:56Z",
"estimated_end_time": "2023-11-07T05:31:56Z",
"estimated_end_time_note": "<string>",
"estimated_end_time_calculated_at": "2023-11-07T05:31:56Z",
"test_setup": {},
"step_labels_validated": false,
"notes": "<string>",
"measurement_type": "properties",
"file_metadata": {},
"channel_id": "<string>",
"protocol_id": "<string>",
"program_id": "<string>"
}
'import requests
url = "https://api.ionworks.com/cell_instances/{cell_instance_id}/cell_measurements/create"
payload = {
"name": "<string>",
"properties": {},
"protocol": {},
"start_time": "2023-11-07T05:31:56Z",
"end_time": "2023-11-07T05:31:56Z",
"estimated_end_time": "2023-11-07T05:31:56Z",
"estimated_end_time_note": "<string>",
"estimated_end_time_calculated_at": "2023-11-07T05:31:56Z",
"test_setup": {},
"step_labels_validated": False,
"notes": "<string>",
"measurement_type": "properties",
"file_metadata": {},
"channel_id": "<string>",
"protocol_id": "<string>",
"program_id": "<string>"
}
headers = {"Content-Type": "application/json"}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
name: '<string>',
properties: {},
protocol: {},
start_time: '2023-11-07T05:31:56Z',
end_time: '2023-11-07T05:31:56Z',
estimated_end_time: '2023-11-07T05:31:56Z',
estimated_end_time_note: '<string>',
estimated_end_time_calculated_at: '2023-11-07T05:31:56Z',
test_setup: {},
step_labels_validated: false,
notes: '<string>',
measurement_type: 'properties',
file_metadata: {},
channel_id: '<string>',
protocol_id: '<string>',
program_id: '<string>'
})
};
fetch('https://api.ionworks.com/cell_instances/{cell_instance_id}/cell_measurements/create', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.ionworks.com/cell_instances/{cell_instance_id}/cell_measurements/create",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'name' => '<string>',
'properties' => [
],
'protocol' => [
],
'start_time' => '2023-11-07T05:31:56Z',
'end_time' => '2023-11-07T05:31:56Z',
'estimated_end_time' => '2023-11-07T05:31:56Z',
'estimated_end_time_note' => '<string>',
'estimated_end_time_calculated_at' => '2023-11-07T05:31:56Z',
'test_setup' => [
],
'step_labels_validated' => false,
'notes' => '<string>',
'measurement_type' => 'properties',
'file_metadata' => [
],
'channel_id' => '<string>',
'protocol_id' => '<string>',
'program_id' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.ionworks.com/cell_instances/{cell_instance_id}/cell_measurements/create"
payload := strings.NewReader("{\n \"name\": \"<string>\",\n \"properties\": {},\n \"protocol\": {},\n \"start_time\": \"2023-11-07T05:31:56Z\",\n \"end_time\": \"2023-11-07T05:31:56Z\",\n \"estimated_end_time\": \"2023-11-07T05:31:56Z\",\n \"estimated_end_time_note\": \"<string>\",\n \"estimated_end_time_calculated_at\": \"2023-11-07T05:31:56Z\",\n \"test_setup\": {},\n \"step_labels_validated\": false,\n \"notes\": \"<string>\",\n \"measurement_type\": \"properties\",\n \"file_metadata\": {},\n \"channel_id\": \"<string>\",\n \"protocol_id\": \"<string>\",\n \"program_id\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.ionworks.com/cell_instances/{cell_instance_id}/cell_measurements/create")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"<string>\",\n \"properties\": {},\n \"protocol\": {},\n \"start_time\": \"2023-11-07T05:31:56Z\",\n \"end_time\": \"2023-11-07T05:31:56Z\",\n \"estimated_end_time\": \"2023-11-07T05:31:56Z\",\n \"estimated_end_time_note\": \"<string>\",\n \"estimated_end_time_calculated_at\": \"2023-11-07T05:31:56Z\",\n \"test_setup\": {},\n \"step_labels_validated\": false,\n \"notes\": \"<string>\",\n \"measurement_type\": \"properties\",\n \"file_metadata\": {},\n \"channel_id\": \"<string>\",\n \"protocol_id\": \"<string>\",\n \"program_id\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.ionworks.com/cell_instances/{cell_instance_id}/cell_measurements/create")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\n \"name\": \"<string>\",\n \"properties\": {},\n \"protocol\": {},\n \"start_time\": \"2023-11-07T05:31:56Z\",\n \"end_time\": \"2023-11-07T05:31:56Z\",\n \"estimated_end_time\": \"2023-11-07T05:31:56Z\",\n \"estimated_end_time_note\": \"<string>\",\n \"estimated_end_time_calculated_at\": \"2023-11-07T05:31:56Z\",\n \"test_setup\": {},\n \"step_labels_validated\": false,\n \"notes\": \"<string>\",\n \"measurement_type\": \"properties\",\n \"file_metadata\": {},\n \"channel_id\": \"<string>\",\n \"protocol_id\": \"<string>\",\n \"program_id\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"name": "<string>",
"id": "<string>",
"cell_instance_id": "<string>",
"organization_id": "<string>",
"project_id": "<string>",
"created_at": "2023-11-07T05:31:56Z",
"updated_at": "2023-11-07T05:31:56Z",
"protocol": {},
"start_time": "2023-11-07T05:31:56Z",
"end_time": "2023-11-07T05:31:56Z",
"estimated_end_time": "2023-11-07T05:31:56Z",
"estimated_end_time_note": "<string>",
"estimated_end_time_calculated_at": "2023-11-07T05:31:56Z",
"test_setup": {},
"step_labels_validated": false,
"notes": "<string>",
"measurement_type": "time_series",
"properties": {},
"file_metadata": {},
"channel_id": "<string>",
"protocol_id": "<string>",
"program_id": "<string>",
"created_by": "<string>",
"created_by_email": "<string>",
"processing_status": "ready",
"processing_error": "<string>",
"source_etag": "<string>",
"row_count": 123,
"time_series_bytes": 123,
"recorded_duration_s": 123,
"estimated_end_time_status": "estimating",
"estimated_end_time_job_id": "<string>",
"extend_claim_id": "<string>",
"extend_in_progress_at": "2023-11-07T05:31:56Z",
"extend_claimed_at": "2023-11-07T05:31:56Z"
}{
"detail": [
{
"loc": [
"<string>"
],
"msg": "<string>",
"type": "<string>",
"input": "<unknown>",
"ctx": {}
}
]
}Path Parameters
Body
Request model for creating a properties-type measurement directly (no upload).
Inherits field validation (including validate_properties) from
CellMeasurementBase. Overrides measurement_type default and
makes properties required.
1 - 255Key-value measurements using Quantity format for numerics. Example: {'thickness': {'value': 0.52, 'unit': 'mm'}}
Protocol information. Typical keys: 'name' (str), 'ambient_temperature_degc' (float), 'definition' (dict | str — a UCP protocol definition or another protocol format).
ISO 8601 datetime with timezone (UTC preferred) marking when the test started.
ISO 8601 datetime with timezone (UTC preferred) marking when the test finished. Leave null while the test is still running; set it once the measurement is complete. A null end_time means the cell is still considered 'on test' in the Lab view.
ISO 8601 datetime with timezone (UTC preferred) forecasting when a still-running test will finish. Distinct from end_time (the actual finish): this is an estimate. Null when no estimate has been computed yet.
Free-text explanation of how estimated_end_time was derived.
ISO 8601 datetime with timezone marking when estimated_end_time was last computed.
Physical test setup. Typical keys: 'cycler' (model), 'operator', 'lab', 'channel_number'. Readers also record what the cycler header carries, drawn from one shared vocabulary so the shape does not vary by cycler: 'test_name', 'cell_label' (the cycler's own label for the cell, which need not match the cell instance), 'instrument', 'cycler_serial_number', 'software_version', 'temperature_setpoint_degc', 'notes', 'end_time', plus export provenance -- 'export_date', 'source_file_path', 'barcode_comment', and 'source_file_id' (an id in the cycler's own id space, not a cross-system identifier). Which of these a file can fill depends on its format; keys the header does not carry are omitted rather than set empty.
Set to true only once step-type labels (Rest, CC charge, CV, discharge, etc.) have been manually reviewed. Server-inferred labels should leave this false.
Free-text notes about the cell measurement
Must be 'properties' for this endpoint.
time_series, file, properties Metadata about uploaded files (MIME types, dimensions, etc.)
Optional ID of the channel this measurement ran on.
Optional ID of the experiment template (protocol) this measurement was run against.
Optional catalog program for this measurement (copied from a linked planned measurement when present).
Response
Successful Response
1 - 255Organization this measurement belongs to.
Project this measurement belongs to
Protocol information. Typical keys: 'name' (str), 'ambient_temperature_degc' (float), 'definition' (dict | str — a UCP protocol definition or another protocol format).
ISO 8601 datetime with timezone (UTC preferred) marking when the test started.
ISO 8601 datetime with timezone (UTC preferred) marking when the test finished. Leave null while the test is still running; set it once the measurement is complete. A null end_time means the cell is still considered 'on test' in the Lab view.
ISO 8601 datetime with timezone (UTC preferred) forecasting when a still-running test will finish. Distinct from end_time (the actual finish): this is an estimate. Null when no estimate has been computed yet.
Free-text explanation of how estimated_end_time was derived.
ISO 8601 datetime with timezone marking when estimated_end_time was last computed.
Physical test setup. Typical keys: 'cycler' (model), 'operator', 'lab', 'channel_number'. Readers also record what the cycler header carries, drawn from one shared vocabulary so the shape does not vary by cycler: 'test_name', 'cell_label' (the cycler's own label for the cell, which need not match the cell instance), 'instrument', 'cycler_serial_number', 'software_version', 'temperature_setpoint_degc', 'notes', 'end_time', plus export provenance -- 'export_date', 'source_file_path', 'barcode_comment', and 'source_file_id' (an id in the cycler's own id space, not a cross-system identifier). Which of these a file can fill depends on its format; keys the header does not carry are omitted rather than set empty.
Set to true only once step-type labels (Rest, CC charge, CV, discharge, etc.) have been manually reviewed. Server-inferred labels should leave this false.
Free-text notes about the cell measurement
What shape of data this measurement holds. Determines which fields are populated and which upload flow applies. See the class docstring.
time_series, file, properties Flat key/value measurements, populated only when measurement_type is 'properties'. Numeric values use the Quantity format. Example: {'thickness': {'value': 0.52, 'unit': 'mm'}, 'DCIR': {'value': 12, 'unit': 'mohm'}}.
Metadata about uploaded files (MIME types, dimensions, etc.)
Optional ID of the channel this measurement ran on.
Optional ID of the experiment template (protocol) this measurement was run against.
Optional catalog program for this measurement (copied from a linked planned measurement when present).
User ID of the user who created this measurement
Email of the user who created this measurement
Lifecycle of server-side step processing. 'ready' once steps are available; 'pending'/'running' while the upload is being processed asynchronously; 'failed' if processing failed (see processing_error).
pending, running, ready, failed, awaiting_extend, extending Reason processing failed, when processing_status is 'failed'. Also carries why an extend did not apply, in which case the status is back to 'ready' and this is advisory only.
Lifecycle of a duration estimate computed by a background simulation.
Used by both estimates: a planned test's total duration
(planned_measurements.estimated_duration_*) and a running test's
remaining duration (cell_measurements.estimated_end_time_*). One enum
because the lifecycle is identical -- only what is being estimated differs.
estimating while the job is in flight, ready once a value came from
it, failed with the reason in the accompanying note. None means no
estimate was ever requested.
estimating, ready, failed Opaque token identifying the in-flight extend that holds this measurement, and the staging prefix its delta is uploaded to. Non-null exactly while processing_status is 'awaiting_extend' or 'extending'.
Deprecated and always null. Use processing_status.
When the in-flight extend claim was taken. Written only by the claim itself, so an unrelated update to the measurement does not age it. Null when no extend holds the measurement.
Was this page helpful?