Skip to main content

API Reference (Leader /api)

Conventions​

  • Only the leader Pioreactor has the /api endpoints exposed.
  • Async endpoints return 202 Accepted with a task_id and result_url_path.
  • Poll GET /unit_api/task_results/{task_id} until status is succeeded or failed.
  • $broadcast may be used in path parameters where documented to target all units/workers.
  • File download endpoints return binary bodies; use the response content-type to handle them.
  • Path parameters are shown inline in the endpoint URL.
  • Request/response examples are the canonical shapes; omit optional fields you do not need.
  • Errors have the following schema:
{
"error": "Human-readable error message",
"cause": "Human-readable cause (defaults to error if not set)",
"remediation": "Suggested fix or next step",
"status": 400
}

Use /api/workers/... for worker-only targets (experiment-scoped jobs/logs) and /api/units/... when the leader is also a valid target; both accept $broadcast where supported.

Pioreactor Leader API

Generated from core/pioreactor/web/api.py.

This file is generated. Edit the API source or generator instead of editing this file by hand.

Endpoint count: 156

Endpoint Index​

MethodPathHandler
GET/api/automations/descriptors/{automation_type}get_automation_descriptors
GET/api/charts/descriptorsget_chart_descriptors
GET/api/config/sharedget_shared_config
PATCH/api/config/sharedupdate_shared_config
GET/api/config/shared/historyget_shared_config_history
GET/api/config/units/{pioreactor_unit}get_config_for_pioreactor_unit
GET/api/config/units/{pioreactor_unit}/specificget_specific_config_for_pioreactor_unit
PATCH/api/config/units/{pioreactor_unit}/specificupdate_specific_config_for_pioreactor_unit
GET/api/config/units/{pioreactor_unit}/specific/historyget_specific_config_history_for_pioreactor_unit
GET/api/config/zippedget_zipped_configs
GET/api/datasets/exportableget_exportable_datasets
GET/api/datasets/exportable/{target_dataset}/previewpreview_exportable_dataset
POST/api/datasets/exportable/exportexport_exportable_datasets
POST/api/datasets/exportable/export-to-usbexport_exportable_datasets_to_usb
GET/api/experiment_profilesget_experiment_profiles
POST/api/experiment_profilescreate_experiment_profile
DELETE/api/experiment_profiles/{filename}delete_experiment_profile
GET/api/experiment_profiles/{filename}get_experiment_profile
PATCH/api/experiment_profiles/{filename}update_experiment_profile
GET/api/experimentsget_experiments
POST/api/experimentscreate_experiment
DELETE/api/experiments/{experiment}delete_experiment
GET/api/experiments/{experiment}get_experiment
PATCH/api/experiments/{experiment}update_experiment
GET/api/experiments/{experiment}/chart_preferencesget_experiment_chart_preferences
PATCH/api/experiments/{experiment}/chart_preferencesupdate_experiment_chart_preferences
GET/api/experiments/{experiment}/camerasget_camera_statuses_for_experiment
GET/api/experiments/{experiment}/experiment_profiles/recentget_recent_experiment_profile_runs
GET/api/experiments/{experiment}/experiment_profiles/runningget_running_profiles
GET/api/experiments/{experiment}/historical_worker_assignmentsget_list_of_historical_workers_for_experiment
GET/api/experiments/{experiment}/logsget_exp_logs
GET/api/experiments/{experiment}/media_ratesget_media_rates
GET/api/experiments/{experiment}/recent_logsget_recent_logs
GET/api/experiments/{experiment}/time_series/{data_source}/{column}get_fallback_time_series
GET/api/experiments/{experiment}/time_series/growth_ratesget_growth_rates
GET/api/experiments/{experiment}/time_series/od_readingsget_od_readings
GET/api/experiments/{experiment}/time_series/od_readings_filteredget_od_readings_filtered
GET/api/experiments/{experiment}/time_series/od_readings_fusedget_od_readings_fused
GET/api/experiments/{experiment}/time_series/raw_od_readingsget_od_raw_readings
GET/api/experiments/{experiment}/time_series/temperature_readingsget_temperature_readings
GET/api/experiments/{experiment}/unit_labelsget_unit_labels
PATCH/api/experiments/{experiment}/unit_labelsupsert_unit_labels
PUT/api/experiments/{experiment}/unit_labelsupsert_unit_labels
DELETE/api/experiments/{experiment}/workersremove_workers_from_experiment
GET/api/experiments/{experiment}/workersget_list_of_workers_for_experiment
PUT/api/experiments/{experiment}/workersadd_worker_to_experiment
DELETE/api/experiments/{experiment}/workers/{pioreactor_unit}remove_worker_from_experiment
GET/api/experiments/activeget_active_experiments
GET/api/experiments/assignment_countget_experiments_worker_assignments
GET/api/experiments/latestget_latest_experiment
GET/api/jobs/descriptorsget_job_descriptors
GET/api/local_access_pointget_local_access_point
GET/api/logsget_logs
GET/api/modelsget_models
GET/api/settings/descriptorsget_settings_descriptors
POST/api/system/update_from_archiveupdate_app_from_release_archive
POST/api/system/update_next_versionupdate_app
POST/api/system/uploadupload_system_file
POST/api/system/utc_clockset_system_utc_clock
GET/api/unitsget_list_of_units
GET/api/units/{pioreactor_unit}/capabilitiesget_capabilities
POST/api/units/{pioreactor_unit}/experiments/{experiment}/logspublish_new_log
POST/api/units/{pioreactor_unit}/import_zipped_dot_pioreactorimport_dot_pioreactor_archive
PATCH/api/units/{pioreactor_unit}/jobs/run/job_name/{job_name}/experiments/{experiment}run_job_on_unit_in_experiment
POST/api/units/{pioreactor_unit}/jobs/run/job_name/{job_name}/experiments/{experiment}run_job_on_unit_in_experiment
GET/api/units/{pioreactor_unit}/jobs/runningget_jobs_running
PATCH/api/units/{pioreactor_unit}/jobs/stop/experiments/{experiment}stop_all_jobs_on_unit_for_experiment
POST/api/units/{pioreactor_unit}/jobs/stop/experiments/{experiment}stop_all_jobs_on_unit_for_experiment
PATCH/api/units/{pioreactor_unit}/jobs/stop/job_name/{job_name}/experiments/{experiment}stop_specific_job_on_unit
POST/api/units/{pioreactor_unit}/jobs/stop/job_name/{job_name}/experiments/{experiment}stop_specific_job_on_unit
PATCH/api/units/{pioreactor_unit}/jobs/update/job_name/{job_name}/experiments/{experiment}update_job_on_unit
GET/api/units/{pioreactor_unit}/logsget_logs_for_unit
PATCH/api/units/{pioreactor_unit}/plugins/installinstall_plugin_across_cluster
POST/api/units/{pioreactor_unit}/plugins/installinstall_plugin_across_cluster
PATCH/api/units/{pioreactor_unit}/plugins/install-from-leader-usbinstall_plugin_from_leader_usb_on_machine
POST/api/units/{pioreactor_unit}/plugins/install-from-leader-usbinstall_plugin_from_leader_usb_on_machine
GET/api/units/{pioreactor_unit}/plugins/installedget_plugins_on_machine
PATCH/api/units/{pioreactor_unit}/plugins/uninstalluninstall_plugin_across_cluster
POST/api/units/{pioreactor_unit}/plugins/uninstalluninstall_plugin_across_cluster
POST/api/units/{pioreactor_unit}/system/rebootreboot_unit
POST/api/units/{pioreactor_unit}/system/repairrepair_unit
POST/api/units/{pioreactor_unit}/system/shutdownshutdown_unit
GET/api/units/{pioreactor_unit}/system/utc_clockget_unit_utc_clock
GET/api/units/{pioreactor_unit}/system_logsget_system_logs_for_unit
GET/api/units/{pioreactor_unit}/usbget_usb_status_on_machine
GET/api/units/{pioreactor_unit}/usb/artifactsget_usb_artifacts_on_machine
POST/api/units/{pioreactor_unit}/usb/ejecteject_usb_on_machine
POST/api/units/{pioreactor_unit}/usb/mountmount_usb_on_machine
GET/api/units/{pioreactor_unit}/versions/appget_app_versions
GET/api/units/{pioreactor_unit}/zipped_dot_pioreactorget_zipped_dot_pioreactor
GET/api/workersget_list_of_workers
PUT/api/workersadd_worker
DELETE/api/workers/{pioreactor_unit}delete_worker
GET/api/workers/{pioreactor_unit}get_worker
GET/api/workers/{pioreactor_unit}/active_calibrationsget_all_active_calibrations
DELETE/api/workers/{pioreactor_unit}/active_calibrations/{device}remove_active_status_calibration
PATCH/api/workers/{pioreactor_unit}/active_calibrations/{device}/{calibration_name}set_active_calibration
GET/api/workers/{pioreactor_unit}/active_estimatorsget_all_active_estimators
DELETE/api/workers/{pioreactor_unit}/active_estimators/{device}remove_active_status_estimator
PATCH/api/workers/{pioreactor_unit}/active_estimators/{device}/{estimator_name}set_active_estimator
GET/api/workers/{pioreactor_unit}/automations/descriptors/{automation_type}get_automation_descriptors_for_worker
PATCH/api/workers/{pioreactor_unit}/bioreactor/update/experiments/{experiment}update_bioreactor_on_unit
POST/api/workers/{pioreactor_unit}/blinkblink_worker
GET/api/workers/{pioreactor_unit}/calibration_protocolsget_calibration_protocols
GET/api/workers/{pioreactor_unit}/calibrationsget_all_calibrations
GET/api/workers/{pioreactor_unit}/calibrations/{device}get_calibrations
POST/api/workers/{pioreactor_unit}/calibrations/{device}create_calibration
DELETE/api/workers/{pioreactor_unit}/calibrations/{device}/{calibration_name}delete_calibration
GET/api/workers/{pioreactor_unit}/calibrations/{device}/{calibration_name}get_calibration
POST/api/workers/{pioreactor_unit}/calibrations/sessionsstart_calibration_session
GET/api/workers/{pioreactor_unit}/calibrations/sessions/{session_id}get_calibration_session
POST/api/workers/{pioreactor_unit}/calibrations/sessions/{session_id}/abortabort_calibration_session
POST/api/workers/{pioreactor_unit}/calibrations/sessions/{session_id}/inputsadvance_calibration_session
GET/api/workers/{pioreactor_unit}/camera/experiments/{experiment}/statusget_camera_status_for_worker
GET/api/workers/{pioreactor_unit}/camera/experiments/{experiment}/stillslist_camera_stills_for_worker_experiment
POST/api/workers/{pioreactor_unit}/camera/experiments/{experiment}/stillscapture_camera_still_for_worker_experiment
GET/api/workers/{pioreactor_unit}/camera/experiments/{experiment}/stills.zipget_zipped_camera_stills_for_worker_experiment
DELETE/api/workers/{pioreactor_unit}/camera/experiments/{experiment}/stills/{image_id}.jpgdelete_camera_still_for_worker_experiment
GET/api/workers/{pioreactor_unit}/camera/experiments/{experiment}/stills/{image_id}.jpgget_camera_still_for_worker_experiment
PATCH/api/workers/{pioreactor_unit}/camera/experiments/{experiment}/stills/{image_id}.jpgrename_camera_still_for_worker_experiment
GET/api/workers/{pioreactor_unit}/camera/focus_sessions/{session_id}/preview.jpgget_camera_focus_preview_for_worker
PATCH/api/workers/{pioreactor_unit}/camera/settingsupdate_camera_settings_for_worker
GET/api/workers/{pioreactor_unit}/capabilitiesget_capabilities
GET/api/workers/{pioreactor_unit}/estimatorsget_all_estimators
GET/api/workers/{pioreactor_unit}/estimators/{device}get_estimators_by_device
DELETE/api/workers/{pioreactor_unit}/estimators/{device}/{estimator_name}delete_estimator
GET/api/workers/{pioreactor_unit}/estimators/{device}/{estimator_name}get_estimator
GET/api/workers/{pioreactor_unit}/experimentget_experiment_assignment_for_worker
GET/api/workers/{pioreactor_unit}/experiments/{experiment}/logsget_logs_for_unit_and_experiment
POST/api/workers/{pioreactor_unit}/experiments/{experiment}/logspublish_new_log
GET/api/workers/{pioreactor_unit}/experiments/{experiment}/recent_logsget_recent_logs_for_unit_and_experiment
GET/api/workers/{pioreactor_unit}/experiments/{experiment}/time_series/{data_source}/{column}get_fallback_time_series_per_unit
GET/api/workers/{pioreactor_unit}/experiments/{experiment}/time_series/growth_ratesget_growth_rates_per_unit
GET/api/workers/{pioreactor_unit}/experiments/{experiment}/time_series/od_readingsget_od_readings_per_unit
GET/api/workers/{pioreactor_unit}/experiments/{experiment}/time_series/od_readings_filteredget_od_readings_filtered_per_unit
GET/api/workers/{pioreactor_unit}/experiments/{experiment}/time_series/od_readings_fusedget_od_readings_fused_per_unit
GET/api/workers/{pioreactor_unit}/experiments/{experiment}/time_series/raw_od_readingsget_od_raw_readings_per_unit
GET/api/workers/{pioreactor_unit}/experiments/{experiment}/time_series/temperature_readingsget_temperature_readings_per_unit
PUT/api/workers/{pioreactor_unit}/is_activechange_worker_status
GET/api/workers/{pioreactor_unit}/jobs/descriptorsget_job_descriptors_for_worker
PATCH/api/workers/{pioreactor_unit}/jobs/run/job_name/{job_name}/experiments/{experiment}run_job_on_unit_in_experiment
POST/api/workers/{pioreactor_unit}/jobs/run/job_name/{job_name}/experiments/{experiment}run_job_on_unit_in_experiment
GET/api/workers/{pioreactor_unit}/jobs/runningget_jobs_running
GET/api/workers/{pioreactor_unit}/jobs/settings/job_name/{job_name}/experiments/{experiment}get_job_settings_for_worker
GET/api/workers/{pioreactor_unit}/jobs/settings/job_name/{job_name}/setting/{setting}/experiments/{experiment}get_job_setting_for_worker
PATCH/api/workers/{pioreactor_unit}/jobs/stop/experiments/{experiment}stop_all_jobs_on_unit_for_experiment
POST/api/workers/{pioreactor_unit}/jobs/stop/experiments/{experiment}stop_all_jobs_on_unit_for_experiment
PATCH/api/workers/{pioreactor_unit}/jobs/stop/job_name/{job_name}/experiments/{experiment}stop_specific_job_on_unit
POST/api/workers/{pioreactor_unit}/jobs/stop/job_name/{job_name}/experiments/{experiment}stop_specific_job_on_unit
PATCH/api/workers/{pioreactor_unit}/jobs/update/job_name/{job_name}/experiments/{experiment}update_job_on_unit
GET/api/workers/{pioreactor_unit}/modelget_worker_model_and_metadata
PUT/api/workers/{pioreactor_unit}/modelchange_worker_model
GET/api/workers/{pioreactor_unit}/settings/descriptorsget_settings_descriptors_for_worker
GET/api/workers/{pioreactor_unit}/task_results/{task_id}get_task_result_for_worker
GET/api/workers/{pioreactor_unit}/zipped_calibrationsget_zipped_calibrations
DELETE/api/workers/assignmentsremove_all_workers_from_all_experiments
GET/api/workers/assignmentsget_workers_and_experiment_assignments
GET/api/workers/discoverdiscover_available_workers
POST/api/workers/setupsetup_worker_pioreactor

Get Automation Descriptors​

Return the leader's automation UI descriptors for one automation family.

Endpoint​

GET /api/automations/descriptors/{automation_type}

Request​

Path Parameters​

NameTypeRequiredDescription
automation_typestringYesAutomation type, for example dosing, temperature, or led.

Response​

Success​

Status: 200 OK

Example body:

[
{
"display_name": "Only record temperature",
"automation_name": "only_record_temperature",
"description": "Apply no heating, only record the temperature.",
"source": null,
"fields": []
},
{
"display_name": "Thermostat",
"automation_name": "thermostat",
"description": "Vary the amount of applied heating to keep the culture near a target temperature, using a control-loop.",
"source": null,
"fields": [
{
"key": "target_temperature",
"default": 30,
"label": "Target temperature",
"disabled": false,
"required": true,
"unit": "\u2103",
"type": "numeric",
"options": null
}
]
}
]

Get Chart Descriptors​

Return the leader's chart UI descriptors.

Endpoint​

GET /api/charts/descriptors

Response​

Success​

Status: 200 OK

Example body:

[
{
"chart_key": "implied_growth_rate",
"data_source": "growth_rates",
"title": "Implied growth rate",
"source": "app",
"y_axis_label": "Growth rate, h\u207b\u00b9",
"fixed_decimals": 2,
"down_sample": true,
"mqtt_topic": "growth_rate_calculating/growth_rate",
"lookback": 100000,
"data_source_column": null,
"payload_key": "growth_rate",
"y_transformation": "(y) => y",
"y_axis_domain": [
-0.02,
0.1
],
"interpolation": "stepAfter"
},
{
"chart_key": "implied_daily_growth_rate",
"data_source": "growth_rates",
"title": "Implied daily growth rate",
"source": "app",
"y_axis_label": "Growth rate, d\u207b\u00b9",
"fixed_decimals": 2,
"down_sample": true,
"mqtt_topic": "growth_rate_calculating/growth_rate",
"lookback": 100000,
"data_source_column": null,
"payload_key": "growth_rate",
"y_transformation": "(y) => 24 * y",
"y_axis_domain": [
-0.1,
1.0
],
"interpolation": "stepAfter"
},
{
"chart_key": "fraction_of_volume_that_is_alternative_media",
"data_source": "alt_media_fractions",
"title": "Fraction of volume that is alternative media",
"source": "app",
"y_axis_label": "Fraction",
"fixed_decimals": 3,
"down_sample": false,
"mqtt_topic": "bioreactor/alt_media_fraction",
"lookback": 100000,
"data_source_column": "alt_media_fraction",
"payload_key": null,
"y_transformation": "(y) => y",
"y_axis_domain": [
0.0,
0.05
],
"interpolation": "stepAfter"
}
]

Get Shared Config​

Get Shared Config endpoint.

Endpoint​

GET /api/config/shared

Response​

Success​

Status: 200 OK

Response body is plain text.

Update Shared Config​

Update Shared Config endpoint.

Endpoint​

PATCH /api/config/shared

Request​

Request Body​

NameTypeRequiredDescription
codestringYescode.
{
"code": "[section]\nkey=value\n"
}

Response​

Success​

Status: 200 OK

Example body:

{
"status": "success"
}

Get Shared Config History​

Get Shared Config History endpoint.

Endpoint​

GET /api/config/shared/history

Response​

Success​

Status: 200 OK

Example body:

[
{
"filename": "config.ini",
"timestamp": "2026-08-04T21:28:03.520Z",
"data": "[PWM]\n# map the externals to the PWM\n# hardware PWM are available on channels 1 & 3.\n1=stirring\n2=waste\n3=media\n4=alt_media\n5=heating\n\n\n[leds]\nA=IR\nB=white_light\nC=\nD=\n\n\n[bioreactor]\n# efflux_tube_volume_ml is determined by the volume that just touches the outflow tube. I.e. if you\n# where to keep running the waste pump, what would the stable volume be.\n# see docs\nefflux_tube_volume_ml=14\ninitial_volume_ml=14\ninitial_alt_media_fraction=0.0\ninitial_cumulative_media_added_ml=0\ninitial_cumulative_a...<truncated>"
},
{
"filename": "config.ini",
"timestamp": "2026-08-04T21:27:21.754Z",
"data": "[PWM]\n# map the externals to the PWM\n# hardware PWM are available on channels 1 & 3.\n1=stirring\n2=waste\n3=media\n4=alt_media\n5=heating\n\n\n[leds]\nA=IR\nB=white_light\nC=\nD=\n\n\n[bioreactor]\n# efflux_tube_volume_ml is determined by the volume that just touches the outflow tube. I.e. if you\n# where to keep running the waste pump, what would the stable volume be.\n# see docs\nefflux_tube_volume_ml=14\ninitial_volume_ml=14\ninitial_alt_media_fraction=0.0\ninitial_cumulative_media_added_ml=0\ninitial_cumulative_a...<truncated>"
},
{
"filename": "config.ini",
"timestamp": "2026-06-30T16:13:30.963Z",
"data": "[PWM]\n# map the externals to the PWM\n# hardware PWM are available on channels 1 & 3.\n1=stirring\n2=waste\n3=media\n4=alt_media\n5=heating\n\n\n[leds]\nA=IR\nB=white_light\nC=\nD=\n\n\n[bioreactor]\n# efflux_tube_volume_ml is determined by the volume that just touches the outflow tube. I.e. if you\n# where to keep running the waste pump, what would the stable volume be.\n# see docs\nefflux_tube_volume_ml=14\ninitial_volume_ml=14\ninitial_alt_media_fraction=0.0\ninitial_cumulative_media_added_ml=0\ninitial_cumulative_a...<truncated>"
}
]

Get Config For Pioreactor Unit​

Get merged configs, optionally limiting $broadcast with repeated unit query parameters.

Endpoint​

GET /api/config/units/{pioreactor_unit}

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.

Response​

Success​

Status: 200 OK

Example body:

{
"configs": {
"localhost": {
"PWM": {
"1": "stirring",
"2": "waste",
"3": "media",
"4": "bubblert",
"5": "heating"
},
"leds": {
"A": "IR",
"B": "white_light",
"C": "",
"D": ""
},
"bioreactor": {
"efflux_tube_volume_ml": "14",
"initial_volume_ml": "14",
"initial_alt_media_fraction": "0.0",
"initial_cumulative_media_added_ml": "0",
"initial_cumulative_alt_media_added_ml": "0",
"initial_cumulative_waste_removed_ml": "0"
},
"stirring.config": {
"initial_target_rpm": "500",
"initial_duty_cycle": "15",
"pwm_hz": "200",
"use_rpm": "True",
"duration_between_updates_seconds": "23",
"post_delay_duration": "0.25",
"pre_delay_duration": "0.25",
"enable_dodging_od": "true",
"target_rpm_during_od_reading": "0",
"target_rpm_outside_od_reading": "500"
},
"dosing_automation.turbidostat": {
"biomass_signal": "auto"
},
"stirring.pid": {
"Kp": "0.007",
"Ki": "0.0",
"Kd": "0.0"
},
"od_config.photodiode_channel": {
"1": "REF",
"2": "90"
},
"od_reading.config": {
"samples_per_second": "0.2",
"turn_off_leds_during_reading": "1",
"pd_reference_ema": "0.4",
"ir_led_intensity": "80",
"duration_between_led_off_and_od_reading": "0.1",
"smoothing_penalizer": "6.0",
"use_dark_offsets": "1"
},
"camera": {
"snapshot_interval_minutes": "5",
"camera_index": "0",
"ir_led_intensity": "90",
"enabled": "1",
"keep_camera_active": "0"
},
"storage": {
"database": "/Users/camerondavidson-pilon/code/pioreactor/.pioreactor/storage/pioreactor.sqlite",
"temporary_cache": "/Users/camerondavidson-pilon/code/pioreactor/.pioreactor/storage/local_intermittent_pioreactor_metadata.sqlite",
"persistent_cache": "/Users/camerondavidson-pilon/code/pioreactor/.pioreactor/storage/local_persistent_pioreactor_metadata.sqlite",
"number_of_backup_replicates_to_workers": "0"
},
"logging": {
"log_file": "./pioreactor.log",
"ui_log_file": "./pioreactor.log",
"ui_log_level": "DEBUG",
"console_log_level": "DEBUG"
},
"cluster.topology": {
"leader_hostname": "localhost",
"leader_address": "localhost"
},
"ui.overview.settings": {
"filtered_od_lookback_minutes": "240",
"raw_od_lookback_minutes": "240",
"log_display_count": "65",
"time_display_mode": "hours"
},
"ui": {
"port": "4999",
"proto": "http"
},
"ui.overview.charts": {
"implied_growth_rate": "1",
"implied_daily_growth_rate": "0",
"fraction_of_volume_that_is_alternative_media": "1",
"normalized_optical_density": "1",
"raw_optical_density": "1",
"temperature": "1",
"optical_density": "1"
},
"ui.overview.cards": {
"dosings": "1",
"event_logs": "1",
"profiles": "1"
},
"dosing_automation.pid_morbidostat": {
"Kp": "5",
"Ki": "0",
"Kd": "0"
},
"temperature_automation.thermostat": {
"Kp": ".01",
"Ki": ".01",
"Kd": ".01"
},
"mqtt": {
"username": "pioreactor",
"password": "raspberry",
"broker_address": "localhost",
"broker_ws_port": "9001",
"broker_port": "1883",
"ws_protocol": "ws",
"use_tls": "0"
},
"dosing_automation.config": {
"pause_between_subdoses_seconds": "0.5",
"waste_removal_multiplier": "2.0",
"max_volume_to_warn": "17.0",
"max_volume_to_stop": "18.0",
"max_subdose": "1.0",
"experimental_pump_malfunction_tolerance": "0.2",
"experimental_detect_pump_malfunction": "False"
}
}
},
"errors": {}
}

Get Specific Config For Pioreactor Unit​

Get Specific Config For Pioreactor Unit endpoint.

Endpoint​

GET /api/config/units/{pioreactor_unit}/specific

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.

Response​

Success​

Status: 200 OK

Response body is plain text.

Update Specific Config For Pioreactor Unit​

Update Specific Config For Pioreactor Unit endpoint.

Endpoint​

PATCH /api/config/units/{pioreactor_unit}/specific

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.

Request Body​

NameTypeRequiredDescription
codestringYescode.
{
"code": "[section]\nkey=value\n"
}

Response​

Success​

Status: 200 OK

Example body:

{
"status": "success"
}

Get Specific Config History For Pioreactor Unit​

Get Specific Config History For Pioreactor Unit endpoint.

Endpoint​

GET /api/config/units/{pioreactor_unit}/specific/history

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.

Response​

Success​

Status: 200 OK

Example body:

[
{
"filename": "unit_config.ini::localhost",
"timestamp": "2026-04-08T00:58:21.686Z",
"data": "[PWM]\n# map the externals to the PWM\n# hardware PWM are available on channels 1 & 3.\n1=stirring\n2=waste\n3=media\n4=bubblert\n5=heating"
},
{
"filename": "unit_config.ini::localhost",
"timestamp": "2026-04-08T00:18:45.007Z",
"data": "[PWM]\n# map the externals to the PWM\n# hardware PWM are available on channels 1 & 3.\n1=stirring\n2=waste\n3=media\n4=bubbler\n5=heating"
},
{
"filename": "config_localhost.ini",
"timestamp": "2025-12-03T02:50:38.730Z",
"data": "[bioreactor]\nmax_volume_ml=30\n"
}
]

Get Zipped Configs​

Get Zipped Configs endpoint.

Endpoint​

GET /api/config/zipped

Response​

Success​

Status: 200 OK

Response body is binary file data.

Get Exportable Datasets​

Get Exportable Datasets endpoint.

Endpoint​

GET /api/datasets/exportable

Response​

Success​

Status: 200 OK

Example body:

[
{
"dataset_name": "pioreactor_unit_activity_data",
"description": "This dataset includes most of your experiment data, including the time series of OD metrics, temperature, stirring rates, LED updates, and dosings.",
"display_name": "Pioreactor unit activity data (recommended)",
"has_experiment": true,
"has_unit": true,
"default_order_by": "timestamp",
"table": "pioreactor_unit_activity_data",
"query": null,
"source": "app",
"timestamp_columns": [
"timestamp"
],
"always_partition_by_unit": true,
"column_descriptions": {},
"column_units": {}
},
{
"dataset_name": "logs",
"description": "This dataset includes the append-only collection of logs from all Pioreactors. A subset of these logs are displayed in the Log Table in the Experiment Overview.",
"display_name": "Pioreactor logs",
"has_experiment": true,
"has_unit": true,
"default_order_by": "timestamp",
"table": "logs",
"query": null,
"source": "app",
"timestamp_columns": [
"timestamp"
],
"always_partition_by_unit": false,
"column_descriptions": {},
"column_units": {}
},
{
"dataset_name": "od_readings",
"description": "This dataset includes a time series of readings provided by the sensors (transformed via a calibration curve, if available), the inputs for growth calculations and normalized optical density.",
"display_name": "Optical density",
"has_experiment": true,
"has_unit": true,
"default_order_by": "timestamp",
"table": "od_readings",
"query": null,
"source": "app",
"timestamp_columns": [
"timestamp"
],
"always_partition_by_unit": false,
"column_descriptions": {},
"column_units": {}
}
]

Preview Exportable Dataset​

Preview Exportable Dataset endpoint.

Endpoint​

GET /api/datasets/exportable/{target_dataset}/preview

Request​

Path Parameters​

NameTypeRequiredDescription
target_datasetstringYesExportable dataset name.

Response​

Success​

Status: 200 OK

Example body:

[
{
"timestamp": "2026-01-01T00:00:00Z",
"pioreactor_unit": "pio01",
"experiment": "testing_experiment"
}
]

Export Exportable Datasets​

Export selected datasets for one experiment.

Endpoint​

POST /api/datasets/exportable/export

Request​

Request Body​

NameTypeRequiredDescription
datasetsarrayYesdatasets.
experimentstringYesexperiment.
partition_by_experimentbooleanYespartition by experiment.
partition_by_unitbooleanYespartition by unit.
end_timeobjectNoend time.
start_timeobjectNostart time.
{
"datasets": [
"od_readings"
],
"experiment": "testing_experiment",
"partition_by_experiment": true,
"partition_by_unit": true,
"end_time": "2026-01-01T12:00:00Z",
"start_time": "2026-01-01T00:00:00Z"
}

Response​

Success​

Status: 202 Accepted

Example body:

{
"unit": "pio01",
"task_id": "abcd1234",
"result_url_path": "/unit_api/task_results/abcd1234",
"status": "accepted"
}

Export Exportable Datasets To Usb​

Export selected datasets for one experiment to the leader's mounted USB.

Endpoint​

POST /api/datasets/exportable/export-to-usb

Request​

Request Body​

NameTypeRequiredDescription
datasetsarrayYesdatasets.
experimentstringYesexperiment.
partition_by_experimentbooleanYespartition by experiment.
partition_by_unitbooleanYespartition by unit.
end_timeobjectNoend time.
start_timeobjectNostart time.
{
"datasets": [
"od_readings"
],
"experiment": "testing_experiment",
"partition_by_experiment": true,
"partition_by_unit": true,
"end_time": "2026-01-01T12:00:00Z",
"start_time": "2026-01-01T00:00:00Z"
}

Response​

Success​

Status: 202 Accepted

Example body:

{
"unit": "pio01",
"task_id": "abcd1234",
"result_url_path": "/unit_api/task_results/abcd1234",
"status": "accepted"
}

Get Experiment Profiles​

Get Experiment Profiles endpoint.

Endpoint​

GET /api/experiment_profiles

Response​

Success​

Status: 200 OK

Example body:

[
{
"experimentProfile": {
"version": "1.0",
"experiment_profile_name": "updating_jobs",
"metadata": {
"author": "Cam Davidson-Pilon",
"description": "A profile to immediately start stirring, heating to 30C, and, after 2h, update temperature to 35C."
},
"plugins": [],
"common": {
"jobs": {
"stirring": {
"actions": "<truncated>",
"description": "<truncated>"
},
"temperature_automation": {
"actions": "<truncated>",
"description": "<truncated>"
}
}
},
"pioreactors": {},
"inputs": {}
},
"file": "update_temp.yaml",
"fullpath": "/Users/camerondavidson-pilon/code/pioreactor/.pioreactor/experiment_profiles/update_temp.yaml"
},
{
"experimentProfile": {
"version": "1.0",
"experiment_profile_name": "test_simple1",
"metadata": {
"author": "Jane Doe",
"description": null
},
"plugins": [],
"common": {
"jobs": {
"od_reading": {
"actions": "<truncated>",
"description": "<truncated>"
}
}
},
"pioreactors": {},
"inputs": {}
},
"file": "test_simple.yaml",
"fullpath": "/Users/camerondavidson-pilon/code/pioreactor/.pioreactor/experiment_profiles/test_simple.yaml"
},
{
"experimentProfile": {
"version": "1.0",
"experiment_profile_name": "temp_test",
"metadata": {
"author": null,
"description": "testing https://forum.pioreactor.com/t/writing-an-experimental-profile-based-on-a-temperature-automation-dependent-on-a-desired-od-reading/774"
},
"plugins": [],
"common": {
"jobs": {}
},
"pioreactors": {
"localhost": {
"jobs": {
"temperature_automation": "<truncated>"
},
"label": null
}
},
"inputs": {}
},
"file": "temp_test.yaml",
"fullpath": "/Users/camerondavidson-pilon/code/pioreactor/.pioreactor/experiment_profiles/temp_test.yaml"
}
]

Create Experiment Profile​

Create an experiment profile YAML file.

Endpoint​

POST /api/experiment_profiles

Request​

Request Body​

NameTypeRequiredDescription
bodystringYesbody.
filenamestringYesfilename.
{
"body": "Profile YAML or text content.",
"filename": "profile.yaml"
}

Response​

Success​

Status: 200 OK

Example body:

{
"status": "success"
}

Delete Experiment Profile​

Delete Experiment Profile endpoint.

Endpoint​

DELETE /api/experiment_profiles/{filename}

Request​

Path Parameters​

NameTypeRequiredDescription
filenamestringYesFilename.

Response​

Success​

Status: 200 OK

Example body:

{
"status": "success"
}

Get Experiment Profile​

Get Experiment Profile endpoint.

Endpoint​

GET /api/experiment_profiles/{filename}

Request​

Path Parameters​

NameTypeRequiredDescription
filenamestringYesFilename.

Response​

Success​

Status: 200 OK

Response body is plain text.

Update Experiment Profile​

Update Experiment Profile endpoint.

Endpoint​

PATCH /api/experiment_profiles/{filename}

Request​

Path Parameters​

NameTypeRequiredDescription
filenamestringYesFilename.

Request Body​

NameTypeRequiredDescription
bodystringYesbody.
{
"body": "Profile YAML or text content."
}

Response​

Success​

Status: 200 OK

Example body:

{
"status": "success"
}

Get Experiments​

Get Experiments endpoint.

Endpoint​

GET /api/experiments

Response​

Success​

Status: 200 OK

Example body:

[
{
"experiment": "demo",
"created_at": "2026-07-08T15:25:38.033Z",
"description": "aefaefef",
"delta_hours": 984.0,
"worker_count": 0,
"tags": [
"awdawd",
"rgrg"
]
},
{
"experiment": "test_bioreactor_topics_land_in_db2",
"created_at": "2026-07-08T15:19:13.502Z",
"description": null,
"delta_hours": 984.0,
"worker_count": 0,
"tags": []
},
{
"experiment": "test_bioreactor_topics_land_in_db",
"created_at": "2026-06-22T14:55:36.582000+00:00",
"description": null,
"delta_hours": 1369.0,
"worker_count": 0,
"tags": []
}
]

Create Experiment​

Create a new experiment.

Endpoint​

POST /api/experiments

Request​

Request Body​

NameTypeRequiredDescription
experimentstringYesexperiment.
descriptionstringNodescription.
tagsarrayNotags.
{
"experiment": "testing_experiment",
"description": "Experiment notes.",
"tags": [
"screening"
]
}

Response​

Success​

Status: 201 Created

Example body:

{
"experiment": "testing_experiment",
"created_at": "2026-01-01T00:00:00Z",
"description": "Experiment notes.",
"delta_hours": 0,
"worker_count": 1,
"tags": [
"screening"
]
}

Delete Experiment​

Delete Experiment endpoint.

Endpoint​

DELETE /api/experiments/{experiment}

Request​

Path Parameters​

NameTypeRequiredDescription
experimentstringYesExperiment identifier.

Response​

Success​

Status: 202 Accepted

Example body:

{
"unit": "pio01",
"task_id": "abcd1234",
"result_url_path": "/unit_api/task_results/abcd1234",
"status": "accepted"
}

Get Experiment​

Get Experiment endpoint.

Endpoint​

GET /api/experiments/{experiment}

Request​

Path Parameters​

NameTypeRequiredDescription
experimentstringYesExperiment identifier.

Response​

Success​

Status: 200 OK

Example body:

{
"experiment": "demo",
"created_at": "2026-07-08T15:25:38.033Z",
"description": "aefaefef",
"delta_hours": 984.0,
"worker_count": 0,
"tags": [
"awdawd",
"rgrg"
]
}

Update Experiment​

Update Experiment endpoint.

Endpoint​

PATCH /api/experiments/{experiment}

Request​

Path Parameters​

NameTypeRequiredDescription
experimentstringYesExperiment identifier.

Request Body​

NameTypeRequiredDescription
descriptionstringNodescription.
tagsarrayNotags.
{
"description": "Experiment notes.",
"tags": [
"screening"
]
}

Response​

Success​

Status: 200 OK

Example body:

{
"experiment": "testing_experiment",
"created_at": "2026-01-01T00:00:00Z",
"description": "Experiment notes.",
"delta_hours": 0,
"worker_count": 1,
"tags": [
"screening"
]
}

Get Experiment Chart Preferences​

Return the experiment's saved chart selections. Overview and individual Pioreactor chart views have independent ordered lists. A null value means the UI uses the configured defaults; an empty list means no charts are selected.

Endpoint​

GET /api/experiments/{experiment}/chart_preferences

Request​

Path Parameters​

NameTypeRequiredDescription
experimentstringYesExperiment identifier.

Response​

Status: 200 OK

{
"overview_chart_keys": ["optical_density", "temperature"],
"pioreactor_chart_keys": null
}

An unknown experiment returns 404 Not Found.

Update Experiment Chart Preferences​

Save chart selection and display order for an experiment. These preferences are stored on the leader and shared across browsers.

Endpoint​

PATCH /api/experiments/{experiment}/chart_preferences

Request​

Path Parameters​

NameTypeRequiredDescription
experimentstringYesExperiment identifier.

JSON Body​

Provide at least one of overview_chart_keys or pioreactor_chart_keys. Each value is an ordered array of distinct chart keys or null to restore configuration defaults. Omitted fields are unchanged. An empty array hides all charts for that view. Obtain valid keys from GET /api/charts/descriptors.

{
"overview_chart_keys": ["optical_density", "temperature"],
"pioreactor_chart_keys": null
}

Response​

Status: 200 OK. Returns both preference fields in the same shape as the GET endpoint.

Duplicate or unavailable chart keys, or a body with neither supported field, return 400 Bad Request. An unknown experiment returns 404 Not Found.

Get Camera Statuses For Experiment​

Get Camera Statuses For Experiment endpoint.

Endpoint​

GET /api/experiments/{experiment}/cameras

Request​

Path Parameters​

NameTypeRequiredDescription
experimentstringYesExperiment identifier.

Response​

Success​

Status: 200 OK

Example body:

{
"cameras": {
"localhost": {
"ok": true,
"unit": "localhost",
"value": {
"unit": "localhost",
"detection_status": "detected",
"runtime_available": true,
"capture_command": null,
"mock": true,
"latest_still": {
"experiment": "demo",
"captured_at": "2026-08-18T15:54:17.433333Z",
"image_id": "20260818T155417.433333Z-a5d9d6ba",
"capture_reason": "scheduled"
},
"auto_capture_enabled": true,
"snapshot_interval_minutes": 5
}
}
}
}

Get Recent Experiment Profile Runs​

Get Recent Experiment Profile Runs endpoint.

Endpoint​

GET /api/experiments/{experiment}/experiment_profiles/recent

Request​

Path Parameters​

NameTypeRequiredDescription
experimentstringYesExperiment identifier.

Response​

Success​

Status: 200 OK

Example body:

[]

Get Running Profiles​

Get Running Profiles endpoint.

Endpoint​

GET /api/experiments/{experiment}/experiment_profiles/running

Request​

Path Parameters​

NameTypeRequiredDescription
experimentstringYesExperiment identifier.

Response​

Success​

Status: 200 OK

Example body:

[]

Get List Of Historical Workers For Experiment​

Get List Of Historical Workers For Experiment endpoint.

Endpoint​

GET /api/experiments/{experiment}/historical_worker_assignments

Request​

Path Parameters​

NameTypeRequiredDescription
experimentstringYesExperiment identifier.

Response​

Success​

Status: 200 OK

Example body:

[
{
"pioreactor_unit": "localhost",
"experiment": "demo",
"is_currently_assigned_to_experiment": 0
}
]

Get Exp Logs​

Shows event logs from all units, uses pagination.

Endpoint​

GET /api/experiments/{experiment}/logs

Request​

Path Parameters​

NameTypeRequiredDescription
experimentstringYesExperiment identifier.

Query Parameters​

NameTypeRequiredDescription
min_levelstringNomin level.

Response​

Success​

Status: 200 OK

Example body:

[
{
"timestamp": "2026-01-01T00:00:00Z",
"level": "INFO",
"message": "Log message.",
"task": "stirring",
"source": "app",
"pioreactor_unit": "pio01",
"experiment": "testing_experiment"
}
]

Get Media Rates​

Shows amount of added media per unit. Note that it only consider values from a dosing automation (i.e. not manual dosing, which includes continously dose)

Endpoint​

GET /api/experiments/{experiment}/media_rates

Request​

Path Parameters​

NameTypeRequiredDescription
experimentstringYesExperiment identifier.

Response​

Success​

Status: 200 OK

Example body:

{
"all": {
"altMediaRate": 0.0,
"mediaRate": 0.0
}
}

Get Recent Logs​

Shows recent event logs from all units

Endpoint​

GET /api/experiments/{experiment}/recent_logs

Request​

Path Parameters​

NameTypeRequiredDescription
experimentstringYesExperiment identifier.

Query Parameters​

NameTypeRequiredDescription
min_levelstringNomin level.

Response​

Success​

Status: 200 OK

Example body:

[
{
"timestamp": "2026-01-01T00:00:00Z",
"level": "INFO",
"message": "Log message.",
"task": "stirring",
"source": "app",
"pioreactor_unit": "pio01",
"experiment": "testing_experiment"
}
]

Get Fallback Time Series​

Get Fallback Time Series endpoint.

Endpoint​

GET /api/experiments/{experiment}/time_series/{data_source}/{column}

Request​

Path Parameters​

NameTypeRequiredDescription
experimentstringYesExperiment identifier.
data_sourcestringYesTime-series data source name.
columnstringYesDataset column name.

Response​

Success​

Status: 200 OK

Body shape: series is a list of series labels. data is a parallel list of point arrays, so data[i] contains the points for series[i]. Each point has x as an ISO-8601 UTC timestamp string and y as a number.

Example body:

{
"series": [
"pio01",
"pio02"
],
"data": [
[
{
"x": "2026-01-01T00:00:00.000Z",
"y": 0.01234
},
{
"x": "2026-01-01T00:01:00.000Z",
"y": 0.0125
}
],
[
{
"x": "2026-01-01T00:00:00.000Z",
"y": 0.00987
},
{
"x": "2026-01-01T00:01:00.000Z",
"y": 0.01001
}
]
]
}

Get Growth Rates​

Gets growth rates for all units

Endpoint​

GET /api/experiments/{experiment}/time_series/growth_rates

Request​

Path Parameters​

NameTypeRequiredDescription
experimentstringYesExperiment identifier.

Response​

Success​

Status: 200 OK

Body shape: series is a list of series labels. data is a parallel list of point arrays, so data[i] contains the points for series[i]. Each point has x as an ISO-8601 UTC timestamp string and y as a number.

Example body:

{
"series": [
"pio01",
"pio02"
],
"data": [
[
{
"x": "2026-01-01T00:00:00.000Z",
"y": 0.01234
},
{
"x": "2026-01-01T00:01:00.000Z",
"y": 0.0125
}
],
[
{
"x": "2026-01-01T00:00:00.000Z",
"y": 0.00987
},
{
"x": "2026-01-01T00:01:00.000Z",
"y": 0.01001
}
]
]
}

Get Od Readings​

Gets raw od for all units

Endpoint​

GET /api/experiments/{experiment}/time_series/od_readings

Request​

Path Parameters​

NameTypeRequiredDescription
experimentstringYesExperiment identifier.

Response​

Success​

Status: 200 OK

Body shape: series is a list of series labels. data is a parallel list of point arrays, so data[i] contains the points for series[i]. Each point has x as an ISO-8601 UTC timestamp string and y as a number.

Example body:

{
"series": [
"pio01",
"pio02"
],
"data": [
[
{
"x": "2026-01-01T00:00:00.000Z",
"y": 0.01234
},
{
"x": "2026-01-01T00:01:00.000Z",
"y": 0.0125
}
],
[
{
"x": "2026-01-01T00:00:00.000Z",
"y": 0.00987
},
{
"x": "2026-01-01T00:01:00.000Z",
"y": 0.01001
}
]
]
}

Get Od Readings Filtered​

Gets normalized od for all units

Endpoint​

GET /api/experiments/{experiment}/time_series/od_readings_filtered

Request​

Path Parameters​

NameTypeRequiredDescription
experimentstringYesExperiment identifier.

Response​

Success​

Status: 200 OK

Body shape: series is a list of series labels. data is a parallel list of point arrays, so data[i] contains the points for series[i]. Each point has x as an ISO-8601 UTC timestamp string and y as a number.

Example body:

{
"series": [
"pio01",
"pio02"
],
"data": [
[
{
"x": "2026-01-01T00:00:00.000Z",
"y": 0.01234
},
{
"x": "2026-01-01T00:01:00.000Z",
"y": 0.0125
}
],
[
{
"x": "2026-01-01T00:00:00.000Z",
"y": 0.00987
},
{
"x": "2026-01-01T00:01:00.000Z",
"y": 0.01001
}
]
]
}

Get Od Readings Fused​

Get Od Readings Fused endpoint.

Endpoint​

GET /api/experiments/{experiment}/time_series/od_readings_fused

Request​

Path Parameters​

NameTypeRequiredDescription
experimentstringYesExperiment identifier.

Response​

Success​

Status: 200 OK

Body shape: series is a list of series labels. data is a parallel list of point arrays, so data[i] contains the points for series[i]. Each point has x as an ISO-8601 UTC timestamp string and y as a number.

Example body:

{
"series": [
"pio01",
"pio02"
],
"data": [
[
{
"x": "2026-01-01T00:00:00.000Z",
"y": 0.01234
},
{
"x": "2026-01-01T00:01:00.000Z",
"y": 0.0125
}
],
[
{
"x": "2026-01-01T00:00:00.000Z",
"y": 0.00987
},
{
"x": "2026-01-01T00:01:00.000Z",
"y": 0.01001
}
]
]
}

Get Od Raw Readings​

Gets raw od for all units

Endpoint​

GET /api/experiments/{experiment}/time_series/raw_od_readings

Request​

Path Parameters​

NameTypeRequiredDescription
experimentstringYesExperiment identifier.

Response​

Success​

Status: 200 OK

Body shape: series is a list of series labels. data is a parallel list of point arrays, so data[i] contains the points for series[i]. Each point has x as an ISO-8601 UTC timestamp string and y as a number.

Example body:

{
"series": [
"pio01",
"pio02"
],
"data": [
[
{
"x": "2026-01-01T00:00:00.000Z",
"y": 0.01234
},
{
"x": "2026-01-01T00:01:00.000Z",
"y": 0.0125
}
],
[
{
"x": "2026-01-01T00:00:00.000Z",
"y": 0.00987
},
{
"x": "2026-01-01T00:01:00.000Z",
"y": 0.01001
}
]
]
}

Get Temperature Readings​

Gets temperature readings for all units

Endpoint​

GET /api/experiments/{experiment}/time_series/temperature_readings

Request​

Path Parameters​

NameTypeRequiredDescription
experimentstringYesExperiment identifier.

Response​

Success​

Status: 200 OK

Body shape: series is a list of series labels. data is a parallel list of point arrays, so data[i] contains the points for series[i]. Each point has x as an ISO-8601 UTC timestamp string and y as a number.

Example body:

{
"series": [
"pio01",
"pio02"
],
"data": [
[
{
"x": "2026-01-01T00:00:00.000Z",
"y": 0.01234
},
{
"x": "2026-01-01T00:01:00.000Z",
"y": 0.0125
}
],
[
{
"x": "2026-01-01T00:00:00.000Z",
"y": 0.00987
},
{
"x": "2026-01-01T00:01:00.000Z",
"y": 0.01001
}
]
]
}

Get Unit Labels​

Get Unit Labels endpoint.

Endpoint​

GET /api/experiments/{experiment}/unit_labels

Request​

Path Parameters​

NameTypeRequiredDescription
experimentstringYesExperiment identifier.

Response​

Success​

Status: 200 OK

Example body:

{}

Upsert Unit Labels​

Update or insert a new unit label for the current experiment.

Endpoint​

PATCH /api/experiments/{experiment}/unit_labels

Request​

Path Parameters​

NameTypeRequiredDescription
experimentstringYesExperiment identifier.

Request Body​

NameTypeRequiredDescription
labelstringYeslabel.
unitstringYesunit.
{
"label": "Control",
"unit": "example_unit"
}

Response​

Success​

Status: 201 Created

Example body:

{
"status": "success"
}

Upsert Unit Labels​

Update or insert a new unit label for the current experiment.

Endpoint​

PUT /api/experiments/{experiment}/unit_labels

Request​

Path Parameters​

NameTypeRequiredDescription
experimentstringYesExperiment identifier.

Request Body​

NameTypeRequiredDescription
labelstringYeslabel.
unitstringYesunit.
{
"label": "Control",
"unit": "example_unit"
}

Response​

Success​

Status: 201 Created

Example body:

{
"status": "success"
}

Remove Workers From Experiment​

Remove Workers From Experiment endpoint.

Endpoint​

DELETE /api/experiments/{experiment}/workers

Request​

Path Parameters​

NameTypeRequiredDescription
experimentstringYesExperiment identifier.

Response​

Success​

Status: 202 Accepted

Example body:

{
"unit": "pio01",
"task_id": "abcd1234",
"result_url_path": "/unit_api/task_results/abcd1234",
"status": "accepted"
}

Get List Of Workers For Experiment​

Get List Of Workers For Experiment endpoint.

Endpoint​

GET /api/experiments/{experiment}/workers

Request​

Path Parameters​

NameTypeRequiredDescription
experimentstringYesExperiment identifier.

Response​

Success​

Status: 200 OK

Example body:

[]

Add Worker To Experiment​

Assign a worker, treating a retry of the current assignment as a no-op.

Endpoint​

PUT /api/experiments/{experiment}/workers

Request​

Path Parameters​

NameTypeRequiredDescription
experimentstringYesExperiment identifier.

Request Body​

NameTypeRequiredDescription
pioreactor_unitstringYespioreactor unit.
{
"pioreactor_unit": "pio02"
}

Response​

Success​

Status: 200 OK

Example body:

{
"status": "success"
}

Remove Worker From Experiment​

Remove Worker From Experiment endpoint.

Endpoint​

DELETE /api/experiments/{experiment}/workers/{pioreactor_unit}

Request​

Path Parameters​

NameTypeRequiredDescription
experimentstringYesExperiment identifier.
pioreactor_unitstringYesUnit name or $broadcast where supported.

Response​

Success​

Status: 200 OK

Example body:

{
"status": "success"
}

Get Active Experiments​

Get list of experiments with at least one active worker assigned

Endpoint​

GET /api/experiments/active

Response​

Success​

Status: 200 OK

Example body:

[
{
"experiment": "ALE - Acetate",
"created_at": "2024-09-04T17:04:46.423882Z",
"description": "MZ PhD Evolution research experiment. Pioreactors 9-16.",
"delta_hours": 17111.0,
"worker_count": 1,
"tags": []
}
]

Get Experiments Worker Assignments​

Get Experiments Worker Assignments endpoint.

Endpoint​

GET /api/experiments/assignment_count

Response​

Success​

Status: 200 OK

Example body:

[
{
"experiment": "ALE - Acetate",
"worker_count": 1
}
]

Get Latest Experiment​

Get Latest Experiment endpoint.

Endpoint​

GET /api/experiments/latest

Response​

Success​

Status: 200 OK

Example body:

{
"experiment": "demo",
"created_at": "2026-07-08T15:25:38.033Z",
"description": "aefaefef",
"delta_hours": 984.0,
"worker_count": 0,
"tags": [
"awdawd",
"rgrg"
]
}

Get Job Descriptors​

Return the leader's background-job UI descriptors.

Endpoint​

GET /api/jobs/descriptors

Response​

Success​

Status: 200 OK

Example body:

[
{
"display_name": "Stirring",
"job_name": "stirring",
"display": true,
"published_settings": [
{
"key": "target_rpm",
"type": "numeric",
"display": true,
"description": "Modify the target RPM of stirring. This will effect the optical density reading. Too low and the stirring may completely stop. Too high and the resulting vortex may interfere with the optics.",
"default": null,
"unit": "RPM",
"label": "Target stir RPM",
"editable": true,
"min": null,
"max": null
}
],
"source": "app",
"description": "Start the stirring on the Pioreactor. Stirring is needed for mixing and proper OD measurements.",
"subtext": null,
"is_testing": false
},
{
"display_name": "Optical density",
"job_name": "od_reading",
"display": true,
"published_settings": [],
"source": "app",
"description": "Collect optical density measurements of the culture over time.",
"subtext": null,
"is_testing": false
},
{
"display_name": "Growth rate",
"job_name": "growth_rate_calculating",
"display": true,
"published_settings": [],
"source": "app",
"description": "Transform optical density measurements into culture growth rate measurements. Start this after innoculation. Begins by sampling for a few minutes to gather a baseline.",
"subtext": null,
"is_testing": false
}
]

Get Local Access Point​

Get Local Access Point endpoint.

Endpoint​

GET /api/local_access_point

Response​

Success​

Status: 200 OK

Example body:

{
"active": false
}

Get Logs​

Shows event logs from all units, uses pagination.

Endpoint​

GET /api/logs

Request​

Query Parameters​

NameTypeRequiredDescription
min_levelstringNomin level.

Response​

Success​

Status: 200 OK

Example body:

[
{
"timestamp": "2026-01-01T00:00:00Z",
"level": "INFO",
"message": "Log message.",
"task": "stirring",
"source": "app",
"pioreactor_unit": "pio01",
"experiment": "testing_experiment"
}
]

Get Models​

Return the list of supported Pioreactor models (name, version, display_name).

Endpoint​

GET /api/models

Response​

Success​

Status: 200 OK

Example body:

{
"models": [
{
"model_name": "pioreactor_40ml",
"model_version": "1.5",
"display_name": "Pioreactor 40ml, v1.5",
"reactor_capacity_ml": 40.0,
"reactor_diameter_mm": 27.0,
"reactor_max_fill_volume_ml": 36.0,
"max_temp_to_reduce_heating": 78.0,
"max_temp_to_disable_heating": 80.0,
"max_temp_to_shutdown": 85.0,
"is_legacy": false,
"is_contrib": false
},
{
"model_name": "pioreactor_40ml",
"model_version": "1.0",
"display_name": "Pioreactor 40ml, v1.0",
"reactor_capacity_ml": 40.0,
"reactor_diameter_mm": 27.0,
"reactor_max_fill_volume_ml": 36.0,
"max_temp_to_reduce_heating": 78.0,
"max_temp_to_disable_heating": 80.0,
"max_temp_to_shutdown": 85.0,
"is_legacy": true,
"is_contrib": false
},
{
"model_name": "pioreactor_20ml",
"model_version": "1.1",
"display_name": "Pioreactor 20ml, v1.1",
"reactor_capacity_ml": 20.0,
"reactor_diameter_mm": 27.0,
"reactor_max_fill_volume_ml": 18.0,
"max_temp_to_reduce_heating": 78.0,
"max_temp_to_disable_heating": 80.0,
"max_temp_to_shutdown": 85.0,
"is_legacy": true,
"is_contrib": false
}
]
}

Get Settings Descriptors​

Return the leader's settings UI descriptors.

Endpoint​

GET /api/settings/descriptors

Response​

Success​

Status: 200 OK

Example body:

[
{
"key": "bioreactor",
"display_name": "Bioreactor",
"display": true,
"published_settings": [
{
"key": "current_volume_ml",
"type": "numeric",
"display": true,
"description": "Current estimated liquid volume in the vial.",
"default": 14.0,
"unit": "mL",
"label": "Current volume",
"editable": true,
"min": 0.0,
"max": null
},
{
"key": "efflux_tube_volume_ml",
"type": "numeric",
"display": true,
"description": "Liquid volume equivalent to the height of the waste/efflux tube.",
"default": 14.0,
"unit": "mL",
"label": "Efflux tube level",
"editable": true,
"min": 0.0,
"max": null
},
{
"key": "alt_media_fraction",
"type": "numeric",
"display": true,
"description": "Fraction of the current volume estimated to be alt media.",
"default": 0.0,
"unit": null,
"label": "Alt media fraction",
"editable": true,
"min": 0.0,
"max": 1.0
}
],
"source": "app",
"description": "Per-unit bioreactor settings.",
"subtext": null
},
{
"key": "leds",
"display_name": "led intensity",
"display": false,
"published_settings": [
{
"key": "intensity",
"type": "string",
"display": true,
"description": null,
"default": null,
"unit": null,
"label": "LED intensity",
"editable": false,
"min": null,
"max": null
}
],
"source": "app",
"description": null,
"subtext": null
},
{
"key": "pwms",
"display_name": "PWMs",
"display": false,
"published_settings": [
{
"key": "dc",
"type": "string",
"display": true,
"description": null,
"default": null,
"unit": null,
"label": "PWM intensity",
"editable": false,
"min": null,
"max": null
}
],
"source": "app",
"description": null,
"subtext": null
}
]

Update App From Release Archive​

Update the Pioreactor app across the cluster from a staged release archive.

Endpoint​

POST /api/system/update_from_archive

Request​

Request Body​

NameTypeRequiredDescription
release_archive_locationstringYesrelease archive location.
unitsstringYesunits.
{
"release_archive_location": "/tmp/release.zip",
"units": "pio01"
}

Response​

Success​

Status: 202 Accepted

Example body:

{
"unit": "pio01",
"task_id": "abcd1234",
"result_url_path": "/unit_api/task_results/abcd1234",
"status": "accepted"
}

Update App​

Update the Pioreactor app across the cluster to the next version.

Endpoint​

POST /api/system/update_next_version

Request​

Request Body​

NameTypeRequiredDescription
unitsstringNounits.
{
"units": "pio01"
}

Response​

Success​

Status: 202 Accepted

Example body:

{
"unit": "pio01",
"task_id": "abcd1234",
"result_url_path": "/unit_api/task_results/abcd1234",
"status": "accepted"
}

Upload System File​

Stage a release archive or other system file on the leader.

Endpoint​

POST /api/system/upload

Response​

Success​

Status: 201 Created

Example body:

{
"message": "File successfully uploaded",
"save_path": "/tmp/file.zip"
}

Set System Utc Clock​

Set the leader UTC clock, then sync workers from the leader.

Endpoint​

POST /api/system/utc_clock

Request​

Request Body​

NameTypeRequiredDescription
utc_clock_timestringYesutc clock time.
{
"utc_clock_time": "2026-01-01T00:00:00Z"
}

Response​

Success​

Status: 202 Accepted

Example body:

{
"unit": "pio01",
"task_id": "abcd1234",
"result_url_path": "/unit_api/task_results/abcd1234",
"status": "accepted"
}

Get List Of Units​

Get List Of Units endpoint.

Endpoint​

GET /api/units

Response​

Success​

Status: 200 OK

Example body:

[
{
"pioreactor_unit": "localhost"
}
]

Get Capabilities​

Get Capabilities endpoint.

Endpoint​

GET /api/units/{pioreactor_unit}/capabilities

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.

Response​

Success​

Status: 202 Accepted

Example body:

{
"unit": "localhost",
"task_id": "fb320b20-371d-4325-955d-10b0fd137311",
"result_url_path": "/unit_api/task_results/fb320b20-371d-4325-955d-10b0fd137311",
"status": "accepted"
}

Publish New Log​

Publish a log message into an experiment log stream.

Endpoint​

POST /api/units/{pioreactor_unit}/experiments/{experiment}/logs

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.
experimentstringYesExperiment identifier.

Request Body​

NameTypeRequiredDescription
levelstringYeslevel.
messagestringYesmessage.
sourcestringYessource.
timestampstringYestimestamp.
source_stringNosource .
taskstringNotask.
{
"level": "INFO",
"message": "Log message.",
"source": "api",
"timestamp": "2026-01-01T00:00:00Z",
"source_": "api",
"task": "stirring"
}

Response​

Success​

Status: 202 Accepted

Example body:

{
"status": "accepted"
}

Import Dot Pioreactor Archive​

Import a zipped DOT_PIOREACTOR archive into one unit.

Endpoint​

POST /api/units/{pioreactor_unit}/import_zipped_dot_pioreactor

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.

Response​

Success​

Status: 201 Created

Response body is binary file data.

Run Job On Unit In Experiment​

Runs specified job on unit.

Endpoint​

PATCH /api/units/{pioreactor_unit}/jobs/run/job_name/{job_name}/experiments/{experiment}

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.
job_namestringYesJob name.
experimentstringYesExperiment identifier.

Request Body​

NameTypeRequiredDescription
argsarrayNoargs.
config_overridesarrayNoconfig overrides.
envobjectNoenv.
optionsobjectNooptions.
{
"options": {
"target_rpm": "200"
},
"env": {
"JOB_SOURCE": "api"
},
"args": [
"some-flag"
],
"config_overrides": [
[
"stirring.config",
"pwm_hz",
"100"
]
]
}

Response​

Success​

Status: 202 Accepted

Example body:

{
"unit": "pio01",
"task_id": "abcd1234",
"result_url_path": "/unit_api/task_results/abcd1234",
"status": "accepted"
}

Run Job On Unit In Experiment​

Runs specified job on unit.

Endpoint​

POST /api/units/{pioreactor_unit}/jobs/run/job_name/{job_name}/experiments/{experiment}

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.
job_namestringYesJob name.
experimentstringYesExperiment identifier.

Request Body​

NameTypeRequiredDescription
argsarrayNoargs.
config_overridesarrayNoconfig overrides.
envobjectNoenv.
optionsobjectNooptions.
{
"options": {
"target_rpm": "200"
},
"env": {
"JOB_SOURCE": "api"
},
"args": [
"some-flag"
],
"config_overrides": [
[
"stirring.config",
"pwm_hz",
"100"
]
]
}

Response​

Success​

Status: 202 Accepted

Example body:

{
"unit": "pio01",
"task_id": "abcd1234",
"result_url_path": "/unit_api/task_results/abcd1234",
"status": "accepted"
}

Get Jobs Running​

Get Jobs Running endpoint.

Endpoint​

GET /api/units/{pioreactor_unit}/jobs/running

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.

Response​

Success​

Status: 202 Accepted

Example body:

{
"unit": "localhost",
"task_id": "f81e1c52-411c-4d3d-898b-8c452b9c88a9",
"result_url_path": "/unit_api/task_results/f81e1c52-411c-4d3d-898b-8c452b9c88a9",
"status": "accepted"
}

Stop All Jobs On Unit For Experiment​

Stop all jobs for one unit, or $broadcast, in one experiment.

Endpoint​

PATCH /api/units/{pioreactor_unit}/jobs/stop/experiments/{experiment}

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.
experimentstringYesExperiment identifier.

Response​

Success​

Status: 202 Accepted

Example body:

{
"status": "success"
}

Stop All Jobs On Unit For Experiment​

Stop all jobs for one unit, or $broadcast, in one experiment.

Endpoint​

POST /api/units/{pioreactor_unit}/jobs/stop/experiments/{experiment}

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.
experimentstringYesExperiment identifier.

Response​

Success​

Status: 202 Accepted

Example body:

{
"status": "success"
}

Stop Specific Job On Unit​

Stop one job on one unit in one experiment.

Endpoint​

PATCH /api/units/{pioreactor_unit}/jobs/stop/job_name/{job_name}/experiments/{experiment}

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.
job_namestringYesJob name.
experimentstringYesExperiment identifier.

Response​

Success​

Status: 202 Accepted

Example body:

{
"unit": "pio01",
"task_id": "abcd1234",
"result_url_path": "/unit_api/task_results/abcd1234",
"status": "accepted"
}

Stop Specific Job On Unit​

Stop one job on one unit in one experiment.

Endpoint​

POST /api/units/{pioreactor_unit}/jobs/stop/job_name/{job_name}/experiments/{experiment}

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.
job_namestringYesJob name.
experimentstringYesExperiment identifier.

Response​

Success​

Status: 202 Accepted

Example body:

{
"unit": "pio01",
"task_id": "abcd1234",
"result_url_path": "/unit_api/task_results/abcd1234",
"status": "accepted"
}

Update Job On Unit​

Update specified job on unit. Use $broadcast for everyone.

Endpoint​

PATCH /api/units/{pioreactor_unit}/jobs/update/job_name/{job_name}/experiments/{experiment}

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.
job_namestringYesJob name.
experimentstringYesExperiment identifier.

Request Body​

NameTypeRequiredDescription
settingsobjectYessettings.
{
"settings": {
"target_rpm": "200"
}
}

Response​

Success​

Status: 202 Accepted

Example body:

{
"status": "accepted"
}

Get Logs For Unit​

Shows event logs from all units, uses pagination.

Endpoint​

GET /api/units/{pioreactor_unit}/logs

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.

Query Parameters​

NameTypeRequiredDescription
min_levelstringNomin level.

Response​

Success​

Status: 200 OK

Example body:

[
{
"timestamp": "2026-01-01T00:00:00Z",
"level": "INFO",
"message": "Log message.",
"task": "stirring",
"source": "app",
"pioreactor_unit": "pio01",
"experiment": "testing_experiment"
}
]

Install Plugin Across Cluster​

Install one plugin on one unit, or $broadcast.

Endpoint​

PATCH /api/units/{pioreactor_unit}/plugins/install

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.

Request Body​

NameTypeRequiredDescription
argsarrayNoargs.
envobjectNoenv.
optionsobjectNooptions.
{
"args": [
"some-flag"
],
"env": {
"JOB_SOURCE": "api"
},
"options": {
"target_rpm": "200"
}
}

Response​

Success​

Status: 202 Accepted

Example body:

{
"unit": "pio01",
"task_id": "abcd1234",
"result_url_path": "/unit_api/task_results/abcd1234",
"status": "accepted"
}

Install Plugin Across Cluster​

Install one plugin on one unit, or $broadcast.

Endpoint​

POST /api/units/{pioreactor_unit}/plugins/install

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.

Request Body​

NameTypeRequiredDescription
argsarrayNoargs.
envobjectNoenv.
optionsobjectNooptions.
{
"args": [
"some-flag"
],
"env": {
"JOB_SOURCE": "api"
},
"options": {
"target_rpm": "200"
}
}

Response​

Success​

Status: 202 Accepted

Example body:

{
"unit": "pio01",
"task_id": "abcd1234",
"result_url_path": "/unit_api/task_results/abcd1234",
"status": "accepted"
}

Install Plugin From Leader Usb On Machine​

Install one plugin artifact from the leader's Pioreactor-managed USB mount onto selected unit(s).

Endpoint​

PATCH /api/units/{pioreactor_unit}/plugins/install-from-leader-usb

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.

Request Body​

NameTypeRequiredDescription
filepathstringYesfilepath.
{
"filepath": "example_filepath"
}

Response​

Success​

Status: 202 Accepted

Example body:

{
"unit": "pio01",
"task_id": "abcd1234",
"result_url_path": "/unit_api/task_results/abcd1234",
"status": "accepted"
}

Install Plugin From Leader Usb On Machine​

Install one plugin artifact from the leader's Pioreactor-managed USB mount onto selected unit(s).

Endpoint​

POST /api/units/{pioreactor_unit}/plugins/install-from-leader-usb

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.

Request Body​

NameTypeRequiredDescription
filepathstringYesfilepath.
{
"filepath": "example_filepath"
}

Response​

Success​

Status: 202 Accepted

Example body:

{
"unit": "pio01",
"task_id": "abcd1234",
"result_url_path": "/unit_api/task_results/abcd1234",
"status": "accepted"
}

Get Plugins On Machine​

Get Plugins On Machine endpoint.

Endpoint​

GET /api/units/{pioreactor_unit}/plugins/installed

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.

Response​

Success​

Status: 202 Accepted

Example body:

{
"unit": "localhost",
"task_id": "d56b6643-69ad-4bce-89dc-fd108cee451b",
"result_url_path": "/unit_api/task_results/d56b6643-69ad-4bce-89dc-fd108cee451b",
"status": "accepted"
}

Uninstall Plugin Across Cluster​

Uninstall one plugin from one unit, or $broadcast.

Endpoint​

PATCH /api/units/{pioreactor_unit}/plugins/uninstall

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.

Request Body​

NameTypeRequiredDescription
argsarrayNoargs.
envobjectNoenv.
optionsobjectNooptions.
{
"args": [
"some-flag"
],
"env": {
"JOB_SOURCE": "api"
},
"options": {
"target_rpm": "200"
}
}

Response​

Success​

Status: 202 Accepted

Example body:

{
"unit": "pio01",
"task_id": "abcd1234",
"result_url_path": "/unit_api/task_results/abcd1234",
"status": "accepted"
}

Uninstall Plugin Across Cluster​

Uninstall one plugin from one unit, or $broadcast.

Endpoint​

POST /api/units/{pioreactor_unit}/plugins/uninstall

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.

Request Body​

NameTypeRequiredDescription
argsarrayNoargs.
envobjectNoenv.
optionsobjectNooptions.
{
"args": [
"some-flag"
],
"env": {
"JOB_SOURCE": "api"
},
"options": {
"target_rpm": "200"
}
}

Response​

Success​

Status: 202 Accepted

Example body:

{
"unit": "pio01",
"task_id": "abcd1234",
"result_url_path": "/unit_api/task_results/abcd1234",
"status": "accepted"
}

Reboot Unit​

Reboot one unit, or $broadcast.

Endpoint​

POST /api/units/{pioreactor_unit}/system/reboot

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.

Response​

Success​

Status: 201 Created

No success response body.

Repair Unit​

Repair filesystem permissions on one unit, or $broadcast.

Endpoint​

POST /api/units/{pioreactor_unit}/system/repair

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.

Response​

Success​

Status: 201 Created

No example body inferred.

Shutdown Unit​

Shut down one unit, or $broadcast.

Endpoint​

POST /api/units/{pioreactor_unit}/system/shutdown

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.

Response​

Success​

Status: 201 Created

No success response body.

Get Unit Utc Clock​

Get Unit Utc Clock endpoint.

Endpoint​

GET /api/units/{pioreactor_unit}/system/utc_clock

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.

Response​

Success​

Status: 202 Accepted

Example body:

{
"unit": "localhost",
"task_id": "5c7da9e5-395c-4b31-95da-295f3ce2dd63",
"result_url_path": "/unit_api/task_results/5c7da9e5-395c-4b31-95da-295f3ce2dd63",
"status": "accepted"
}

Get System Logs For Unit​

Shows system logs from specific unit uses pagination.

Endpoint​

GET /api/units/{pioreactor_unit}/system_logs

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.

Query Parameters​

NameTypeRequiredDescription
min_levelstringNomin level.

Response​

Success​

Status: 200 OK

Example body:

[
{
"timestamp": "2026-01-01T00:00:00Z",
"level": "INFO",
"message": "Log message.",
"task": "stirring",
"source": "app",
"pioreactor_unit": "pio01",
"experiment": "testing_experiment"
}
]

Get Usb Status On Machine​

Get Usb Status On Machine endpoint.

Endpoint​

GET /api/units/{pioreactor_unit}/usb

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.

Response​

Success​

Status: 202 Accepted

Example body:

{
"unit": "localhost",
"task_id": "48114953-967d-4ef5-ae1d-3b2eb7acb9c1",
"result_url_path": "/unit_api/task_results/48114953-967d-4ef5-ae1d-3b2eb7acb9c1",
"status": "accepted"
}

Get Usb Artifacts On Machine​

Get Usb Artifacts On Machine endpoint.

Endpoint​

GET /api/units/{pioreactor_unit}/usb/artifacts

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.

Response​

Success​

Status: 202 Accepted

Example body:

{
"unit": "localhost",
"task_id": "b9edf6a8-45c0-4348-83c2-eec6be8cfef2",
"result_url_path": "/unit_api/task_results/b9edf6a8-45c0-4348-83c2-eec6be8cfef2",
"status": "accepted"
}

Eject Usb On Machine​

Eject Usb On Machine endpoint.

Endpoint​

POST /api/units/{pioreactor_unit}/usb/eject

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.

Request Body​

NameTypeRequiredDescription
devicestringNodevice.
{
"device": "example_device"
}

Response​

Success​

Status: 202 Accepted

Example body:

{
"unit": "pio01",
"task_id": "abcd1234",
"result_url_path": "/unit_api/task_results/abcd1234",
"status": "accepted"
}

Mount Usb On Machine​

Mount Usb On Machine endpoint.

Endpoint​

POST /api/units/{pioreactor_unit}/usb/mount

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.

Request Body​

NameTypeRequiredDescription
devicestringNodevice.
{
"device": "example_device"
}

Response​

Success​

Status: 202 Accepted

Example body:

{
"unit": "pio01",
"task_id": "abcd1234",
"result_url_path": "/unit_api/task_results/abcd1234",
"status": "accepted"
}

Get App Versions​

Get App Versions endpoint.

Endpoint​

GET /api/units/{pioreactor_unit}/versions/app

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.

Response​

Success​

Status: 202 Accepted

Example body:

{
"unit": "localhost",
"task_id": "d3b290e6-7855-4998-a849-3cadfa57dbef",
"result_url_path": "/unit_api/task_results/d3b290e6-7855-4998-a849-3cadfa57dbef",
"status": "accepted"
}

Get Zipped Dot Pioreactor​

Download a ZIP of ~/.pioreactor from one or all workers.

Endpoint​

GET /api/units/{pioreactor_unit}/zipped_dot_pioreactor

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.

Response​

Success​

Status: 200 OK

Response body is binary file data.

Get List Of Workers​

Get List Of Workers endpoint.

Endpoint​

GET /api/workers

Response​

Success​

Status: 200 OK

Example body:

[
{
"pioreactor_unit": "localhost",
"added_at": "2025-10-03T14:12:44.444Z",
"is_active": 1,
"model_name": "pioreactor_40ml",
"model_version": "1.5",
"ipv4_address": null
}
]

Add Worker​

Register a worker without changing an existing worker on retry.

Endpoint​

PUT /api/workers

Request​

Request Body​

NameTypeRequiredDescription
pioreactor_unitstringYespioreactor unit.
model_namestringNomodel name.
model_versionstringNomodel version.
{
"pioreactor_unit": "pio02",
"model_name": "pioreactor_40ml",
"model_version": "1.5"
}

Response​

Success​

Status: 200 OK

Example body:

{
"status": "success"
}

Delete Worker​

Delete Worker endpoint.

Endpoint​

DELETE /api/workers/{pioreactor_unit}

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.

Response​

Success​

Status: 202 Accepted

Example body:

{
"status": "success"
}

Get Worker​

Get Worker endpoint.

Endpoint​

GET /api/workers/{pioreactor_unit}

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.

Response​

Success​

Status: 200 OK

Example body:

{
"pioreactor_unit": "localhost",
"added_at": "2025-10-03T14:12:44.444Z",
"is_active": 1,
"model_name": "pioreactor_40ml",
"model_version": "1.5"
}

Get All Active Calibrations​

Get All Active Calibrations endpoint.

Endpoint​

GET /api/workers/{pioreactor_unit}/active_calibrations

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.

Response​

Success​

Status: 202 Accepted

Example body:

{
"unit": "localhost",
"task_id": "23dd05e2-1fda-4c4a-ac8a-d8a1a6c3f6b6",
"result_url_path": "/unit_api/task_results/23dd05e2-1fda-4c4a-ac8a-d8a1a6c3f6b6",
"status": "accepted"
}

Remove Active Status Calibration​

Remove Active Status Calibration endpoint.

Endpoint​

DELETE /api/workers/{pioreactor_unit}/active_calibrations/{device}

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.
devicestringYesTarget device name.

Response​

Success​

Status: 202 Accepted

Example body:

{
"unit": "pio01",
"task_id": "abcd1234",
"result_url_path": "/unit_api/task_results/abcd1234",
"status": "accepted"
}

Set Active Calibration​

Set Active Calibration endpoint.

Endpoint​

PATCH /api/workers/{pioreactor_unit}/active_calibrations/{device}/{calibration_name}

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.
devicestringYesTarget device name.
calibration_namestringYesCalibration name.

Response​

Success​

Status: 202 Accepted

Example body:

{
"unit": "pio01",
"task_id": "abcd1234",
"result_url_path": "/unit_api/task_results/abcd1234",
"status": "accepted"
}

Get All Active Estimators​

Get All Active Estimators endpoint.

Endpoint​

GET /api/workers/{pioreactor_unit}/active_estimators

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.

Response​

Success​

Status: 202 Accepted

Example body:

{
"unit": "localhost",
"task_id": "5009497c-f57a-44c1-a490-a190314dc97d",
"result_url_path": "/unit_api/task_results/5009497c-f57a-44c1-a490-a190314dc97d",
"status": "accepted"
}

Remove Active Status Estimator​

Remove Active Status Estimator endpoint.

Endpoint​

DELETE /api/workers/{pioreactor_unit}/active_estimators/{device}

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.
devicestringYesTarget device name.

Response​

Success​

Status: 202 Accepted

Example body:

{
"unit": "pio01",
"task_id": "abcd1234",
"result_url_path": "/unit_api/task_results/abcd1234",
"status": "accepted"
}

Set Active Estimator​

Set Active Estimator endpoint.

Endpoint​

PATCH /api/workers/{pioreactor_unit}/active_estimators/{device}/{estimator_name}

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.
devicestringYesTarget device name.
estimator_namestringYesEstimator name.

Response​

Success​

Status: 202 Accepted

Example body:

{
"unit": "pio01",
"task_id": "abcd1234",
"result_url_path": "/unit_api/task_results/abcd1234",
"status": "accepted"
}

Get Automation Descriptors For Worker​

Proxy a request for automation UI descriptors to one worker.

Endpoint​

GET /api/workers/{pioreactor_unit}/automations/descriptors/{automation_type}

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.
automation_typestringYesAutomation type, for example dosing, temperature, or led.

Response​

Success​

Status: 200 OK

Example body:

[
{
"display_name": "Only record temperature",
"automation_name": "only_record_temperature",
"description": "Apply no heating, only record the temperature.",
"source": null,
"fields": []
},
{
"display_name": "Thermostat",
"automation_name": "thermostat",
"description": "Vary the amount of applied heating to keep the culture near a target temperature, using a control-loop.",
"source": null,
"fields": [
{
"key": "target_temperature",
"default": 30,
"label": "Target temperature",
"disabled": false,
"required": true,
"unit": "\u2103",
"type": "numeric",
"options": null
}
]
}
]

Update Bioreactor On Unit​

Update Bioreactor On Unit endpoint.

Endpoint​

PATCH /api/workers/{pioreactor_unit}/bioreactor/update/experiments/{experiment}

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.
experimentstringYesExperiment identifier.

Request Body​

NameTypeRequiredDescription
valuesobjectYesvalues.
{
"values": {
"current_volume_ml": 12.5
}
}

Response​

Success​

Status: 202 Accepted

Example body:

{
"unit": "pio01",
"task_id": "abcd1234",
"result_url_path": "/unit_api/task_results/abcd1234",
"status": "accepted"
}

Blink Worker​

Ask one worker's monitor job to blink its response LED.

Endpoint​

POST /api/workers/{pioreactor_unit}/blink

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.

Response​

Success​

Status: 202 Accepted

Example body:

{
"status": "accepted"
}

Get Calibration Protocols​

Get Calibration Protocols endpoint.

Endpoint​

GET /api/workers/{pioreactor_unit}/calibration_protocols

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.

Response​

Success​

Status: 202 Accepted

Example body:

{
"unit": "localhost",
"task_id": "86b6c527-2d8c-4642-a4ad-35524f4a8a60",
"result_url_path": "/unit_api/task_results/86b6c527-2d8c-4642-a4ad-35524f4a8a60",
"status": "accepted"
}

Get All Calibrations​

Get All Calibrations endpoint.

Endpoint​

GET /api/workers/{pioreactor_unit}/calibrations

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.

Response​

Success​

Status: 202 Accepted

Example body:

{
"unit": "localhost",
"task_id": "25425d9b-9331-422d-af3c-4e32a357611e",
"result_url_path": "/unit_api/task_results/25425d9b-9331-422d-af3c-4e32a357611e",
"status": "accepted"
}

Get Calibrations​

Get Calibrations endpoint.

Endpoint​

GET /api/workers/{pioreactor_unit}/calibrations/{device}

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.
devicestringYesTarget device name.

Response​

Success​

Status: 202 Accepted

Example body:

{
"unit": "localhost",
"task_id": "6b56752e-e72b-4b2f-9cb6-acf7176773ee",
"result_url_path": "/unit_api/task_results/6b56752e-e72b-4b2f-9cb6-acf7176773ee",
"status": "accepted"
}

Create Calibration​

Create a calibration on one worker, or $broadcast.

Endpoint​

POST /api/workers/{pioreactor_unit}/calibrations/{device}

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.
devicestringYesTarget device name.

Request Body​

NameTypeRequiredDescription
calibration_datastringYescalibration data.
set_as_activebooleanNoset as active.
{
"calibration_data": "calibration_type: simple_peristaltic_pump\ncalibration_name: example_calibration\n",
"set_as_active": true
}

Response​

Success​

Status: 202 Accepted

Example body:

{
"unit": "pio01",
"task_id": "abcd1234",
"result_url_path": "/unit_api/task_results/abcd1234",
"status": "accepted"
}

Delete Calibration​

Delete Calibration endpoint.

Endpoint​

DELETE /api/workers/{pioreactor_unit}/calibrations/{device}/{calibration_name}

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.
devicestringYesTarget device name.
calibration_namestringYesCalibration name.

Response​

Success​

Status: 202 Accepted

Example body:

{
"unit": "pio01",
"task_id": "abcd1234",
"result_url_path": "/unit_api/task_results/abcd1234",
"status": "accepted"
}

Get Calibration​

Get Calibration endpoint.

Endpoint​

GET /api/workers/{pioreactor_unit}/calibrations/{device}/{calibration_name}

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.
devicestringYesTarget device name.
calibration_namestringYesCalibration name.

Response​

Success​

Status: 202 Accepted

Example body:

{
"unit": "localhost",
"task_id": "021f40dd-1df1-4073-8908-3d81f277387b",
"result_url_path": "/unit_api/task_results/021f40dd-1df1-4073-8908-3d81f277387b",
"status": "accepted"
}

Start Calibration Session​

Start a browser-driven calibration session on one worker.

Endpoint​

POST /api/workers/{pioreactor_unit}/calibrations/sessions

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.

Request Body​

NameTypeRequiredDescription
protocol_namestringYesprotocol name.
target_devicestringYestarget device.
{
"protocol_name": "example_protocol_name",
"target_device": "example_target_device"
}

Response​

Success​

Status: 201 Created

No success response body.

Get Calibration Session​

Get Calibration Session endpoint.

Endpoint​

GET /api/workers/{pioreactor_unit}/calibrations/sessions/{session_id}

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.
session_idstringYesCalibration session identifier.

Response​

Success​

Status: 200 OK

No success response body.

Abort Calibration Session​

Abort a calibration session on one worker.

Endpoint​

POST /api/workers/{pioreactor_unit}/calibrations/sessions/{session_id}/abort

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.
session_idstringYesCalibration session identifier.

Response​

Success​

Status: 201 Created

No success response body.

Advance Calibration Session​

Submit inputs for the current step of a calibration session.

Endpoint​

POST /api/workers/{pioreactor_unit}/calibrations/sessions/{session_id}/inputs

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.
session_idstringYesCalibration session identifier.

Request Body​

NameTypeRequiredDescription
inputsobjectNoinputs.
{
"inputs": {}
}

Response​

Success​

Status: 201 Created

No success response body.

Get Camera Status For Worker​

Get Camera Status For Worker endpoint.

Endpoint​

GET /api/workers/{pioreactor_unit}/camera/experiments/{experiment}/status

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.
experimentstringYesExperiment identifier.

Response​

Success​

Status: 200 OK

Example body:

{
"unit": "localhost",
"detection_status": "detected",
"runtime_available": true,
"capture_command": null,
"mock": true,
"latest_still": {
"experiment": "demo",
"captured_at": "2026-08-18T15:54:17.433333Z",
"image_id": "20260818T155417.433333Z-a5d9d6ba",
"capture_reason": "scheduled"
},
"auto_capture_enabled": true,
"snapshot_interval_minutes": 5
}

List Camera Stills For Worker Experiment​

List Camera Stills For Worker Experiment endpoint.

Endpoint​

GET /api/workers/{pioreactor_unit}/camera/experiments/{experiment}/stills

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.
experimentstringYesExperiment identifier.

Response​

Success​

Status: 200 OK

Example body:

{
"unit": "localhost",
"experiment": "demo",
"stills": [
{
"experiment": "demo",
"captured_at": "2026-08-18T15:54:17.433333Z",
"image_id": "20260818T155417.433333Z-a5d9d6ba",
"capture_reason": "scheduled"
}
]
}

Capture Camera Still For Worker Experiment​

Capture Camera Still For Worker Experiment endpoint.

Endpoint​

POST /api/workers/{pioreactor_unit}/camera/experiments/{experiment}/stills

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.
experimentstringYesExperiment identifier.

Response​

Success​

Status: 202 Accepted

Example body:

{
"unit": "pio01",
"task_id": "abcd1234",
"result_url_path": "/unit_api/task_results/abcd1234",
"status": "accepted"
}

Get Zipped Camera Stills For Worker Experiment​

Get Zipped Camera Stills For Worker Experiment endpoint.

Endpoint​

GET /api/workers/{pioreactor_unit}/camera/experiments/{experiment}/stills.zip

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.
experimentstringYesExperiment identifier.

Response​

Success​

Status: 200 OK

Response body is binary file data.

Delete Camera Still For Worker Experiment​

Delete Camera Still For Worker Experiment endpoint.

Endpoint​

DELETE /api/workers/{pioreactor_unit}/camera/experiments/{experiment}/stills/{image_id}.jpg

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.
experimentstringYesExperiment identifier.
image_idstringYesimage id.

Response​

Success​

Status: 200 OK

No example body inferred.

Get Camera Still For Worker Experiment​

Get Camera Still For Worker Experiment endpoint.

Endpoint​

GET /api/workers/{pioreactor_unit}/camera/experiments/{experiment}/stills/{image_id}.jpg

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.
experimentstringYesExperiment identifier.
image_idstringYesimage id.

Response​

Success​

Status: 200 OK

No example body inferred.

Rename Camera Still For Worker Experiment​

Rename a stored photo without changing its experiment, capture time, or capture reason. The name becomes its image identifier and JPEG filename.

Endpoint​

PATCH /api/workers/{pioreactor_unit}/camera/experiments/{experiment}/stills/{image_id}.jpg

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesOne worker name; $broadcast is not supported.
experimentstringYesExperiment identifier.
image_idstringYesCurrent image identifier, without the .jpg extension.

JSON Body​

{
"new_image_id": "culture-before-dosing"
}

new_image_id is required. Use only ASCII letters, digits, dots, dashes, and underscores, without spaces or a .jpg extension. The name must not already belong to another stored image on that Pioreactor, including images from other experiments.

Response​

Status: 200 OK. Returns the updated image metadata:

{
"experiment": "my experiment",
"captured_at": "2026-09-09T12:00:00Z",
"image_id": "culture-before-dosing",
"capture_reason": "manual"
}

Use the new identifier for subsequent image requests. Invalid names return 400 Bad Request, missing images return 404 Not Found, and name conflicts return 409 Conflict.

Get Camera Focus Preview For Worker​

Get Camera Focus Preview For Worker endpoint.

Endpoint​

GET /api/workers/{pioreactor_unit}/camera/focus_sessions/{session_id}/preview.jpg

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.
session_idstringYesCalibration session identifier.

Response​

Success​

Status: 200 OK

No example body inferred.

Update Camera Settings For Worker​

Update Camera Settings For Worker endpoint.

Endpoint​

PATCH /api/workers/{pioreactor_unit}/camera/settings

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.

Request Body​

NameTypeRequiredDescription
auto_capture_enabledbooleanYesauto capture enabled.
{
"auto_capture_enabled": true
}

Response​

Success​

Status: 202 Accepted

Example body:

{
"unit": "pio01",
"task_id": "abcd1234",
"result_url_path": "/unit_api/task_results/abcd1234",
"status": "accepted"
}

Get Capabilities​

Get Capabilities endpoint.

Endpoint​

GET /api/workers/{pioreactor_unit}/capabilities

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.

Response​

Success​

Status: 202 Accepted

Example body:

{
"unit": "localhost",
"task_id": "854085b1-9281-4dd3-b6b4-c8b164cd0f58",
"result_url_path": "/unit_api/task_results/854085b1-9281-4dd3-b6b4-c8b164cd0f58",
"status": "accepted"
}

Get All Estimators​

Get All Estimators endpoint.

Endpoint​

GET /api/workers/{pioreactor_unit}/estimators

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.

Response​

Success​

Status: 202 Accepted

Example body:

{
"unit": "localhost",
"task_id": "d548b4f9-4c77-41a9-b932-5f683e5fe975",
"result_url_path": "/unit_api/task_results/d548b4f9-4c77-41a9-b932-5f683e5fe975",
"status": "accepted"
}

Get Estimators By Device​

Get Estimators By Device endpoint.

Endpoint​

GET /api/workers/{pioreactor_unit}/estimators/{device}

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.
devicestringYesTarget device name.

Response​

Success​

Status: 202 Accepted

Example body:

{
"unit": "localhost",
"task_id": "f5cef2be-fdc9-4056-b206-efbbc3279a91",
"result_url_path": "/unit_api/task_results/f5cef2be-fdc9-4056-b206-efbbc3279a91",
"status": "accepted"
}

Delete Estimator​

Delete Estimator endpoint.

Endpoint​

DELETE /api/workers/{pioreactor_unit}/estimators/{device}/{estimator_name}

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.
devicestringYesTarget device name.
estimator_namestringYesEstimator name.

Response​

Success​

Status: 202 Accepted

Example body:

{
"unit": "pio01",
"task_id": "abcd1234",
"result_url_path": "/unit_api/task_results/abcd1234",
"status": "accepted"
}

Get Estimator​

Get Estimator endpoint.

Endpoint​

GET /api/workers/{pioreactor_unit}/estimators/{device}/{estimator_name}

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.
devicestringYesTarget device name.
estimator_namestringYesEstimator name.

Response​

Success​

Status: 202 Accepted

Example body:

{
"unit": "localhost",
"task_id": "5d98f40c-fa53-4b99-aed1-2a1ad2cb2a08",
"result_url_path": "/unit_api/task_results/5d98f40c-fa53-4b99-aed1-2a1ad2cb2a08",
"status": "accepted"
}

Get Experiment Assignment For Worker​

Get Experiment Assignment For Worker endpoint.

Endpoint​

GET /api/workers/{pioreactor_unit}/experiment

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.

Response​

Success​

Status: 200 OK

Example body:

{
"pioreactor_unit": "localhost",
"is_active": 1,
"experiment": "ALE - Acetate",
"model_name": "pioreactor_40ml",
"model_version": "1.5"
}

Get Logs For Unit And Experiment​

Shows event logs from specific unit and experiment, uses pagination.

Endpoint​

GET /api/workers/{pioreactor_unit}/experiments/{experiment}/logs

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.
experimentstringYesExperiment identifier.

Query Parameters​

NameTypeRequiredDescription
min_levelstringNomin level.

Response​

Success​

Status: 200 OK

Example body:

[
{
"timestamp": "2026-01-01T00:00:00Z",
"level": "INFO",
"message": "Log message.",
"task": "stirring",
"source": "app",
"pioreactor_unit": "pio01",
"experiment": "testing_experiment"
}
]

Publish New Log​

Publish a log message into an experiment log stream.

Endpoint​

POST /api/workers/{pioreactor_unit}/experiments/{experiment}/logs

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.
experimentstringYesExperiment identifier.

Request Body​

NameTypeRequiredDescription
levelstringYeslevel.
messagestringYesmessage.
sourcestringYessource.
timestampstringYestimestamp.
source_stringNosource .
taskstringNotask.
{
"level": "INFO",
"message": "Log message.",
"source": "api",
"timestamp": "2026-01-01T00:00:00Z",
"source_": "api",
"task": "stirring"
}

Response​

Success​

Status: 202 Accepted

Example body:

{
"status": "accepted"
}

Get Recent Logs For Unit And Experiment​

Shows event logs for a specific unit within an experiment. This is for the single-page Pioreactor ui

Endpoint​

GET /api/workers/{pioreactor_unit}/experiments/{experiment}/recent_logs

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.
experimentstringYesExperiment identifier.

Query Parameters​

NameTypeRequiredDescription
min_levelstringNomin level.

Response​

Success​

Status: 200 OK

Example body:

[
{
"timestamp": "2026-01-01T00:00:00Z",
"level": "INFO",
"message": "Log message.",
"task": "stirring",
"source": "app",
"pioreactor_unit": "pio01",
"experiment": "testing_experiment"
}
]

Get Fallback Time Series Per Unit​

Get Fallback Time Series Per Unit endpoint.

Endpoint​

GET /api/workers/{pioreactor_unit}/experiments/{experiment}/time_series/{data_source}/{column}

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.
experimentstringYesExperiment identifier.
data_sourcestringYesTime-series data source name.
columnstringYesDataset column name.

Response​

Success​

Status: 200 OK

Body shape: series is a list of series labels. data is a parallel list of point arrays, so data[i] contains the points for series[i]. Each point has x as an ISO-8601 UTC timestamp string and y as a number.

Example body:

{
"series": [
"pio01",
"pio02"
],
"data": [
[
{
"x": "2026-01-01T00:00:00.000Z",
"y": 0.01234
},
{
"x": "2026-01-01T00:01:00.000Z",
"y": 0.0125
}
],
[
{
"x": "2026-01-01T00:00:00.000Z",
"y": 0.00987
},
{
"x": "2026-01-01T00:01:00.000Z",
"y": 0.01001
}
]
]
}

Get Growth Rates Per Unit​

Get Growth Rates Per Unit endpoint.

Endpoint​

GET /api/workers/{pioreactor_unit}/experiments/{experiment}/time_series/growth_rates

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.
experimentstringYesExperiment identifier.

Response​

Success​

Status: 200 OK

Body shape: series is a list of series labels. data is a parallel list of point arrays, so data[i] contains the points for series[i]. Each point has x as an ISO-8601 UTC timestamp string and y as a number.

Example body:

{
"series": [
"pio01",
"pio02"
],
"data": [
[
{
"x": "2026-01-01T00:00:00.000Z",
"y": 0.01234
},
{
"x": "2026-01-01T00:01:00.000Z",
"y": 0.0125
}
],
[
{
"x": "2026-01-01T00:00:00.000Z",
"y": 0.00987
},
{
"x": "2026-01-01T00:01:00.000Z",
"y": 0.01001
}
]
]
}

Get Od Readings Per Unit​

Get Od Readings Per Unit endpoint.

Endpoint​

GET /api/workers/{pioreactor_unit}/experiments/{experiment}/time_series/od_readings

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.
experimentstringYesExperiment identifier.

Response​

Success​

Status: 200 OK

Body shape: series is a list of series labels. data is a parallel list of point arrays, so data[i] contains the points for series[i]. Each point has x as an ISO-8601 UTC timestamp string and y as a number.

Example body:

{
"series": [
"pio01",
"pio02"
],
"data": [
[
{
"x": "2026-01-01T00:00:00.000Z",
"y": 0.01234
},
{
"x": "2026-01-01T00:01:00.000Z",
"y": 0.0125
}
],
[
{
"x": "2026-01-01T00:00:00.000Z",
"y": 0.00987
},
{
"x": "2026-01-01T00:01:00.000Z",
"y": 0.01001
}
]
]
}

Get Od Readings Filtered Per Unit​

Get Od Readings Filtered Per Unit endpoint.

Endpoint​

GET /api/workers/{pioreactor_unit}/experiments/{experiment}/time_series/od_readings_filtered

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.
experimentstringYesExperiment identifier.

Response​

Success​

Status: 200 OK

Body shape: series is a list of series labels. data is a parallel list of point arrays, so data[i] contains the points for series[i]. Each point has x as an ISO-8601 UTC timestamp string and y as a number.

Example body:

{
"series": [
"pio01",
"pio02"
],
"data": [
[
{
"x": "2026-01-01T00:00:00.000Z",
"y": 0.01234
},
{
"x": "2026-01-01T00:01:00.000Z",
"y": 0.0125
}
],
[
{
"x": "2026-01-01T00:00:00.000Z",
"y": 0.00987
},
{
"x": "2026-01-01T00:01:00.000Z",
"y": 0.01001
}
]
]
}

Get Od Readings Fused Per Unit​

Get Od Readings Fused Per Unit endpoint.

Endpoint​

GET /api/workers/{pioreactor_unit}/experiments/{experiment}/time_series/od_readings_fused

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.
experimentstringYesExperiment identifier.

Response​

Success​

Status: 200 OK

Body shape: series is a list of series labels. data is a parallel list of point arrays, so data[i] contains the points for series[i]. Each point has x as an ISO-8601 UTC timestamp string and y as a number.

Example body:

{
"series": [
"pio01",
"pio02"
],
"data": [
[
{
"x": "2026-01-01T00:00:00.000Z",
"y": 0.01234
},
{
"x": "2026-01-01T00:01:00.000Z",
"y": 0.0125
}
],
[
{
"x": "2026-01-01T00:00:00.000Z",
"y": 0.00987
},
{
"x": "2026-01-01T00:01:00.000Z",
"y": 0.01001
}
]
]
}

Get Od Raw Readings Per Unit​

Get Od Raw Readings Per Unit endpoint.

Endpoint​

GET /api/workers/{pioreactor_unit}/experiments/{experiment}/time_series/raw_od_readings

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.
experimentstringYesExperiment identifier.

Response​

Success​

Status: 200 OK

Body shape: series is a list of series labels. data is a parallel list of point arrays, so data[i] contains the points for series[i]. Each point has x as an ISO-8601 UTC timestamp string and y as a number.

Example body:

{
"series": [
"pio01",
"pio02"
],
"data": [
[
{
"x": "2026-01-01T00:00:00.000Z",
"y": 0.01234
},
{
"x": "2026-01-01T00:01:00.000Z",
"y": 0.0125
}
],
[
{
"x": "2026-01-01T00:00:00.000Z",
"y": 0.00987
},
{
"x": "2026-01-01T00:01:00.000Z",
"y": 0.01001
}
]
]
}

Get Temperature Readings Per Unit​

Get Temperature Readings Per Unit endpoint.

Endpoint​

GET /api/workers/{pioreactor_unit}/experiments/{experiment}/time_series/temperature_readings

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.
experimentstringYesExperiment identifier.

Response​

Success​

Status: 200 OK

Body shape: series is a list of series labels. data is a parallel list of point arrays, so data[i] contains the points for series[i]. Each point has x as an ISO-8601 UTC timestamp string and y as a number.

Example body:

{
"series": [
"pio01",
"pio02"
],
"data": [
[
{
"x": "2026-01-01T00:00:00.000Z",
"y": 0.01234
},
{
"x": "2026-01-01T00:01:00.000Z",
"y": 0.0125
}
],
[
{
"x": "2026-01-01T00:00:00.000Z",
"y": 0.00987
},
{
"x": "2026-01-01T00:01:00.000Z",
"y": 0.01001
}
]
]
}

Change Worker Status​

Change Worker Status endpoint.

Endpoint​

PUT /api/workers/{pioreactor_unit}/is_active

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.

Request Body​

NameTypeRequiredDescription
is_activeintegerYesis active.
{
"is_active": true
}

Response​

Success​

Status: 200 OK

Example body:

{
"status": "success"
}

Get Job Descriptors For Worker​

Proxy a request for background-job UI descriptors to one worker.

Endpoint​

GET /api/workers/{pioreactor_unit}/jobs/descriptors

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.

Response​

Success​

Status: 200 OK

Example body:

[
{
"display_name": "Stirring",
"job_name": "stirring",
"display": true,
"published_settings": [
{
"key": "target_rpm",
"type": "numeric",
"display": true,
"description": "Modify the target RPM of stirring. This will effect the optical density reading. Too low and the stirring may completely stop. Too high and the resulting vortex may interfere with the optics.",
"default": null,
"unit": "RPM",
"label": "Target stir RPM",
"editable": true,
"min": null,
"max": null
}
],
"source": "app",
"description": "Start the stirring on the Pioreactor. Stirring is needed for mixing and proper OD measurements.",
"subtext": null,
"is_testing": false
},
{
"display_name": "Optical density",
"job_name": "od_reading",
"display": true,
"published_settings": [],
"source": "app",
"description": "Collect optical density measurements of the culture over time.",
"subtext": null,
"is_testing": false
},
{
"display_name": "Growth rate",
"job_name": "growth_rate_calculating",
"display": true,
"published_settings": [],
"source": "app",
"description": "Transform optical density measurements into culture growth rate measurements. Start this after innoculation. Begins by sampling for a few minutes to gather a baseline.",
"subtext": null,
"is_testing": false
}
]

Run Job On Unit In Experiment​

Runs specified job on unit.

Endpoint​

PATCH /api/workers/{pioreactor_unit}/jobs/run/job_name/{job_name}/experiments/{experiment}

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.
job_namestringYesJob name.
experimentstringYesExperiment identifier.

Request Body​

NameTypeRequiredDescription
argsarrayNoargs.
config_overridesarrayNoconfig overrides.
envobjectNoenv.
optionsobjectNooptions.
{
"options": {
"target_rpm": "200"
},
"env": {
"JOB_SOURCE": "api"
},
"args": [
"some-flag"
],
"config_overrides": [
[
"stirring.config",
"pwm_hz",
"100"
]
]
}

Response​

Success​

Status: 202 Accepted

Example body:

{
"unit": "pio01",
"task_id": "abcd1234",
"result_url_path": "/unit_api/task_results/abcd1234",
"status": "accepted"
}

Run Job On Unit In Experiment​

Runs specified job on unit.

Endpoint​

POST /api/workers/{pioreactor_unit}/jobs/run/job_name/{job_name}/experiments/{experiment}

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.
job_namestringYesJob name.
experimentstringYesExperiment identifier.

Request Body​

NameTypeRequiredDescription
argsarrayNoargs.
config_overridesarrayNoconfig overrides.
envobjectNoenv.
optionsobjectNooptions.
{
"options": {
"target_rpm": "200"
},
"env": {
"JOB_SOURCE": "api"
},
"args": [
"some-flag"
],
"config_overrides": [
[
"stirring.config",
"pwm_hz",
"100"
]
]
}

Response​

Success​

Status: 202 Accepted

Example body:

{
"unit": "pio01",
"task_id": "abcd1234",
"result_url_path": "/unit_api/task_results/abcd1234",
"status": "accepted"
}

Get Jobs Running​

Get Jobs Running endpoint.

Endpoint​

GET /api/workers/{pioreactor_unit}/jobs/running

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.

Response​

Success​

Status: 202 Accepted

Example body:

{
"unit": "localhost",
"task_id": "d4eaeb59-9054-40bd-924d-97dc64e0e27f",
"result_url_path": "/unit_api/task_results/d4eaeb59-9054-40bd-924d-97dc64e0e27f",
"status": "accepted"
}

Get Job Settings For Worker​

Get Job Settings For Worker endpoint.

Endpoint​

GET /api/workers/{pioreactor_unit}/jobs/settings/job_name/{job_name}/experiments/{experiment}

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.
job_namestringYesJob name.
experimentstringYesExperiment identifier.

Response​

Success​

Status: 202 Accepted

Example body:

{
"unit": "pio01",
"task_id": "abcd1234",
"result_url_path": "/unit_api/task_results/abcd1234",
"status": "accepted"
}

Get Job Setting For Worker​

Get Job Setting For Worker endpoint.

Endpoint​

GET /api/workers/{pioreactor_unit}/jobs/settings/job_name/{job_name}/setting/{setting}/experiments/{experiment}

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.
job_namestringYesJob name.
settingstringYesJob setting name.
experimentstringYesExperiment identifier.

Response​

Success​

Status: 202 Accepted

Example body:

{
"unit": "pio01",
"task_id": "abcd1234",
"result_url_path": "/unit_api/task_results/abcd1234",
"status": "accepted"
}

Stop All Jobs On Unit For Experiment​

Stop all jobs for one unit, or $broadcast, in one experiment.

Endpoint​

PATCH /api/workers/{pioreactor_unit}/jobs/stop/experiments/{experiment}

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.
experimentstringYesExperiment identifier.

Response​

Success​

Status: 202 Accepted

Example body:

{
"status": "success"
}

Stop All Jobs On Unit For Experiment​

Stop all jobs for one unit, or $broadcast, in one experiment.

Endpoint​

POST /api/workers/{pioreactor_unit}/jobs/stop/experiments/{experiment}

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.
experimentstringYesExperiment identifier.

Response​

Success​

Status: 202 Accepted

Example body:

{
"status": "success"
}

Stop Specific Job On Unit​

Stop one job on one unit in one experiment.

Endpoint​

PATCH /api/workers/{pioreactor_unit}/jobs/stop/job_name/{job_name}/experiments/{experiment}

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.
job_namestringYesJob name.
experimentstringYesExperiment identifier.

Response​

Success​

Status: 202 Accepted

Example body:

{
"unit": "pio01",
"task_id": "abcd1234",
"result_url_path": "/unit_api/task_results/abcd1234",
"status": "accepted"
}

Stop Specific Job On Unit​

Stop one job on one unit in one experiment.

Endpoint​

POST /api/workers/{pioreactor_unit}/jobs/stop/job_name/{job_name}/experiments/{experiment}

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.
job_namestringYesJob name.
experimentstringYesExperiment identifier.

Response​

Success​

Status: 202 Accepted

Example body:

{
"unit": "pio01",
"task_id": "abcd1234",
"result_url_path": "/unit_api/task_results/abcd1234",
"status": "accepted"
}

Update Job On Unit​

Update specified job on unit. Use $broadcast for everyone.

Endpoint​

PATCH /api/workers/{pioreactor_unit}/jobs/update/job_name/{job_name}/experiments/{experiment}

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.
job_namestringYesJob name.
experimentstringYesExperiment identifier.

Request Body​

NameTypeRequiredDescription
settingsobjectYessettings.
{
"settings": {
"target_rpm": "200"
}
}

Response​

Success​

Status: 202 Accepted

Example body:

{
"status": "accepted"
}

Get Worker Model And Metadata​

Get Worker Model And Metadata endpoint.

Endpoint​

GET /api/workers/{pioreactor_unit}/model

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.

Response​

Success​

Status: 200 OK

Example body:

{
"pioreactor_unit": "localhost",
"model_name": "pioreactor_40ml",
"model_version": "1.5",
"display_name": "Pioreactor 40ml, v1.5",
"reactor_capacity_ml": 40.0,
"reactor_diameter_mm": 27.0,
"reactor_max_fill_volume_ml": 36.0,
"max_temp_to_reduce_heating": 78.0,
"max_temp_to_disable_heating": 80.0,
"max_temp_to_shutdown": 85.0,
"is_legacy": false,
"is_contrib": false
}

Change Worker Model​

Change Worker Model endpoint.

Endpoint​

PUT /api/workers/{pioreactor_unit}/model

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.

Request Body​

NameTypeRequiredDescription
model_namestringYesmodel name.
model_versionstringYesmodel version.
{
"model_name": "pioreactor_40ml",
"model_version": "1.5"
}

Response​

Success​

Status: 200 OK

Example body:

{
"status": "success"
}

Get Settings Descriptors For Worker​

Proxy a request for settings UI descriptors to one worker.

Endpoint​

GET /api/workers/{pioreactor_unit}/settings/descriptors

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.

Response​

Success​

Status: 200 OK

Example body:

[
{
"key": "bioreactor",
"display_name": "Bioreactor",
"display": true,
"published_settings": [
{
"key": "current_volume_ml",
"type": "numeric",
"display": true,
"description": "Current estimated liquid volume in the vial.",
"default": 14.0,
"unit": "mL",
"label": "Current volume",
"editable": true,
"min": 0.0,
"max": null
},
{
"key": "efflux_tube_volume_ml",
"type": "numeric",
"display": true,
"description": "Liquid volume equivalent to the height of the waste/efflux tube.",
"default": 14.0,
"unit": "mL",
"label": "Efflux tube level",
"editable": true,
"min": 0.0,
"max": null
},
{
"key": "alt_media_fraction",
"type": "numeric",
"display": true,
"description": "Fraction of the current volume estimated to be alt media.",
"default": 0.0,
"unit": null,
"label": "Alt media fraction",
"editable": true,
"min": 0.0,
"max": 1.0
}
],
"source": "app",
"description": "Per-unit bioreactor settings.",
"subtext": null
},
{
"key": "leds",
"display_name": "led intensity",
"display": false,
"published_settings": [
{
"key": "intensity",
"type": "string",
"display": true,
"description": null,
"default": null,
"unit": null,
"label": "LED intensity",
"editable": false,
"min": null,
"max": null
}
],
"source": "app",
"description": null,
"subtext": null
},
{
"key": "pwms",
"display_name": "PWMs",
"display": false,
"published_settings": [
{
"key": "dc",
"type": "string",
"display": true,
"description": null,
"default": null,
"unit": null,
"label": "PWM intensity",
"editable": false,
"min": null,
"max": null
}
],
"source": "app",
"description": null,
"subtext": null
}
]

Get Task Result For Worker​

Get Task Result For Worker endpoint.

Endpoint​

GET /api/workers/{pioreactor_unit}/task_results/{task_id}

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.
task_idstringYesTask identifier.

Response​

Success​

Status: 202 Accepted

Example body:

{
"task_id": "task-id",
"result_url_path": "/unit_api/task_results/task-id",
"status": "pending"
}

Get Zipped Calibrations​

Get Zipped Calibrations endpoint.

Endpoint​

GET /api/workers/{pioreactor_unit}/zipped_calibrations

Request​

Path Parameters​

NameTypeRequiredDescription
pioreactor_unitstringYesUnit name or $broadcast where supported.

Response​

Success​

Status: 200 OK

Response body is binary file data.

Remove All Workers From All Experiments​

Remove All Workers From All Experiments endpoint.

Endpoint​

DELETE /api/workers/assignments

Response​

Success​

Status: 202 Accepted

Example body:

{
"unit": "pio01",
"task_id": "abcd1234",
"result_url_path": "/unit_api/task_results/abcd1234",
"status": "accepted"
}

Get Workers And Experiment Assignments​

Get Workers And Experiment Assignments endpoint.

Endpoint​

GET /api/workers/assignments

Response​

Success​

Status: 200 OK

Example body:

[
{
"pioreactor_unit": "localhost",
"experiment": "ALE - Acetate",
"is_active": 1
}
]

Discover Available Workers​

Discover available pioreactor workers on the network not already registered.

Endpoint​

GET /api/workers/discover

Response​

Success​

Status: 200 OK

Example body:

[]

Setup Worker Pioreactor​

Provision and register a newly discovered worker.

Endpoint​

POST /api/workers/setup

Request​

Request Body​

NameTypeRequiredDescription
modelstringYesmodel.
namestringYesname.
versionstringYesversion.
ipv4_addressstringNoipv4 address.
{
"model": "example_model",
"name": "testing_experiment",
"version": "example_version",
"ipv4_address": "example_ipv4_address"
}

Response​

Success​

Status: 200 OK

Example body:

{
"msg": "Worker pio02 added successfully."
}