{"openapi":"3.1.0","info":{"title":"FastAPI","version":"0.1.0"},"servers":[{"url":"https://api.ionworks.com","description":"Production"}],"paths":{"/metrics":{"get":{"summary":"Metrics","description":"Endpoint that serves Prometheus metrics.","operationId":"metrics_metrics_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"x-hidden":true}},"/agent/sessions":{"get":{"summary":"List Sessions","description":"List the current user's chat sessions for a project (newest first).","operationId":"list_sessions_agent_sessions_get","parameters":[{"name":"project_id","in":"query","required":true,"schema":{"type":"string","title":"Project Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AgentSession"},"title":"Response List Sessions Agent Sessions Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true},"post":{"summary":"Create Session","description":"Create a new chat session for a project.","operationId":"create_session_agent_sessions_post","parameters":[{"name":"project_id","in":"query","required":true,"schema":{"type":"string","title":"Project Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSessionRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentSession"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/agent/sessions/{session_id}":{"patch":{"summary":"Update Session","description":"Update a chat session (rename and/or persist the SDK session id).","operationId":"update_session_agent_sessions__session_id__patch","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","title":"Session Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSessionRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentSession"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true},"delete":{"summary":"Delete Session","description":"Delete a chat session and its messages.","operationId":"delete_session_agent_sessions__session_id__delete","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","title":"Session Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Delete Session Agent Sessions  Session Id  Delete"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/agent/sessions/{session_id}/messages":{"get":{"summary":"List Messages","description":"List a session's messages in chronological order.","operationId":"list_messages_agent_sessions__session_id__messages_get","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","title":"Session Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AgentMessage"},"title":"Response List Messages Agent Sessions  Session Id  Messages Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true},"post":{"summary":"Add Message","description":"Persist one rendered message (user text or assistant parts) to a session.","operationId":"add_message_agent_sessions__session_id__messages_post","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","title":"Session Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddMessageRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentMessage"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/agent/skills":{"get":{"summary":"Get Skills Bundle Info","description":"Describe the toolkit without transferring it.\n\nLets the download UI show which version it is offering without pulling the\nwhole archive on page load.","operationId":"get_skills_bundle_info_agent_skills_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillsBundleInfo"}}}}},"x-hidden":true}},"/agent/skills.zip":{"get":{"summary":"Download Skills Bundle","description":"Download the Ionworks Agentic Toolkit as a zip archive.\n\nAuthenticated so the toolkit stays behind login, matching the private\nmirror it is built from. The archive unzips to a single\n``ionworks-skills/`` directory that works as a local install source for\nevery agent listed in the toolkit README.","operationId":"download_skills_bundle_agent_skills_zip_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"x-hidden":true}},"/cell_specifications/{cell_spec_id}/cell_instances":{"post":{"tags":["Cell Specifications","Cell Instances"],"summary":"Create a new cell instance for a cell specification","description":"Creates a new cell instance under the specified cell specification (by ID).\nReturns the created cell instance and sets the Location header.","operationId":"create_cell_instance_cell_specifications__cell_spec_id__cell_instances_post","parameters":[{"name":"cell_spec_id","in":"path","required":true,"schema":{"type":"string","title":"Cell Spec Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Raw Data"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CellInstance"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false},"get":{"tags":["Cell Specifications","Cell Instances"],"summary":"List cell instances for a cell specification","description":"List cell instances for a specification with pagination and filtering.\n\nFilter parameters support Supabase filter operators:\n- Text fields (name, created_by_email): Use ``ilike.%value%`` for partial\n  match\n- Date fields: Use ``gte.value``, ``lte.value``, etc.\n- Date range: Use created_at_gt and created_at_lt for between queries","operationId":"list_cell_instances_cell_specifications__cell_spec_id__cell_instances_get","parameters":[{"name":"cell_spec_id","in":"path","required":true,"schema":{"type":"string","title":"Cell Spec Id"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":1000,"minimum":1,"default":1000,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Free-text search on instance name plus prefix full-text match, matching the global search. Composes with the column filters.","title":"Q"},"description":"Free-text search on instance name plus prefix full-text match, matching the global search. Composes with the column filters."},{"name":"name","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"}},{"name":"created_by_email","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created By Email"}},{"name":"created_at","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At"}},{"name":"created_at_gt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At Gt"}},{"name":"created_at_lt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At Lt"}},{"name":"updated_at","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated At"}},{"name":"updated_at_gt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated At Gt"}},{"name":"updated_at_lt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated At Lt"}},{"name":"order_by","in":"query","required":false,"schema":{"enum":["name","created_at","updated_at"],"type":"string","default":"created_at","title":"Order By"}},{"name":"order","in":"query","required":false,"schema":{"enum":["asc","desc"],"type":"string","default":"desc","title":"Order"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/cell_specifications":{"post":{"tags":["Cell Specifications"],"summary":"Create a new cell specification with nested component/material data","description":"Create a new cell specification with nested component and material data.\n\nMaterials and components are automatically upserted based on uniqueness:\n- Materials: unique on (organization_id, name, manufacturer)\n- Components: unique on (organization_id, component_type, material_id, properties)\n\nExample request body:\n```json\n{\n    \"name\": \"NCM622/Graphite Coin Cell\",\n    \"capacity\": 0.002,\n    \"lower_voltage_cutoff\": 2.5,\n    \"upper_voltage_cutoff\": 4.2,\n    \"form_factor\": \"R2032\",\n    \"anode\": {\n        \"properties\": {\"diameter_mm\": 15, \"thickness_um\": 23},\n        \"material\": {\"name\": \"Graphite\", \"manufacturer\": \"Customcells\"}\n    },\n    \"cathode\": {\n        \"properties\": {\"diameter_mm\": 14, \"thickness_um\": 22},\n        \"material\": {\n            \"name\": \"NCM622\",\n            \"definition\": {\"formula\": \"LiNi0.6Co0.2Mn0.2O2\"}\n        }\n    }\n}\n```","operationId":"create_cell_specification_cell_specifications_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCellSpecificationNested"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CellSpecificationWithComponents"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false},"get":{"tags":["Cell Specifications"],"summary":"List cell specifications for the current organization","description":"List cell specifications with pagination and optional filtering.\n\nWith ``project_id``, only specs linked to that project; without it, every\nspec in the organization.\n\nMaterial reverse-lookup: ``material_id``/``material_ids`` search all slots, a\nper-slot ``<slot>_material_id`` only that slot, and ``exclude_cell_spec_id``\ndrops one spec. These take precedence over the text/date filters, which use\nSupabase operators (``ilike.%value%``, ``gte.value``); ``created_at_gt``/\n``_lt`` bound a range. ``q`` is the search box's free-text param.","operationId":"list_cell_specifications_cell_specifications_get","parameters":[{"name":"full","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Full"}},{"name":"project_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Id"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":1000,"minimum":1,"default":1000,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Free-text search on cell specification name plus prefix full-text match, matching the global search. Composes with the column filters.","title":"Q"},"description":"Free-text search on cell specification name plus prefix full-text match, matching the global search. Composes with the column filters."},{"name":"name","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"}},{"name":"form_factor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Form Factor"}},{"name":"anode","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Anode"}},{"name":"cathode","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cathode"}},{"name":"material_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Material Id"}},{"name":"material_ids","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}],"title":"Material Ids"}},{"name":"anode_material_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Anode Material Id"}},{"name":"cathode_material_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cathode Material Id"}},{"name":"electrolyte_material_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Electrolyte Material Id"}},{"name":"separator_material_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Separator Material Id"}},{"name":"case_material_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Case Material Id"}},{"name":"exclude_cell_spec_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Exclude Cell Spec Id"}},{"name":"created_by_email","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created By Email"}},{"name":"created_at","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At"}},{"name":"created_at_gt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At Gt"}},{"name":"created_at_lt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At Lt"}},{"name":"updated_at","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated At"}},{"name":"updated_at_gt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated At Gt"}},{"name":"updated_at_lt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated At Lt"}},{"name":"order_by","in":"query","required":false,"schema":{"enum":["name","created_at","updated_at"],"type":"string","default":"created_at","title":"Order By"}},{"name":"order","in":"query","required":false,"schema":{"enum":["asc","desc"],"type":"string","default":"desc","title":"Order"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/cell_specifications/{cell_spec_id}":{"get":{"tags":["Cell Specifications"],"summary":"Get a cell specification with nested component and material data","description":"Retrieve a cell specification with nested component and material information.\n\nReturns the specification with anode, cathode, electrolyte, separator, and case\ncomponents, each including their material details.","operationId":"get_cell_specification_cell_specifications__cell_spec_id__get","parameters":[{"name":"cell_spec_id","in":"path","required":true,"schema":{"type":"string","title":"Cell Spec Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CellSpecificationWithComponents"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false},"patch":{"tags":["Cell Specifications"],"summary":"Update a cell specification with nested component/material data","description":"Update an existing cell specification with nested component and material data.\n\nMaterials and components are automatically upserted based on uniqueness.\nOnly provided fields will be updated.\n\nExample request body:\n```json\n{\n    \"capacity\": 0.003,\n    \"anode\": {\n        \"properties\": {\"diameter_mm\": 16, \"thickness_um\": 25},\n        \"material\": {\"name\": \"Graphite\", \"manufacturer\": \"NewSupplier\"}\n    }\n}\n```","operationId":"update_cell_specification_cell_specifications__cell_spec_id__patch","parameters":[{"name":"cell_spec_id","in":"path","required":true,"schema":{"type":"string","title":"Cell Spec Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCellSpecificationNested"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CellSpecificationWithComponents"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false},"delete":{"tags":["Cell Specifications"],"summary":"Delete a cell specification by id for the current organization","description":"Delete a cell specification and all its instances, measurements, and storage files.","operationId":"delete_cell_specification_cell_specifications__cell_spec_id__delete","parameters":[{"name":"cell_spec_id","in":"path","required":true,"schema":{"type":"string","title":"Cell Spec Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/experiment_templates":{"get":{"tags":["experiment_templates"],"summary":"List Experiment Templates","description":"List a project's experiment templates.\n\n``project_id`` is **required**. Protocols are project-scoped: every project\nholds its own copies of the built-in catalog, so an organization-wide list\nreturns the same protocol once per project rather than a meaningful catalog.\nThis endpoint used to union the org's unscoped rows with the system\norganization's; both of those sources are gone in the contract phase, so\nrather than silently returning N copies of everything it now rejects the\ncall. The response is lightweight by default:\nlarge JSONB columns\n(``protocol_config``, ``parameters_schema``, ``time_series_spec``,\n``metrics_spec``, ``plot_options``) and the ``source_protocol`` text are\nomitted unless explicitly requested via ``?include=``. Fetch the full\ntemplate via ``GET /{template_id}`` when the user opens one.\n\nParameters\n----------\nlimit : int | None, optional\n    Page size (1-100). When omitted, one page of up to PostgREST's\n    ``max_rows`` is returned; compare ``count`` against ``total`` to\n    detect that there is more.\noffset : int | None, optional\n    Number of records to skip before the page starts.\ninclude : str | None, optional\n    Comma-separated list of heavy columns to include in the response.\n    Supported values: ``protocol_config``, ``parameters_schema``,\n    ``time_series_spec``, ``metrics_spec``, ``plot_options``,\n    ``source_protocol``. Unknown names are silently ignored.\nproject_id : str\n    Project whose protocols to return. Required — see above.\nname : str | None, optional\n    Text filter on the protocol name, per the field's policy in\n    ``_PROTOCOL_FILTERS``: ``ilike.%rpt%`` for a partial match,\n    ``eq.RPT`` for an exact one. A bare value is equality.\ncreated_by_email : str | None, optional\n    Text filter on the creator's email, same operator syntax as ``name``.\ncreated_at, updated_at : str | None, optional\n    Date filters: ``gte.value`` / ``lte.value`` etc. Use the ``_gt`` /\n    ``_lt`` variants together for a between query.\norder_by : str, optional\n    Column to sort by. Defaults to ``created_at``.\norder : str, optional\n    Sort direction. Defaults to ``desc``.\n\nReturns\n-------\nExperimentTemplateListResponse\n    ``items``, ``count`` (rows in this response) and ``total`` (every\n    protocol matching the filters). ``count < total`` means the result was\n    truncated — page through with ``limit`` / ``offset`` to get the rest.\n\nRaises\n------\nBadRequestError\n    If ``project_id`` is omitted, or a filter value violates its field\n    policy. An unsupported ``order_by`` / ``order`` is a 422 from FastAPI.","operationId":"list_experiment_templates_experiment_templates_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","maximum":100,"minimum":1},{"type":"null"}],"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":0},{"type":"null"}],"title":"Offset"}},{"name":"include","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Include"}},{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Free-text search on template name plus prefix full-text match, matching the global search.","title":"Q"},"description":"Free-text search on template name plus prefix full-text match, matching the global search."},{"name":"project_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Id"}},{"name":"name","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"}},{"name":"description","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"}},{"name":"created_by_email","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created By Email"}},{"name":"protocol_group_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Protocol Group Id"}},{"name":"created_at","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At"}},{"name":"created_at_gt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At Gt"}},{"name":"created_at_lt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At Lt"}},{"name":"updated_at","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated At"}},{"name":"updated_at_gt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated At Gt"}},{"name":"updated_at_lt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated At Lt"}},{"name":"order_by","in":"query","required":false,"schema":{"enum":["name","created_at","updated_at"],"type":"string","default":"created_at","title":"Order By"}},{"name":"order","in":"query","required":false,"schema":{"enum":["asc","desc"],"type":"string","default":"desc","title":"Order"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExperimentTemplateListResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true},"post":{"tags":["experiment_templates"],"summary":"Create Experiment Template","description":"Create a new experiment template.\n\nParameters\n----------\nbody : CreateExperimentTemplateBody\n    Template creation data.\n\nReturns\n-------\nExperimentTemplate\n    Created experiment template.","operationId":"create_experiment_template_experiment_templates_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateExperimentTemplateBody"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExperimentTemplate"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/experiment_templates/{template_id}":{"get":{"tags":["experiment_templates"],"summary":"Get Experiment Template","description":"Get a specific experiment template by ID.\n\nParameters\n----------\ntemplate_id : str\n    ID of the template to retrieve.\n\nReturns\n-------\nExperimentTemplate\n    The experiment template.\n\nRaises\n------\nNotFoundError\n    If the template does not exist or is not accessible to the caller.","operationId":"get_experiment_template_experiment_templates__template_id__get","parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExperimentTemplate"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true},"patch":{"tags":["experiment_templates"],"summary":"Update Experiment Template","description":"Update an experiment template's name and/or description.\n\nOnly organization-owned templates can be updated (not system templates).\n\nParameters\n----------\ntemplate_id : str\n    ID of the template to update.\nbody : UpdateExperimentTemplateBody\n    Fields to update.\n\nReturns\n-------\nExperimentTemplate\n    Updated experiment template.","operationId":"update_experiment_template_experiment_templates__template_id__patch","parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateExperimentTemplateBody"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExperimentTemplate"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true},"delete":{"tags":["experiment_templates"],"summary":"Delete Experiment Template","description":"Delete an experiment template.\n\nParameters\n----------\ntemplate_id : str\n    ID of the template to delete.\n\nReturns\n-------\ndict\n    Success message.\n\nRaises\n------\nNotFoundError\n    If the template is not found or not owned by the caller's organization.","operationId":"delete_experiment_template_experiment_templates__template_id__delete","parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/experiment_templates/{template_id}/human_readable":{"get":{"tags":["experiment_templates"],"summary":"Get Experiment Template Human Readable","description":"Get a human-readable representation of a template's protocol.\n\nParameters\n----------\ntemplate_id : str\n    ID of the template.\n\nReturns\n-------\nstr\n    Human-readable protocol text.","operationId":"get_experiment_template_human_readable_experiment_templates__template_id__human_readable_get","parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}}],"responses":{"200":{"description":"Successful Response","content":{"text/plain":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/experiment_templates/{template_id}/source_protocol":{"get":{"tags":["experiment_templates"],"summary":"Get Experiment Template Source Protocol","description":"Return the source protocol text stored on a template.\n\nParameters\n----------\ntemplate_id : str\n    ID of the template.\n\nReturns\n-------\nstr\n    The original protocol text.\n\nRaises\n------\nNotFoundError\n    If the template or its source protocol does not exist.","operationId":"get_experiment_template_source_protocol_experiment_templates__template_id__source_protocol_get","parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}}],"responses":{"200":{"description":"Successful Response","content":{"text/plain":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/protocol_groups":{"get":{"tags":["protocol_groups"],"summary":"List Protocol Groups","description":"List a project's protocol groups.\n\n``project_id`` is required — groups are project-scoped, exactly like the\nprotocols they group. Each item carries ``protocol_count``, the number of\nprotocols currently filed under it.\n\nParameters\n----------\nproject_id : str\n    Project whose groups to list.\nlimit : int | None, optional\n    Page size, 1–100. When None, returns all groups.\noffset : int | None, optional\n    Number of records to skip.\norder_by : {\"name\", \"created_at\", \"updated_at\"}, optional\n    Column to sort by. Defaults to ``created_at``.\norder : {\"asc\", \"desc\"}, optional\n    Sort direction. Defaults to ``desc``.\n\nReturns\n-------\nProtocolGroupListResponse\n    Page of groups plus the total number matching the filters.","operationId":"list_protocol_groups_protocol_groups_get","parameters":[{"name":"project_id","in":"query","required":true,"schema":{"type":"string","title":"Project Id"}},{"name":"limit","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","maximum":100,"minimum":1},{"type":"null"}],"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":0},{"type":"null"}],"title":"Offset"}},{"name":"name","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"}},{"name":"created_by_email","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created By Email"}},{"name":"created_at","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At"}},{"name":"created_at_gt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At Gt"}},{"name":"created_at_lt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At Lt"}},{"name":"updated_at","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated At"}},{"name":"updated_at_gt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated At Gt"}},{"name":"updated_at_lt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated At Lt"}},{"name":"order_by","in":"query","required":false,"schema":{"enum":["name","created_at","updated_at"],"type":"string","default":"created_at","title":"Order By"}},{"name":"order","in":"query","required":false,"schema":{"enum":["asc","desc"],"type":"string","default":"desc","title":"Order"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProtocolGroupListResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true},"post":{"tags":["protocol_groups"],"summary":"Create Protocol Group","description":"Create a protocol group in a project.\n\nParameters\n----------\nbody : CreateProtocolGroupBody\n    Group creation data.\n\nReturns\n-------\nProtocolGroup\n    The created group.\n\nRaises\n------\nConflictError\n    If the project already has a group with this name (case-insensitive).\nAppError\n    If the insert returns no row.","operationId":"create_protocol_group_protocol_groups_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProtocolGroupBody"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProtocolGroup"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/protocol_groups/{group_id}":{"get":{"tags":["protocol_groups"],"summary":"Get Protocol Group","description":"Get a single protocol group by ID.\n\nParameters\n----------\ngroup_id : str\n    ID of the group to retrieve.\n\nReturns\n-------\nProtocolGroup\n    The requested group.\n\nRaises\n------\nNotFoundError\n    If the group does not exist or belongs to another organization.","operationId":"get_protocol_group_protocol_groups__group_id__get","parameters":[{"name":"group_id","in":"path","required":true,"schema":{"type":"string","title":"Group Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProtocolGroup"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true},"patch":{"tags":["protocol_groups"],"summary":"Update Protocol Group","description":"Update a protocol group's name and/or description.\n\nRenaming a group affects every protocol in it, since membership is by\nreference rather than by copied name.\n\nParameters\n----------\ngroup_id : str\n    ID of the group to update.\nbody : UpdateProtocolGroupBody\n    Fields to update. Omitted fields are left unchanged; an explicit\n    ``description: null`` clears the description.\n\nReturns\n-------\nProtocolGroup\n    The updated group.\n\nRaises\n------\nNotFoundError\n    If the group does not exist or belongs to another organization.\nConflictError\n    If the new name collides with another group in the same project.","operationId":"update_protocol_group_protocol_groups__group_id__patch","parameters":[{"name":"group_id","in":"path","required":true,"schema":{"type":"string","title":"Group Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProtocolGroupBody"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProtocolGroup"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true},"delete":{"tags":["protocol_groups"],"summary":"Delete Protocol Group","description":"Delete a protocol group.\n\nThe protocols in the group are **not** deleted — the database's\n``ON DELETE SET NULL`` ungroups them, since a group is metadata about\nprotocols and never their owner.\n\nParameters\n----------\ngroup_id : str\n    ID of the group to delete.\n\nReturns\n-------\ndict\n    Success message.\n\nRaises\n------\nNotFoundError\n    If the group does not exist or belongs to another organization.\nForbiddenError\n    If the caller lacks ``protocol_group:delete`` in the project.","operationId":"delete_protocol_group_protocol_groups__group_id__delete","parameters":[{"name":"group_id","in":"path","required":true,"schema":{"type":"string","title":"Group Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Delete Protocol Group Protocol Groups  Group Id  Delete"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/cell_instances/{cell_instance_id}/cell_measurements":{"get":{"tags":["Cell Instances","Cell Measurements"],"summary":"List cell measurements for a cell instance","description":"List cell measurements for an instance with pagination and filtering.\n\nFilter parameters support Supabase filter operators:\n- Text fields (name, created_by_email): Use ``ilike.%value%`` for partial\n  match\n- Date fields: Use ``gte.value``, ``lte.value``, etc.\n- Date range: Use created_at_gt and created_at_lt for between queries","operationId":"list_cell_measurements_cell_instances__cell_instance_id__cell_measurements_get","parameters":[{"name":"cell_instance_id","in":"path","required":true,"schema":{"type":"string","title":"Cell Instance Id"}},{"name":"measurement_type","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/MeasurementType"},{"type":"null"}],"description":"Filter by measurement type","title":"Measurement Type"},"description":"Filter by measurement type"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":1000,"minimum":1,"default":25,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Free-text search on measurement name and search_vector.","title":"Q"},"description":"Free-text search on measurement name and search_vector."},{"name":"name","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"}},{"name":"created_by_email","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created By Email"}},{"name":"start_time","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Start Time"}},{"name":"start_time_gt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Start Time Gt"}},{"name":"start_time_lt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Start Time Lt"}},{"name":"created_at","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At"}},{"name":"created_at_gt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At Gt"}},{"name":"created_at_lt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At Lt"}},{"name":"updated_at","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated At"}},{"name":"updated_at_gt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated At Gt"}},{"name":"updated_at_lt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated At Lt"}},{"name":"order_by","in":"query","required":false,"schema":{"enum":["name","created_at","updated_at","start_time"],"type":"string","default":"created_at","title":"Order By"}},{"name":"order","in":"query","required":false,"schema":{"enum":["asc","desc"],"type":"string","default":"desc","title":"Order"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/cell_instances/{cell_instance_id}/cell_measurements/create":{"post":{"tags":["Cell Instances","Cell Measurements"],"summary":"Create a properties-type measurement directly","description":"Create a properties-type measurement without the upload flow.\n\nUse this for manual measurements like thickness, weight, etc.","operationId":"create_properties_measurement_cell_instances__cell_instance_id__cell_measurements_create_post","parameters":[{"name":"cell_instance_id","in":"path","required":true,"schema":{"type":"string","title":"Cell Instance Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePropertiesMeasurementRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CellMeasurement"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/cell_instances/{cell_instance_id}/cell_measurements/initiate-upload":{"post":{"tags":["Cell Instances","Cell Measurements"],"summary":"Initiate a signed URL upload for measurement data","description":"Initiate upload for time_series or file measurement data.\n\nEach returned upload target also carries an optional S3 ``multipart`` block,\nwhich clients use instead of the signed URL for large files. Its session\ntoken is the caller's own JWT, so storage RLS still applies.","operationId":"initiate_measurement_upload_cell_instances__cell_instance_id__cell_measurements_initiate_upload_post","parameters":[{"name":"cell_instance_id","in":"path","required":true,"schema":{"type":"string","title":"Cell Instance Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InitiateUploadRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/cell_instances/{cell_instance_id}":{"get":{"tags":["Cell Instances"],"summary":"Get a specific cell instance by id","description":"Retrieves a specific cell instance by its ID.","operationId":"get_cell_instance_cell_instances__cell_instance_id__get","parameters":[{"name":"cell_instance_id","in":"path","required":true,"schema":{"type":"string","title":"Cell Instance Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CellInstance"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false},"patch":{"tags":["Cell Instances"],"summary":"Update a specific cell instance by id","description":"Updates an existing cell instance identified by its ID.\nOnly provided fields will be updated.","operationId":"update_cell_instance_cell_instances__cell_instance_id__patch","parameters":[{"name":"cell_instance_id","in":"path","required":true,"schema":{"type":"string","title":"Cell Instance Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Raw Data"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CellInstance"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false},"delete":{"tags":["Cell Instances"],"summary":"Delete a specific cell instance by id","description":"Deletes an existing cell instance identified by its ID, including:\n- All measurements (cascades to delete measurement steps)\n- All associated data files in storage bucket for all measurements\n- The instance itself","operationId":"delete_cell_instance_cell_instances__cell_instance_id__delete","parameters":[{"name":"cell_instance_id","in":"path","required":true,"schema":{"type":"string","title":"Cell Instance Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/cell_measurements":{"get":{"tags":["Cell Measurements"],"summary":"List cell measurements","description":"List cell measurements, scoped to a cell specification or a project.\n\nExactly one of ``cell_specification_id`` (all instances of that spec, page\nsize 1000) or ``project_id`` (paginated, parent instance fields joined, page\nsize 25) is required. ``project_id`` also accepts ``instance_name``,\n``cell_instance_id`` and ``spec_id``.\n\n``channel_id`` and ``protocol_id`` are exact match; text takes\n``ilike.%value%`` and dates ``gte.value`` / ``lte.value``.","operationId":"list_cell_measurements_cell_measurements_get","parameters":[{"name":"cell_specification_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cell Specification Id"}},{"name":"project_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Id"}},{"name":"measurement_type","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/MeasurementType"},{"type":"null"}],"description":"Filter by measurement type","title":"Measurement Type"},"description":"Filter by measurement type"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":1000,"minimum":1,"default":25,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Free-text search on measurement name and search_vector.","title":"Q"},"description":"Free-text search on measurement name and search_vector."},{"name":"id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Id"}},{"name":"id_text","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Id Text"}},{"name":"name","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"}},{"name":"channel_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Channel Id"}},{"name":"protocol_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Protocol Id"}},{"name":"created_by_email","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created By Email"}},{"name":"start_time","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Start Time"}},{"name":"start_time_gt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Start Time Gt"}},{"name":"start_time_lt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Start Time Lt"}},{"name":"created_at","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At"}},{"name":"created_at_gt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At Gt"}},{"name":"created_at_lt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At Lt"}},{"name":"updated_at","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated At"}},{"name":"updated_at_gt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated At Gt"}},{"name":"updated_at_lt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated At Lt"}},{"name":"instance_name","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Instance Name"}},{"name":"cell_instance_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cell Instance Id"}},{"name":"cell_instance_id_text","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cell Instance Id Text"}},{"name":"spec_id_text","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Spec Id Text"}},{"name":"spec_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Spec Id"}},{"name":"order_by","in":"query","required":false,"schema":{"enum":["id","name","created_at","updated_at","start_time","cell_instance_id","step_labels_validated","notes"],"type":"string","default":"created_at","title":"Order By"}},{"name":"order","in":"query","required":false,"schema":{"enum":["asc","desc"],"type":"string","default":"desc","title":"Order"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/cell_measurements/export":{"post":{"tags":["Cell Measurements"],"summary":"Export measurement data (time series, steps, files, metadata) as a zip","operationId":"export_measurements_cell_measurements_export_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MeasurementExportRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/cell_measurements/{measurement_id}":{"get":{"tags":["Cell Measurements"],"summary":"Get a cell measurement by id","description":"Retrieve a cell measurement by its ID only.","operationId":"get_cell_measurement_by_id_cell_measurements__measurement_id__get","parameters":[{"name":"measurement_id","in":"path","required":true,"schema":{"type":"string","title":"Measurement Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false},"patch":{"tags":["Cell Measurements"],"summary":"Update a cell measurement by id","description":"Update an existing cell measurement's metadata.\n\nOnly metadata fields can be updated (name, protocol, test_setup, notes,\nproperties, channel_id, protocol_id). Time series and steps data cannot be\nmodified.","operationId":"update_cell_measurement_cell_measurements__measurement_id__patch","parameters":[{"name":"measurement_id","in":"path","required":true,"schema":{"type":"string","title":"Measurement Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCellMeasurement"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CellMeasurement"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false},"delete":{"tags":["Cell Measurements"],"summary":"Delete a specific cell measurement by id","description":"Deletes a cell measurement identified by its ID, including:\n- All storage files (steps.parquet, time_series.parquet)\n- Database record\nReturns 204 No Content on success or if already deleted.","operationId":"delete_cell_measurement_by_id_cell_measurements__measurement_id__delete","parameters":[{"name":"measurement_id","in":"path","required":true,"schema":{"type":"string","title":"Measurement Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/cell_measurements/{measurement_id}/detail":{"get":{"tags":["Cell Measurements"],"summary":"Get detailed information for a cell measurement","description":"Retrieves detailed information for a specific cell\nmeasurement by measurement ID.\n\n**Deprecated**: prefer the individual endpoints\nGET /steps, GET /cycles, GET /time_series, and\nGET /steps_and_cycles instead.\n\nSupports zoom-based resampling: specify x_min, x_max,\nand x_column to fetch higher resolution data for a\nspecific x-axis range.","operationId":"get_cell_measurement_detail_cell_measurements__measurement_id__detail_get","deprecated":true,"parameters":[{"name":"measurement_id","in":"path","required":true,"schema":{"type":"string","title":"Measurement Id"}},{"name":"target_rows","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":1},{"type":"null"}],"description":"Target rows for downsampled time series","title":"Target Rows"},"description":"Target rows for downsampled time series"},{"name":"columns","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Comma-separated list of columns to load (e.g., 'time,voltage')","title":"Columns"},"description":"Comma-separated list of columns to load (e.g., 'time,voltage')"},{"name":"step_counts","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Step numbers to keep, as singletons and/or ranges (e.g. '0-2,5,8-10')","title":"Step Counts"},"description":"Step numbers to keep, as singletons and/or ranges (e.g. '0-2,5,8-10')"},{"name":"cycle_counts","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Comma-separated list of cycle counts to filter (e.g., '1,2,3')","title":"Cycle Counts"},"description":"Comma-separated list of cycle counts to filter (e.g., '1,2,3')"},{"name":"x_min","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Minimum x-axis value to filter","title":"X Min"},"description":"Minimum x-axis value to filter"},{"name":"x_max","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Maximum x-axis value to filter","title":"X Max"},"description":"Maximum x-axis value to filter"},{"name":"x_column","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Column name for x-axis filtering (e.g., 'Time [s]' or 'Capacity throughput [A.h]')","title":"X Column"},"description":"Column name for x-axis filtering (e.g., 'Time [s]' or 'Capacity throughput [A.h]')"},{"name":"include_steps","in":"query","required":false,"schema":{"type":"boolean","description":"Include steps in response.","default":true,"title":"Include Steps"},"description":"Include steps in response."},{"name":"include_time_series","in":"query","required":false,"schema":{"type":"boolean","description":"Include time_series in response.","default":true,"title":"Include Time Series"},"description":"Include time_series in response."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CellMeasurementDetail"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/cell_measurements/{measurement_id}/estimate_end_time":{"patch":{"tags":["Cell Measurements"],"summary":"Estimate a running measurement's end time from its remaining protocol","description":"Forecast when this still-running test will finish.\n\nReplays the measured steps onto the protocol's state machine, then simulates\nonly the remainder with the cell specification's default model. Returns\nimmediately, marked ``estimating``; ``estimated_end_time`` lands when the\nsimulation finishes.","operationId":"estimate_cell_measurement_end_time_cell_measurements__measurement_id__estimate_end_time_patch","parameters":[{"name":"measurement_id","in":"path","required":true,"schema":{"type":"string","title":"Measurement Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CellMeasurement"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/cell_measurements/{measurement_id}/steps":{"get":{"tags":["Cell Measurements"],"summary":"Get all steps for a cell measurement","description":"Retrieve ALL steps for a specific cell measurement.\n\nBackend fetches all steps internally (paginating as needed with limit 1000).\nReturns ``{ steps: {...} }``.","operationId":"get_cell_measurement_steps_cell_measurements__measurement_id__steps_get","parameters":[{"name":"measurement_id","in":"path","required":true,"schema":{"type":"string","title":"Measurement Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/cell_measurements/{measurement_id}/steps_and_cycles":{"get":{"tags":["Cell Measurements"],"summary":"Get steps and cycle metrics in one call","description":"Retrieve all steps and a budgeted cycle series together.\n\nFetches steps once and computes cycles from the same data, avoiding a double\nfetch when both are needed. Returns ``{ steps: {...}, cycles: {...} }``.\n\n``max_points`` bounds the **cycle** series only. Steps are returned complete\nwhatever it says, and deliberately: the client resolves step-within-cycle filters\nagainst this table and builds its hover labels from it, so a decimated steps table\nwould make the same filter select different rows at different plot widths. The\ncycle series is what gets drawn, and what a long-cycling test can make unbounded.","operationId":"get_cell_measurement_steps_and_cycles_cell_measurements__measurement_id__steps_and_cycles_get","parameters":[{"name":"measurement_id","in":"path","required":true,"schema":{"type":"string","title":"Measurement Id"}},{"name":"max_points","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":1},{"type":"null"}],"description":"Maximum rows of the CYCLE series; steps are always complete","title":"Max Points"},"description":"Maximum rows of the CYCLE series; steps are always complete"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/cell_measurements/{measurement_id}/cycles":{"get":{"tags":["Cell Measurements"],"summary":"Get cycle metrics only for a cell measurement","description":"Retrieve cycle metrics only (computed from ALL steps).\n\nBackend fetches all steps internally to compute cycles.\nReturns ``{ cycles: {...} }``, budgeted to ``max_points`` rows when one is given.","operationId":"get_cell_measurement_cycles_cell_measurements__measurement_id__cycles_get","parameters":[{"name":"measurement_id","in":"path","required":true,"schema":{"type":"string","title":"Measurement Id"}},{"name":"max_points","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":1},{"type":"null"}],"description":"Maximum rows of the cycle series","title":"Max Points"},"description":"Maximum rows of the cycle series"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/cell_measurements/{measurement_id}/time_series":{"get":{"tags":["Cell Measurements"],"summary":"Get time series data for a measurement","description":"Return time series data from storage.\n\nDoes not include steps or cycles. Use GET /steps for steps and GET /cycles for\ncycle metrics.","operationId":"get_cell_measurement_time_series_cell_measurements__measurement_id__time_series_get","parameters":[{"name":"measurement_id","in":"path","required":true,"schema":{"type":"string","title":"Measurement Id"}},{"name":"target_rows","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":1},{"type":"null"}],"description":"Deprecated: use max_points","title":"Target Rows"},"description":"Deprecated: use max_points"},{"name":"max_points","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":1},{"type":"null"}],"description":"Maximum rows to return. Canonical name for the point budget; wins over the deprecated target_rows when both are given.","title":"Max Points"},"description":"Maximum rows to return. Canonical name for the point budget; wins over the deprecated target_rows when both are given."},{"name":"columns","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Comma-separated list of columns to load (e.g., 'time,voltage')","title":"Columns"},"description":"Comma-separated list of columns to load (e.g., 'time,voltage')"},{"name":"step_counts","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Step numbers to keep, as singletons and/or ranges (e.g. '0-2,5,8-10')","title":"Step Counts"},"description":"Step numbers to keep, as singletons and/or ranges (e.g. '0-2,5,8-10')"},{"name":"cycle_counts","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Comma-separated list of cycle counts to filter (e.g., '1,2,3')","title":"Cycle Counts"},"description":"Comma-separated list of cycle counts to filter (e.g., '1,2,3')"},{"name":"x_min","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Minimum x-axis value to filter","title":"X Min"},"description":"Minimum x-axis value to filter"},{"name":"x_max","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Maximum x-axis value to filter","title":"X Max"},"description":"Maximum x-axis value to filter"},{"name":"x_column","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Column name for x-axis filtering (e.g., 'Time [s]')","title":"X Column"},"description":"Column name for x-axis filtering (e.g., 'Time [s]')"},{"name":"group_column","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Column whose values the client draws as separate stacked traces, e.g. 'Cycle count'. Bins are then laid within each group instead of across their combined span, so a sparse selection does not spend its budget on the gaps between the groups it kept. Send it only when really stacking: per-group bins are a different grid, not a finer one.","title":"Group Column"},"description":"Column whose values the client draws as separate stacked traces, e.g. 'Cycle count'. Bins are then laid within each group instead of across their combined span, so a sparse selection does not spend its budget on the gaps between the groups it kept. Send it only when really stacking: per-group bins are a different grid, not a finer one."},{"name":"x_origin","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"'group' re-bases x_column so each group starts at zero, which is what a stacked plot draws; x_min/x_max are then read in those coordinates. Requires group_column. Omitted, x is returned as stored.","title":"X Origin"},"description":"'group' re-bases x_column so each group starts at zero, which is what a stacked plot draws; x_min/x_max are then read in those coordinates. Requires group_column. Omitted, x is returned as stored."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/cell_measurements/{measurement_id}/time_series/download":{"get":{"tags":["Cell Measurements"],"summary":"Download time series parquet file","description":"Redirect to storage for the time series parquet file.\n\nReturns a 307 redirect to a short-lived signed URL. Most HTTP clients\nfollow redirects automatically, so the caller receives the parquet\nbytes transparently. Replaces the old ``/time_series/signed_url``\nendpoint.","operationId":"get_time_series_download_cell_measurements__measurement_id__time_series_download_get","parameters":[{"name":"measurement_id","in":"path","required":true,"schema":{"type":"string","title":"Measurement Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/cell_measurements/{measurement_id}/steps/download":{"get":{"tags":["Cell Measurements"],"summary":"Download steps parquet file","description":"Redirect to storage for the steps parquet file.\n\nReturns a 307 redirect to a short-lived signed URL. Most HTTP clients\nfollow redirects automatically, so the caller receives the parquet\nbytes transparently.","operationId":"get_steps_download_cell_measurements__measurement_id__steps_download_get","parameters":[{"name":"measurement_id","in":"path","required":true,"schema":{"type":"string","title":"Measurement Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/cell_measurements/{measurement_id}/files":{"get":{"tags":["Cell Measurements"],"summary":"List files in a measurement","description":"Return the list of filenames stored in a file-type measurement.","operationId":"list_measurement_files_cell_measurements__measurement_id__files_get","parameters":[{"name":"measurement_id","in":"path","required":true,"schema":{"type":"string","title":"Measurement Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/cell_measurements/{measurement_id}/files/{filename}":{"get":{"tags":["Cell Measurements"],"summary":"Download a measurement file","description":"Stream a specific file in a measurement back to the caller.\n\nThe bytes are proxied through the backend (same-origin) rather than\n307-redirecting to the storage signed URL. A cross-origin redirect to\n``http://`` storage trips the CSP ``upgrade-insecure-requests`` directive in\nlocal dev (and would otherwise require CORS), which breaks the browser-side\nblob fetch the file gallery does.","operationId":"get_measurement_file_cell_measurements__measurement_id__files__filename__get","parameters":[{"name":"measurement_id","in":"path","required":true,"schema":{"type":"string","title":"Measurement Id"}},{"name":"filename","in":"path","required":true,"schema":{"type":"string","title":"Filename"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/cell_measurements/filter-steps/schema":{"get":{"tags":["Cell Measurements"],"summary":"Get available columns for SQL step filtering","description":"Get the schema of available columns for SQL step filtering.\n\nReturns column names (SQL format), types, and descriptions that can be\nused in the WHERE clause of the filter-steps endpoint.","operationId":"get_filter_steps_schema_cell_measurements_filter_steps_schema_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"x-hidden":true}},"/cell_measurements/filter-steps/generate":{"post":{"tags":["Cell Measurements"],"summary":"Generate SQL filter from natural language using AI","description":"Generate a SQL WHERE clause from a natural language description using AI.\n\nThis endpoint uses a language model to convert natural language descriptions\nlike \"steps lasting more than an hour\" into SQL WHERE clauses like\n\"duration_s >= 3600\".\n\nThe AI also determines whether to use \"step\" or \"cycle\" match mode based\non the user's intent.\n\nThe generated SQL is validated against the specified measurement to ensure\nit is syntactically correct. If validation fails, the AI will retry.\n\nReturns:\n- sql_where_clause: The generated SQL WHERE clause\n- match_mode: \"step\" or \"cycle\"\n- explanation: Brief explanation of what the filter does","operationId":"generate_step_filter_cell_measurements_filter_steps_generate_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateFilterRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateFilterResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/cell_measurements/{measurement_id}/filter-steps":{"get":{"tags":["Cell Measurements"],"summary":"Filter steps by SQL condition (paginated)","description":"Filter measurement steps by a SQL WHERE condition and return\nstep counts.\n\nReturns one page of matching step counts. Use limit <= 1000 and\nrepeat with increasing offset until fewer than limit rows are\nreturned to fetch all matches.\n\nThis endpoint allows filtering steps using SQL syntax and returns\nthe step counts from matching steps. Useful for finding specific\nsteps with certain characteristics (e.g., \"find all 1-hour\ndischarge steps\").\n\nMatch modes:\n- \"step\" (default): Return only steps that match the condition\n- \"cycle\": Return ALL steps from cycles that have at least one\n  step matching the condition (useful for getting complete cycles)\n\nAvailable columns for filtering:\n- duration_s: Step duration in seconds\n- cycle_count, step_count: Cycle and step numbers\n- charge_capacity_ah, discharge_capacity_ah: Capacities\n- charge_energy_wh, discharge_energy_wh: Energies\n- min_voltage_v, max_voltage_v, mean_voltage_v: Voltage stats\n- min_current_a, max_current_a, mean_current_a: Current stats\n- And more (see MeasurementStepBase schema)\n\nExample queries:\n- duration_s >= 3600  (steps lasting 1+ hour)\n- charge_capacity_ah > 1.5\n- duration_s BETWEEN 1800 AND 7200","operationId":"filter_steps_by_condition_cell_measurements__measurement_id__filter_steps_get","parameters":[{"name":"measurement_id","in":"path","required":true,"schema":{"type":"string","title":"Measurement Id"}},{"name":"where_clause","in":"query","required":true,"schema":{"type":"string","description":"SQL WHERE clause to filter steps. Example: duration_s >= 3600","title":"Where Clause"},"description":"SQL WHERE clause to filter steps. Example: duration_s >= 3600"},{"name":"match_mode","in":"query","required":false,"schema":{"type":"string","description":"How to match steps. 'step' returns only steps matching the condition. 'cycle' returns ALL steps from cycles that have at least one step matching the condition.","default":"step","title":"Match Mode"},"description":"How to match steps. 'step' returns only steps matching the condition. 'cycle' returns ALL steps from cycles that have at least one step matching the condition."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":1000,"minimum":1,"description":"Number of step counts to return per page (max 1000).","default":1000,"title":"Limit"},"description":"Number of step counts to return per page (max 1000)."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Number of step counts to skip for pagination.","default":0,"title":"Offset"},"description":"Number of step counts to skip for pagination."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/cell_measurements/{measurement_id}/confirm-upload":{"post":{"tags":["Cell Measurements"],"summary":"Confirm a signed URL upload and finalize the measurement","description":"Confirm a signed URL upload and finalize the measurement.","operationId":"confirm_measurement_upload_cell_measurements__measurement_id__confirm_upload_post","parameters":[{"name":"measurement_id","in":"path","required":true,"schema":{"type":"string","title":"Measurement Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfirmUploadRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateMeasurementResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/cell_measurements/{measurement_id}/initiate-extend":{"post":{"tags":["Cell Measurements"],"summary":"Initiate signed URL upload to extend a measurement","description":"Mint a signed URL for uploading a delta time series extend file.","operationId":"initiate_measurement_extend_cell_measurements__measurement_id__initiate_extend_post","parameters":[{"name":"measurement_id","in":"path","required":true,"schema":{"type":"string","title":"Measurement Id"}}],"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InitiateUploadResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/cell_measurements/{measurement_id}/confirm-extend":{"post":{"tags":["Cell Measurements"],"summary":"Confirm extend upload; stitch series and recompute steps","description":"Confirm an extend upload; stitch series and recompute steps.","operationId":"confirm_measurement_extend_cell_measurements__measurement_id__confirm_extend_post","parameters":[{"name":"measurement_id","in":"path","required":true,"schema":{"type":"string","title":"Measurement Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateMeasurementResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/cell_measurements/{measurement_id}/raw_data":{"post":{"tags":["Cell Measurements"],"summary":"Attach raw-data records to a measurement","description":"Bulk-attach raw-data records to a measurement (idempotent).","operationId":"attach_raw_data_cell_measurements__measurement_id__raw_data_post","parameters":[{"name":"measurement_id","in":"path","required":true,"schema":{"type":"string","title":"Measurement Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AttachRawData"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_RawData_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true},"get":{"tags":["Cell Measurements"],"summary":"List a measurement's raw-data sources","description":"List raw-data records linked to a measurement.","operationId":"list_measurement_raw_data_cell_measurements__measurement_id__raw_data_get","parameters":[{"name":"measurement_id","in":"path","required":true,"schema":{"type":"string","title":"Measurement Id"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":100,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_RawData_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/cell_measurements/{measurement_id}/raw_data/{raw_data_id}":{"delete":{"tags":["Cell Measurements"],"summary":"Detach a raw-data record from a measurement","description":"Remove one measurement-to-raw-data link.","operationId":"detach_raw_data_cell_measurements__measurement_id__raw_data__raw_data_id__delete","parameters":[{"name":"measurement_id","in":"path","required":true,"schema":{"type":"string","title":"Measurement Id"}},{"name":"raw_data_id","in":"path","required":true,"schema":{"type":"string","title":"Raw Data Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/cell_measurements/{measurement_id}/watch":{"post":{"tags":["Cell Measurements"],"summary":"Watch a measurement (Lab 'My Channels')","description":"Start watching a measurement for the current user.\n\nIdempotent -- watching an already-watched measurement is a no-op. Watching\nthe live measurement on a channel is how a user adds that channel to their\n\"My Channels\" view.","operationId":"watch_measurement_cell_measurements__measurement_id__watch_post","parameters":[{"name":"measurement_id","in":"path","required":true,"schema":{"type":"string","title":"Measurement Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false},"delete":{"tags":["Cell Measurements"],"summary":"Stop watching a measurement","description":"Stop watching a measurement for the current user.\n\nIdempotent -- unwatching something not watched returns 204 all the same.","operationId":"unwatch_measurement_cell_measurements__measurement_id__watch_delete","parameters":[{"name":"measurement_id","in":"path","required":true,"schema":{"type":"string","title":"Measurement Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/materials":{"post":{"tags":["Materials"],"summary":"Create a new material for the current organization","description":"Create a new material for the current organization.","operationId":"create_material_materials_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateMaterial"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Material"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true},"get":{"tags":["Materials"],"summary":"List materials for the current organization scoped to a project","description":"Retrieve materials for the current organization scoped to a project.\n\nFilter parameters support Supabase filter operators:\n- Text fields (name, manufacturer, product_id): use ``ilike.%value%`` for a\n  partial match, or a bare value for exact equality\n- Date fields: use ``gte.value``, ``lte.value``, etc.\n- Date range: use created_at_gt and created_at_lt for between queries\n\n``q`` is the search box's free-text param, applied in the repository\nindependently of the ``name`` filter above.","operationId":"list_materials_materials_get","parameters":[{"name":"project_id","in":"query","required":true,"schema":{"type":"string","description":"Project to scope materials to","title":"Project Id"},"description":"Project to scope materials to"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":100,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Free-text search on material name (case-insensitive substring).","title":"Q"},"description":"Free-text search on material name (case-insensitive substring)."},{"name":"name","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"}},{"name":"manufacturer","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Manufacturer"}},{"name":"product_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Product Id"}},{"name":"created_at","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At"}},{"name":"created_at_gt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At Gt"}},{"name":"created_at_lt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At Lt"}},{"name":"updated_at","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated At"}},{"name":"updated_at_gt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated At Gt"}},{"name":"updated_at_lt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated At Lt"}},{"name":"order_by","in":"query","required":false,"schema":{"enum":["name","manufacturer","created_at","updated_at"],"type":"string","default":"name","title":"Order By"}},{"name":"order","in":"query","required":false,"schema":{"enum":["asc","desc"],"type":"string","default":"asc","title":"Order"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_Material_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/materials/{material_id}":{"get":{"tags":["Materials"],"summary":"Get a specific material by ID","description":"Retrieve a specific material by its ID.\n\nReturns materials from the current organization only.","operationId":"get_material_materials__material_id__get","parameters":[{"name":"material_id","in":"path","required":true,"schema":{"type":"string","title":"Material Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Material"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true},"patch":{"tags":["Materials"],"summary":"Update a material by ID","description":"Update an existing material identified by its ID.\n\nOnly materials in the current organization can be updated.","operationId":"update_material_materials__material_id__patch","parameters":[{"name":"material_id","in":"path","required":true,"schema":{"type":"string","title":"Material Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateMaterial"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Material"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true},"delete":{"tags":["Materials"],"summary":"Delete a material by ID","description":"Delete a material identified by its ID.\n\nOnly materials in the current organization can be deleted.\nFK violations (e.g. a cell component still references this material) are caught\nby ``global_exception_handler`` and returned as 400 BAD_REQUEST.","operationId":"delete_material_materials__material_id__delete","parameters":[{"name":"material_id","in":"path","required":true,"schema":{"type":"string","title":"Material Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/material_property_datasets":{"post":{"tags":["Material Property Datasets"],"summary":"Upload a material property dataset","description":"Upload a parquet or CSV file as a material property dataset.\n\nThe file must contain at least the columns declared in ``columns``. All\nvalues are coerced to Float64; non-parseable cells are stored as NaN. The\nraw file is preserved in storage alongside the processed parquet.\n\nThe ``columns`` field must be a JSON-encoded array, e.g.::\n\n    [\n        {\"name\": \"c_e\", \"unit\": \"mol/L\"},\n        {\"name\": \"kappa\", \"unit\": \"S/m\"},\n        {\"name\": \"diffusivity\", \"unit\": \"m^2/s\"}\n    ]","operationId":"create_material_property_dataset_material_property_datasets_post","requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_create_material_property_dataset_material_property_datasets_post"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MaterialPropertyDataset"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true},"get":{"tags":["Material Property Datasets"],"summary":"List material property datasets for a material","description":"List material property datasets for a given material.","operationId":"list_material_property_datasets_material_property_datasets_get","parameters":[{"name":"material_id","in":"query","required":true,"schema":{"type":"string","description":"Filter by material ID","title":"Material Id"},"description":"Filter by material ID"},{"name":"project_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Optionally filter by project ID","title":"Project Id"},"description":"Optionally filter by project ID"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":100,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_MaterialPropertyDataset_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/material_property_datasets/{property_id}":{"get":{"tags":["Material Property Datasets"],"summary":"Get a material property dataset by ID","description":"Retrieve a single material property dataset record by its ID.","operationId":"get_material_property_material_property_datasets__property_id__get","parameters":[{"name":"property_id","in":"path","required":true,"schema":{"type":"string","title":"Property Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MaterialPropertyDataset"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true},"patch":{"tags":["Material Property Datasets"],"summary":"Update a material property dataset's metadata or column specs","description":"Update dataset name and/or column specs.\n\nWhen ``columns`` is provided, the original uploaded file is re-parsed\nand the processed parquet is rebuilt with the new column metadata.\nColumn names must exactly match those in the original file.","operationId":"update_material_property_dataset_material_property_datasets__property_id__patch","parameters":[{"name":"property_id","in":"path","required":true,"schema":{"type":"string","title":"Property Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateMaterialPropertyDataset"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MaterialPropertyDataset"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true},"delete":{"tags":["Material Property Datasets"],"summary":"Delete a material property dataset","description":"Delete a material property dataset record and all associated storage files.","operationId":"delete_material_property_material_property_datasets__property_id__delete","parameters":[{"name":"property_id","in":"path","required":true,"schema":{"type":"string","title":"Property Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/material_property_datasets/{property_id}/data":{"get":{"tags":["Material Property Datasets"],"summary":"Download material property data as JSON","description":"Return the property dataset as a JSON object mapping column name to value array.\n\nSupports optional downsampling (``max_points``) and x-range filtering\n(``x_col`` + ``x_min`` + ``x_max``) for dynamic chart zoom resolution.\n\nExample response::\n\n    {\n        \"c_e\": [0.5, 1.0, 1.5, 2.0],\n        \"kappa\": [0.42, 0.71, 0.89, 0.95],\n        \"diffusivity\": [3.2e-10, 2.8e-10, 2.3e-10, 1.9e-10]\n    }","operationId":"get_material_property_data_material_property_datasets__property_id__data_get","parameters":[{"name":"property_id","in":"path","required":true,"schema":{"type":"string","title":"Property Id"}},{"name":"max_points","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":1},{"type":"null"}],"description":"Downsample to at most this many points","title":"Max Points"},"description":"Downsample to at most this many points"},{"name":"x_col","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Column to filter by x range","title":"X Col"},"description":"Column to filter by x range"},{"name":"x_min","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Minimum x value (inclusive)","title":"X Min"},"description":"Minimum x value (inclusive)"},{"name":"x_max","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Maximum x value (inclusive)","title":"X Max"},"description":"Maximum x value (inclusive)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/material_property_datasets/{property_id}/file":{"patch":{"tags":["Material Property Datasets"],"summary":"Replace the data file for a material property dataset","description":"Replace the data file for a material property dataset.\n\nThe dataset record retains its ID and all existing metadata. Only the stored\nfiles (processed parquet and original) are replaced. ``name``, ``columns``,\nand ``no_header`` may optionally be updated in the same request; if omitted,\nthe existing values are preserved.","operationId":"replace_material_property_file_material_property_datasets__property_id__file_patch","parameters":[{"name":"property_id","in":"path","required":true,"schema":{"type":"string","title":"Property Id"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_replace_material_property_file_material_property_datasets__property_id__file_patch"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MaterialPropertyDataset"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true},"get":{"tags":["Material Property Datasets"],"summary":"Download a material property dataset file","description":"Redirect to a short-lived signed URL for downloading a dataset file.\n\nReturns a ``307 Temporary Redirect`` to a Supabase signed URL (valid 5\nminutes). The browser follows the redirect and downloads the file directly\nfrom storage.\n\nUse ``?kind=parquet`` (default) for the processed parquet or\n``?kind=original`` for the raw file the user uploaded.","operationId":"download_material_property_file_material_property_datasets__property_id__file_get","parameters":[{"name":"property_id","in":"path","required":true,"schema":{"type":"string","title":"Property Id"}},{"name":"kind","in":"query","required":false,"schema":{"enum":["parquet","original"],"type":"string","description":"Which file to download: ``parquet`` for the processed dataset, ``original`` for the raw uploaded file.","default":"parquet","title":"Kind"},"description":"Which file to download: ``parquet`` for the processed dataset, ``original`` for the raw uploaded file."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/material_property_datasets/{property_id}/download-url":{"get":{"tags":["Material Property Datasets"],"summary":"Get a signed download URL for a material property dataset file","description":"Return a short-lived signed download URL for a dataset file.\n\nUnlike the ``/file`` redirect endpoint, this returns ``{\"url\": \"...\"}`` as\nJSON so that authenticated API clients can retrieve the URL and hand it to\nthe browser (e.g. ``window.open(url)``). The signed URL is valid for 5\nminutes.","operationId":"get_material_property_dataset_download_url_material_property_datasets__property_id__download_url_get","parameters":[{"name":"property_id","in":"path","required":true,"schema":{"type":"string","title":"Property Id"}},{"name":"kind","in":"query","required":false,"schema":{"enum":["parquet","original"],"type":"string","description":"Which file to return a URL for: ``parquet`` for the processed dataset, ``original`` for the raw uploaded file.","default":"parquet","title":"Kind"},"description":"Which file to return a URL for: ``parquet`` for the processed dataset, ``original`` for the raw uploaded file."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/analyses":{"post":{"tags":["Analyses"],"summary":"Upload an analysis for a measurement","description":"Upload a parquet file as an analysis derived from a single measurement.\n\nThe parquet is stored in the ``measurement-data`` bucket alongside the row.\n``columns`` and ``metadata`` are JSON-encoded form fields.","operationId":"create_analysis_analyses_post","requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_create_analysis_analyses_post"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Analysis"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true},"get":{"tags":["Analyses"],"summary":"List analyses for a measurement or project","description":"List analyses scoped to a single measurement or a whole project.\n\nExactly one of ``measurement_id`` or ``project_id`` must be supplied.","operationId":"list_analyses_analyses_get","parameters":[{"name":"measurement_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by parent measurement ID","title":"Measurement Id"},"description":"Filter by parent measurement ID"},{"name":"project_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by owning project ID","title":"Project Id"},"description":"Filter by owning project ID"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":100,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_Analysis_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/analyses/{analysis_id}":{"get":{"tags":["Analyses"],"summary":"Get an analysis by ID","description":"Retrieve a single analysis record by its ID.","operationId":"get_analysis_analyses__analysis_id__get","parameters":[{"name":"analysis_id","in":"path","required":true,"schema":{"type":"string","title":"Analysis Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Analysis"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true},"patch":{"tags":["Analyses"],"summary":"Update an analysis's metadata","description":"Update analysis metadata fields. Does not replace the parquet.","operationId":"update_analysis_analyses__analysis_id__patch","parameters":[{"name":"analysis_id","in":"path","required":true,"schema":{"type":"string","title":"Analysis Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAnalysis"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Analysis"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true},"delete":{"tags":["Analyses"],"summary":"Delete an analysis","description":"Delete an analysis record and its parquet file.","operationId":"delete_analysis_analyses__analysis_id__delete","parameters":[{"name":"analysis_id","in":"path","required":true,"schema":{"type":"string","title":"Analysis Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/analyses/{analysis_id}/download-url":{"get":{"tags":["Analyses"],"summary":"Get a signed download URL for an analysis parquet","description":"Return a short-lived signed download URL for the analysis parquet.\n\nReturns ``{\"url\": \"...\"}`` as JSON. The signed URL is valid for 5 minutes.","operationId":"get_analysis_download_url_analyses__analysis_id__download_url_get","parameters":[{"name":"analysis_id","in":"path","required":true,"schema":{"type":"string","title":"Analysis Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/analyses/{analysis_id}/series":{"get":{"tags":["Analyses"],"summary":"Read analysis data as columnar JSON, at the caller's density","description":"Return analysis columns as ``{name: [values]}``, windowed and decimated.\n\nThe counterpart to ``/download-url``: that hands the browser the whole parquet, which\nis what \"save this file\" needs and what drawing it does not. Supports semantic zoom —\nrefetch with ``x_min``/``x_max`` and a width-derived ``max_points`` on each gesture.","operationId":"get_analysis_series_analyses__analysis_id__series_get","parameters":[{"name":"analysis_id","in":"path","required":true,"schema":{"type":"string","title":"Analysis Id"}},{"name":"x","in":"query","required":true,"schema":{"type":"string","description":"Column plotted on x; also the axis binned on","title":"X"},"description":"Column plotted on x; also the axis binned on"},{"name":"columns","in":"query","required":true,"schema":{"type":"string","description":"Comma-separated columns to return","title":"Columns"},"description":"Comma-separated columns to return"},{"name":"max_points","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","maximum":80000,"minimum":1},{"type":"null"}],"description":"Width-derived row ceiling. Omit to return the window undecimated.","title":"Max Points"},"description":"Width-derived row ceiling. Omit to return the window undecimated."},{"name":"x_min","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Lower x bound (inclusive)","title":"X Min"},"description":"Lower x bound (inclusive)"},{"name":"x_max","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Upper x bound (inclusive)","title":"X Max"},"description":"Upper x bound (inclusive)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/raw_data/initiate-upload":{"post":{"tags":["Raw Data"],"summary":"Initiate a signed-URL raw-data upload","description":"Generate a signed upload URL. No DB record is created yet.\n\nReturns the pre-generated raw-data ID and a single-element list of\nsigned-URL upload targets. The client PUTs the file bytes to the signed\nURL and then calls the confirm endpoint to create the record. Each target\nalso carries an optional S3 ``multipart`` block, which clients use instead\nof the signed URL for files too large for a single PUT.","operationId":"initiate_raw_data_upload_raw_data_initiate_upload_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InitiateRawDataUploadRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InitiateRawDataUploadResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/raw_data/{raw_data_id}/confirm-upload":{"post":{"tags":["Raw Data"],"summary":"Confirm a signed-URL raw-data upload","description":"Verify the file landed in storage, then create the DB record.\n\nThe storage path is recomputed server-side from ``organization_id``,\n``raw_data_id`` and ``filename``; a client-supplied path is never trusted.","operationId":"confirm_raw_data_upload_raw_data__raw_data_id__confirm_upload_post","parameters":[{"name":"raw_data_id","in":"path","required":true,"schema":{"type":"string","title":"Raw Data Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfirmRawDataUploadRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RawData"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/raw_data":{"get":{"tags":["Raw Data"],"summary":"List raw-data records for a project","description":"List a project's raw-data records, newest first.","operationId":"list_raw_data_raw_data_get","parameters":[{"name":"project_id","in":"query","required":true,"schema":{"type":"string","description":"Filter by owning project ID","title":"Project Id"},"description":"Filter by owning project ID"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":100,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_RawData_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/raw_data/scan":{"post":{"tags":["Raw Data"],"summary":"Scan for unprocessed raw data and queue it for ingestion","description":"Queue every not-yet-processed raw-data record in a project.\n\nDesigned to be called on a schedule. Returns immediately after enqueuing;\nparsing and validation happen on the task worker. Safe to call\nconcurrently — each record is claimed before it is enqueued, so overlapping\nruns cannot process the same file twice.","operationId":"scan_raw_data_raw_data_scan_post","parameters":[{"name":"project_id","in":"query","required":true,"schema":{"type":"string","description":"Project to scan","title":"Project Id"},"description":"Project to scan"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScanResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/raw_data/needs-review":{"get":{"tags":["Raw Data"],"summary":"List raw-data records awaiting review","description":"List records parked on validation findings a human must resolve.","operationId":"list_needs_review_raw_data_needs_review_get","parameters":[{"name":"project_id","in":"query","required":true,"schema":{"type":"string","description":"Project to list","title":"Project Id"},"description":"Project to list"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":100,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_RawData_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/raw_data/{raw_data_id}/issues":{"get":{"tags":["Raw Data"],"summary":"List a raw-data record's validation findings","description":"List every validation finding recorded for this record.\n\nEach finding reports the choices it supports in ``options``, so a client\nrenders the reviewer's buttons without a per-code table of its own.\n\nThe record's ingestion state — ``processing_status``, ``reader``,\n``processed_at``, ``processing_error`` — is on the record itself and comes\nback from ``GET /raw_data/{raw_data_id}``; it is not duplicated here.","operationId":"list_raw_data_issues_raw_data__raw_data_id__issues_get","parameters":[{"name":"raw_data_id","in":"path","required":true,"schema":{"type":"string","title":"Raw Data Id"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":100,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_RawDataIssue_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true},"patch":{"tags":["Raw Data"],"summary":"Resolve several validation issues at once","description":"Apply a reviewer's answers to several findings in one request.\n\nEvery choice is validated before any is written, so an invalid option in\nthe batch rejects the whole request rather than half-applying it. The\nresponse reports whether the file is now ready to retry.","operationId":"resolve_raw_data_issues_raw_data__raw_data_id__issues_patch","parameters":[{"name":"raw_data_id","in":"path","required":true,"schema":{"type":"string","title":"Raw Data Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResolveIssuesRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResolveIssuesResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/raw_data/{raw_data_id}/issues/{issue_id}":{"patch":{"tags":["Raw Data"],"summary":"Resolve a validation issue","description":"Accept or reject one finding.\n\nAccepting stops the finding blocking ingestion (re-parsing unchanged data\nre-reports it, so it is not suppressed); rejecting abandons the file.\nBlocking findings cannot be resolved — the file could not be parsed, so no\ndecision makes it usable.","operationId":"resolve_raw_data_issue_raw_data__raw_data_id__issues__issue_id__patch","parameters":[{"name":"raw_data_id","in":"path","required":true,"schema":{"type":"string","title":"Raw Data Id"}},{"name":"issue_id","in":"path","required":true,"schema":{"type":"string","title":"Issue Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResolveIssueRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RawDataIssue"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/raw_data/{raw_data_id}/retry":{"post":{"tags":["Raw Data"],"summary":"Re-queue a reviewed raw-data record for ingestion","description":"Return the record to the pending pool so the next scan picks it up.\n\nRequires every ``needs_input`` finding to have a decision first.","operationId":"retry_raw_data_raw_data__raw_data_id__retry_post","parameters":[{"name":"raw_data_id","in":"path","required":true,"schema":{"type":"string","title":"Raw Data Id"}}],"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/raw_data/{raw_data_id}":{"get":{"tags":["Raw Data"],"summary":"Get a raw-data record","description":"Retrieve a single raw-data record by ID.","operationId":"get_raw_data_raw_data__raw_data_id__get","parameters":[{"name":"raw_data_id","in":"path","required":true,"schema":{"type":"string","title":"Raw Data Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RawData"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true},"patch":{"tags":["Raw Data"],"summary":"Update a raw-data record's metadata","description":"Update name/metadata. Does not replace the file.","operationId":"update_raw_data_raw_data__raw_data_id__patch","parameters":[{"name":"raw_data_id","in":"path","required":true,"schema":{"type":"string","title":"Raw Data Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateRawData"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RawData"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true},"delete":{"tags":["Raw Data"],"summary":"Delete a raw-data record","description":"Delete a raw-data record and its file.","operationId":"delete_raw_data_raw_data__raw_data_id__delete","parameters":[{"name":"raw_data_id","in":"path","required":true,"schema":{"type":"string","title":"Raw Data Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/raw_data/{raw_data_id}/download-url":{"get":{"tags":["Raw Data"],"summary":"Get a signed download URL for a raw-data file","description":"Return ``{\"url\": \"...\"}`` — a signed URL valid for 5 minutes.","operationId":"get_raw_data_download_url_raw_data__raw_data_id__download_url_get","parameters":[{"name":"raw_data_id","in":"path","required":true,"schema":{"type":"string","title":"Raw Data Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/raw_data/{raw_data_id}/cell_measurements":{"get":{"tags":["Raw Data"],"summary":"List measurement IDs produced from a raw-data record","description":"Reverse provenance read: measurements linked to this raw-data record.","operationId":"list_raw_data_measurements_raw_data__raw_data_id__cell_measurements_get","parameters":[{"name":"raw_data_id","in":"path","required":true,"schema":{"type":"string","title":"Raw Data Id"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":100,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_str_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/cell_components":{"post":{"tags":["Cell Components"],"summary":"Create a new cell component for the current organization","description":"Create a new cell component for the current organization.","operationId":"create_cell_component_cell_components_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCellComponent"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CellComponent"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true},"get":{"tags":["Cell Components"],"summary":"List cell components for the current organization scoped to a project","description":"Retrieve cell components for the current organization scoped to a project.","operationId":"list_cell_components_cell_components_get","parameters":[{"name":"project_id","in":"query","required":true,"schema":{"type":"string","description":"Project to scope components to","title":"Project Id"},"description":"Project to scope components to"},{"name":"component_type","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/ComponentType"},{"type":"null"}],"description":"Filter by component type","title":"Component Type"},"description":"Filter by component type"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CellComponent"},"title":"Response List Cell Components Cell Components Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/cell_components/{component_id}":{"get":{"tags":["Cell Components"],"summary":"Get a specific cell component by ID","description":"Retrieve a specific cell component by its ID.\n\nReturns components from the current organization only.","operationId":"get_cell_component_cell_components__component_id__get","parameters":[{"name":"component_id","in":"path","required":true,"schema":{"type":"string","title":"Component Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CellComponent"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true},"patch":{"tags":["Cell Components"],"summary":"Update a cell component by ID","description":"Update an existing cell component identified by its ID.\n\nOnly components in the current organization can be updated.","operationId":"update_cell_component_cell_components__component_id__patch","parameters":[{"name":"component_id","in":"path","required":true,"schema":{"type":"string","title":"Component Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCellComponent"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CellComponent"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true},"delete":{"tags":["Cell Components"],"summary":"Delete a cell component by ID","description":"Delete a cell component identified by its ID.\n\nOnly components in the current organization can be deleted.","operationId":"delete_cell_component_cell_components__component_id__delete","parameters":[{"name":"component_id","in":"path","required":true,"schema":{"type":"string","title":"Component Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/programs":{"post":{"tags":["Programs"],"summary":"Create a new program","description":"Create a new lab test program for the current organization.\n\nReturns the created program and sets the Location header.","operationId":"create_program_programs_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Raw Data"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Program"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false},"get":{"tags":["Programs"],"summary":"List programs","description":"List lab test programs for the current organization, with pagination.","operationId":"list_programs_programs_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":1000,"minimum":1,"default":100,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"order_by","in":"query","required":false,"schema":{"enum":["name","created_at","updated_at"],"type":"string","default":"name","title":"Order By"}},{"name":"order","in":"query","required":false,"schema":{"enum":["asc","desc"],"type":"string","default":"asc","title":"Order"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/programs/{program_id}":{"get":{"tags":["Programs"],"summary":"Get a specific program by id","description":"Retrieve a specific lab test program by its ID, scoped to the org.","operationId":"get_program_programs__program_id__get","parameters":[{"name":"program_id","in":"path","required":true,"schema":{"type":"string","title":"Program Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Program"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false},"patch":{"tags":["Programs"],"summary":"Update a specific program by id","description":"Update an existing lab test program identified by its ID.\n\nOnly provided fields will be updated.","operationId":"update_program_programs__program_id__patch","parameters":[{"name":"program_id","in":"path","required":true,"schema":{"type":"string","title":"Program Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Raw Data"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Program"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false},"delete":{"tags":["Programs"],"summary":"Delete a specific program by id","description":"Delete an existing lab test program identified by its ID.\n\nPlanned measurements and cell measurements referencing this program have\ntheir ``program_id`` set to null (``ON DELETE SET NULL``); they are not\notherwise affected.","operationId":"delete_program_programs__program_id__delete","parameters":[{"name":"program_id","in":"path","required":true,"schema":{"type":"string","title":"Program Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/sites/{site_id}/cyclers":{"post":{"tags":["Sites","Cyclers"],"summary":"Create a new cycler for a site","description":"Create a new cycler under the specified site (by ID).\n\nThe request body must include ``project_id`` — the project that will own this\ncycler. The site is org-scoped (cross-project), so any of the org's sites may\nhost a cycler for any of its projects. Returns the created cycler and sets the\nLocation header.","operationId":"create_cycler_sites__site_id__cyclers_post","parameters":[{"name":"site_id","in":"path","required":true,"schema":{"type":"string","title":"Site Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Raw Data"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Cycler"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false},"get":{"tags":["Sites","Cyclers"],"summary":"List cyclers for a site","description":"List cyclers for a site with pagination and filtering.\n\nFilters follow each field's policy in ``_CYCLER_FILTERS``: text fields take\n``ilike.%value%``, ``project_id`` is exact-only, date fields take\n``gte.value``/``lte.value``, ``created_at_gt``/``_lt`` bound a range, and\n``calibration_due_at_lt`` finds cyclers due before a date. ``q`` is the\nsearch box's free-text param and composes with all of them.","operationId":"list_cyclers_for_site_sites__site_id__cyclers_get","parameters":[{"name":"site_id","in":"path","required":true,"schema":{"type":"string","title":"Site Id"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":1000,"minimum":1,"default":100,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Free-text search on cycler name plus prefix full-text match, matching the global search. Composes with the column filters.","title":"Q"},"description":"Free-text search on cycler name plus prefix full-text match, matching the global search. Composes with the column filters."},{"name":"id_text","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Id Text"}},{"name":"project_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Id"}},{"name":"name","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"}},{"name":"manufacturer","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Manufacturer"}},{"name":"model","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model"}},{"name":"version","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Version"}},{"name":"serial_number","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Serial Number"}},{"name":"firmware_version","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Firmware Version"}},{"name":"hostname","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Hostname"}},{"name":"created_by_email","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created By Email"}},{"name":"created_at","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At"}},{"name":"created_at_gt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At Gt"}},{"name":"created_at_lt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At Lt"}},{"name":"updated_at","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated At"}},{"name":"updated_at_gt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated At Gt"}},{"name":"updated_at_lt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated At Lt"}},{"name":"calibration_due_at","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Calibration Due At"}},{"name":"calibration_due_at_gt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Calibration Due At Gt"}},{"name":"calibration_due_at_lt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Calibration Due At Lt"}},{"name":"order_by","in":"query","required":false,"schema":{"enum":["name","manufacturer","model","version","serial_number","firmware_version","hostname","last_calibrated_at","calibration_due_at","created_at","updated_at"],"type":"string","default":"created_at","title":"Order By"}},{"name":"order","in":"query","required":false,"schema":{"enum":["asc","desc"],"type":"string","default":"desc","title":"Order"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/sites/{site_id}/thermal_chambers":{"post":{"tags":["Sites","Thermal chambers"],"summary":"Create a new thermal chamber for a site","description":"Create a new thermal chamber under the specified site (by ID).\n\nThe request body must include ``project_id`` — the project that will own this\nchamber — and both temperature bounds. The site is org-scoped\n(cross-project), so any of the org's sites may host a chamber for any of its\nprojects. Returns the created chamber and sets the Location header.","operationId":"create_thermal_chamber_sites__site_id__thermal_chambers_post","parameters":[{"name":"site_id","in":"path","required":true,"schema":{"type":"string","title":"Site Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Raw Data"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ThermalChamber"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false},"get":{"tags":["Sites","Thermal chambers"],"summary":"List thermal chambers for a site","description":"List thermal chambers for a site with pagination and filtering.\n\nFilter parameters support Supabase filter operators, per the field's\ndeclared policy in ``_THERMAL_CHAMBER_FILTERS``:\n- Text fields (name, id_text, manufacturer, model, serial_number,\n  created_by_email): use ``ilike.%value%`` for partial match\n- Exact fields (project_id): literal equality; operator syntax is rejected\n- Date fields: use ``gte.value``, ``lte.value``, etc.\n- Date range: use created_at_gt and created_at_lt for between queries","operationId":"list_thermal_chambers_for_site_sites__site_id__thermal_chambers_get","parameters":[{"name":"site_id","in":"path","required":true,"schema":{"type":"string","title":"Site Id"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":1000,"minimum":1,"default":100,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"id_text","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Id Text"}},{"name":"project_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Id"}},{"name":"name","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"}},{"name":"manufacturer","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Manufacturer"}},{"name":"model","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model"}},{"name":"serial_number","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Serial Number"}},{"name":"created_by_email","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created By Email"}},{"name":"created_at","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At"}},{"name":"created_at_gt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At Gt"}},{"name":"created_at_lt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At Lt"}},{"name":"updated_at","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated At"}},{"name":"updated_at_gt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated At Gt"}},{"name":"updated_at_lt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated At Lt"}},{"name":"order_by","in":"query","required":false,"schema":{"enum":["name","manufacturer","model","serial_number","min_temperature_c","max_temperature_c","created_at","updated_at"],"type":"string","default":"created_at","title":"Order By"}},{"name":"order","in":"query","required":false,"schema":{"enum":["asc","desc"],"type":"string","default":"desc","title":"Order"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/sites":{"post":{"tags":["Sites"],"summary":"Create a new site","description":"Create a new site for the current organization.\n\nReturns the created site and sets the Location header.","operationId":"create_site_sites_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Raw Data"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Site"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false},"get":{"tags":["Sites"],"summary":"List sites","description":"List sites with pagination and filtering.\n\nFilter parameters support Supabase filter operators:\n- Text fields (name, id_text, location, created_by_email): use\n  ``ilike.%value%`` for partial match\n- Date fields: use ``gte.value``, ``lte.value``, etc.\n- Date range: use created_at_gt and created_at_lt for between queries","operationId":"list_sites_sites_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":1000,"minimum":1,"default":100,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"id_text","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Id Text"}},{"name":"name","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"}},{"name":"location","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Location"}},{"name":"created_by_email","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created By Email"}},{"name":"created_at","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At"}},{"name":"created_at_gt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At Gt"}},{"name":"created_at_lt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At Lt"}},{"name":"updated_at","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated At"}},{"name":"updated_at_gt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated At Gt"}},{"name":"updated_at_lt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated At Lt"}},{"name":"order_by","in":"query","required":false,"schema":{"enum":["name","location","created_at","updated_at"],"type":"string","default":"created_at","title":"Order By"}},{"name":"order","in":"query","required":false,"schema":{"enum":["asc","desc"],"type":"string","default":"desc","title":"Order"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/sites/{site_id}":{"get":{"tags":["Sites"],"summary":"Get a specific site by id","description":"Retrieve a specific site by its ID, scoped to the selected org.","operationId":"get_site_sites__site_id__get","parameters":[{"name":"site_id","in":"path","required":true,"schema":{"type":"string","title":"Site Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Site"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false},"patch":{"tags":["Sites"],"summary":"Update a specific site by id","description":"Update an existing site identified by its ID.\n\nOnly provided fields will be updated.","operationId":"update_site_sites__site_id__patch","parameters":[{"name":"site_id","in":"path","required":true,"schema":{"type":"string","title":"Site Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Raw Data"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Site"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false},"delete":{"tags":["Sites"],"summary":"Delete a specific site by id","description":"Delete an existing site identified by its ID.\n\nForeign-key cascade drops child cyclers and their channels\n(sites -> cyclers -> channels).","operationId":"delete_site_sites__site_id__delete","parameters":[{"name":"site_id","in":"path","required":true,"schema":{"type":"string","title":"Site Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/cyclers/{cycler_id}/channels":{"post":{"tags":["Cyclers","Channels"],"summary":"Create a new channel for a cycler","description":"Create a new channel under the specified cycler (by ID).\n\nReturns the created channel and sets the Location header.","operationId":"create_channel_cyclers__cycler_id__channels_post","parameters":[{"name":"cycler_id","in":"path","required":true,"schema":{"type":"string","title":"Cycler Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Raw Data"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Channel"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false},"get":{"tags":["Cyclers","Channels"],"summary":"List channels for a cycler","description":"List channels for a cycler with pagination and filtering.\n\nFilter parameters support Supabase filter operators:\n- Text fields (name, id_text, created_by_email): use ``ilike.%value%`` for\n  partial match\n- Date fields: use ``gte.value``, ``lte.value``, etc.\n- Date range: use created_at_gt and created_at_lt for between queries\n\n``q`` is the free-text search box's param: it narrows on channel name substring\nplus a prefix full-text match over ``search_vector``, and composes with the\ncolumn filters above.","operationId":"list_channels_for_cycler_cyclers__cycler_id__channels_get","parameters":[{"name":"cycler_id","in":"path","required":true,"schema":{"type":"string","title":"Cycler Id"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":1000,"minimum":1,"default":100,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Free-text search on channel name plus prefix full-text match, matching the global search. Composes with the column filters.","title":"Q"},"description":"Free-text search on channel name plus prefix full-text match, matching the global search. Composes with the column filters."},{"name":"id_text","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Id Text"}},{"name":"name","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"}},{"name":"created_by_email","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created By Email"}},{"name":"created_at","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At"}},{"name":"created_at_gt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At Gt"}},{"name":"created_at_lt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At Lt"}},{"name":"updated_at","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated At"}},{"name":"updated_at_gt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated At Gt"}},{"name":"updated_at_lt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated At Lt"}},{"name":"order_by","in":"query","required":false,"schema":{"enum":["name","created_at","updated_at"],"type":"string","default":"created_at","title":"Order By"}},{"name":"order","in":"query","required":false,"schema":{"enum":["asc","desc"],"type":"string","default":"desc","title":"Order"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/cyclers":{"get":{"tags":["Cyclers"],"summary":"List cyclers","description":"List cyclers with pagination and filtering.\n\nFilters follow each field's policy in ``_CYCLER_FILTERS``: text fields take\n``ilike.%value%``, ``site_id``/``project_id`` are exact-only, date fields\ntake ``gte.value``/``lte.value``, ``created_at_gt``/``_lt`` bound a range,\nand ``calibration_due_at_lt`` finds cyclers due before a date. ``q`` is the\nsearch box's free-text param and composes with all of them.","operationId":"list_cyclers_cyclers_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":1000,"minimum":1,"default":100,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Free-text search on cycler name plus prefix full-text match, matching the global search. Composes with the column filters.","title":"Q"},"description":"Free-text search on cycler name plus prefix full-text match, matching the global search. Composes with the column filters."},{"name":"id_text","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Id Text"}},{"name":"site_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Site Id"}},{"name":"project_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Id"}},{"name":"name","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"}},{"name":"manufacturer","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Manufacturer"}},{"name":"model","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model"}},{"name":"version","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Version"}},{"name":"serial_number","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Serial Number"}},{"name":"firmware_version","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Firmware Version"}},{"name":"hostname","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Hostname"}},{"name":"created_by_email","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created By Email"}},{"name":"created_at","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At"}},{"name":"created_at_gt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At Gt"}},{"name":"created_at_lt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At Lt"}},{"name":"updated_at","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated At"}},{"name":"updated_at_gt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated At Gt"}},{"name":"updated_at_lt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated At Lt"}},{"name":"calibration_due_at","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Calibration Due At"}},{"name":"calibration_due_at_gt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Calibration Due At Gt"}},{"name":"calibration_due_at_lt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Calibration Due At Lt"}},{"name":"order_by","in":"query","required":false,"schema":{"enum":["name","manufacturer","model","version","serial_number","firmware_version","hostname","last_calibrated_at","calibration_due_at","created_at","updated_at"],"type":"string","default":"created_at","title":"Order By"}},{"name":"order","in":"query","required":false,"schema":{"enum":["asc","desc"],"type":"string","default":"desc","title":"Order"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/cyclers/{cycler_id}":{"get":{"tags":["Cyclers"],"summary":"Get a specific cycler by id","description":"Retrieve a specific cycler by its ID, scoped to the selected org.","operationId":"get_cycler_cyclers__cycler_id__get","parameters":[{"name":"cycler_id","in":"path","required":true,"schema":{"type":"string","title":"Cycler Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Cycler"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false},"patch":{"tags":["Cyclers"],"summary":"Update a specific cycler by id","description":"Update an existing cycler identified by its ID.\n\nOnly provided fields will be updated.","operationId":"update_cycler_cyclers__cycler_id__patch","parameters":[{"name":"cycler_id","in":"path","required":true,"schema":{"type":"string","title":"Cycler Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Raw Data"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Cycler"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false},"delete":{"tags":["Cyclers"],"summary":"Delete a specific cycler by id","description":"Delete an existing cycler identified by its ID.\n\nForeign-key cascade drops child channels (cyclers -> channels).","operationId":"delete_cycler_cyclers__cycler_id__delete","parameters":[{"name":"cycler_id","in":"path","required":true,"schema":{"type":"string","title":"Cycler Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/cyclers/{cycler_id}/service_events":{"get":{"tags":["Cyclers"],"summary":"List a cycler's service history","description":"List the cycler's service events, most recently created first.\n\nAn event with a null ``performed_at`` is the cycler's current service; at\nmost one can exist. Completing a ``calibration`` event is what advances the\ncycler's ``last_calibrated_at`` and therefore its ``calibration_due_at``.","operationId":"list_cycler_service_events_cyclers__cycler_id__service_events_get","parameters":[{"name":"cycler_id","in":"path","required":true,"schema":{"type":"string","title":"Cycler Id"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":20,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false},"post":{"tags":["Cyclers"],"summary":"Take a cycler out of service for planned work","description":"Open a service event, taking every channel on the cycler out of service.\n\nOne call replaces taking each channel out individually: calibration is\nperformed on the instrument, so the whole cycler goes down as one event and\ncomes back as one. Channels already out of service keep their existing\nincident (a broken relay is more specific than \"being serviced\").\n\nRejected with 409 if the cycler already has an open event, or if any channel\nstill has a running measurement.","operationId":"open_cycler_service_event_cyclers__cycler_id__service_events_post","parameters":[{"name":"cycler_id","in":"path","required":true,"schema":{"type":"string","title":"Cycler Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Raw Data"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CyclerServiceEvent"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/cyclers/{cycler_id}/service_events/open":{"get":{"tags":["Cyclers"],"summary":"Get a cycler's open service event, if any","description":"Return the cycler's current service, or ``null`` when it is in service.\n\nA dedicated read rather than making the caller scan the history: that list is\nordered newest-created first and paginated, so an event recorded after the\nfact sorts ahead of an older open one and would eventually hide it — the\ncycler would read as in service while it is out. At most one open event can\nexist, so this is exact.","operationId":"get_open_cycler_service_event_cyclers__cycler_id__service_events_open_get","parameters":[{"name":"cycler_id","in":"path","required":true,"schema":{"type":"string","title":"Cycler Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/cyclers/{cycler_id}/service_events/complete":{"post":{"tags":["Cyclers"],"summary":"Record a cycler's open service as done","description":"Record service as done on a cycler.\n\nTwo paths behind one endpoint, chosen by whether the cycler is currently out\nof service:\n\n- **Open event** (it was taken out first): that event is completed and every\n  channel incident pointing at it is closed in one write, so the cycler\n  cannot end up half returned to service.\n- **No open event**: the common case of \"I calibrated this, log it\". A\n  single already-completed event is recorded from the request's\n  ``event_type``. Nothing was taken out, so nothing needs returning, and no\n  one has to open an event purely so it can be closed.\n\nEither way a ``calibration`` advances ``last_calibrated_at`` — the only\nsupported way that field moves — and optionally updates\n``calibration_interval_days``.\n\nAddressed by cycler rather than by event id because a cycler has at most one\nopen event: the caller already knows which cycler it serviced, and looking\nup the event id first would be a round-trip that proves nothing.","operationId":"complete_cycler_service_event_cyclers__cycler_id__service_events_complete_post","parameters":[{"name":"cycler_id","in":"path","required":true,"schema":{"type":"string","title":"Cycler Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Raw Data"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CyclerServiceEvent"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/channels":{"get":{"tags":["Channels"],"summary":"List channels","description":"List channels with pagination and filtering.\n\nFilter parameters support Supabase filter operators:\n- Text fields (name, id_text, created_by_email): use ``ilike.%value%`` for\n  partial match\n- Date fields: use ``gte.value``, ``lte.value``, etc.\n- Date range: use created_at_gt and created_at_lt for between queries\n\n``q`` is the free-text search box's param: it narrows on channel name substring\nplus a prefix full-text match over ``search_vector``, and composes with the\ncolumn filters above.","operationId":"list_channels_channels_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":1000,"minimum":1,"default":100,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Free-text search on channel name plus prefix full-text match, matching the global search. Composes with the column filters.","title":"Q"},"description":"Free-text search on channel name plus prefix full-text match, matching the global search. Composes with the column filters."},{"name":"id_text","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Id Text"}},{"name":"cycler_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cycler Id"}},{"name":"name","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"}},{"name":"created_by_email","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created By Email"}},{"name":"created_at","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At"}},{"name":"created_at_gt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At Gt"}},{"name":"created_at_lt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At Lt"}},{"name":"updated_at","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated At"}},{"name":"updated_at_gt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated At Gt"}},{"name":"updated_at_lt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated At Lt"}},{"name":"order_by","in":"query","required":false,"schema":{"enum":["name","created_at","updated_at"],"type":"string","default":"created_at","title":"Order By"}},{"name":"order","in":"query","required":false,"schema":{"enum":["asc","desc"],"type":"string","default":"desc","title":"Order"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/channels/{channel_id}":{"get":{"tags":["Channels"],"summary":"Get a specific channel by id","description":"Retrieve a specific channel by its ID, scoped to the selected org.","operationId":"get_channel_channels__channel_id__get","parameters":[{"name":"channel_id","in":"path","required":true,"schema":{"type":"string","title":"Channel Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Channel"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false},"patch":{"tags":["Channels"],"summary":"Update a specific channel by id","description":"Update an existing channel identified by its ID.\n\nOnly provided fields will be updated. Taking a channel out of service (or\nreturning it) also records an outage span; ``user_id`` is threaded through so\nthe incident records who did it.","operationId":"update_channel_channels__channel_id__patch","parameters":[{"name":"channel_id","in":"path","required":true,"schema":{"type":"string","title":"Channel Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Raw Data"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Channel"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false},"delete":{"tags":["Channels"],"summary":"Delete a specific channel by id","description":"Delete an existing channel identified by its ID.\n\nDeleting a channel nulls ``cell_measurements.channel_id`` on any referencing\nmeasurements (they are not deleted).","operationId":"delete_channel_channels__channel_id__delete","parameters":[{"name":"channel_id","in":"path","required":true,"schema":{"type":"string","title":"Channel Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/channels/{channel_id}/incidents":{"get":{"tags":["Channels"],"summary":"List a channel's out-of-service history","description":"List the channel's outage spans, most recently started first.\n\nAn open incident (``resolved_at`` null) is the channel's current outage;\nat most one can exist. Rows with ``is_estimated`` true were reconstructed\nfrom the channel's last-modified time when outage history was introduced, so\ntheir ``started_at`` is an upper bound rather than a recorded event.","operationId":"list_channel_incidents_channels__channel_id__incidents_get","parameters":[{"name":"channel_id","in":"path","required":true,"schema":{"type":"string","title":"Channel Id"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":20,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/thermal_chambers":{"get":{"tags":["Thermal chambers"],"summary":"List thermal chambers","description":"List thermal chambers with pagination and filtering.\n\nFilter parameters support Supabase filter operators:\n- Text fields (name, id_text, manufacturer, model, serial_number,\n  created_by_email): use ``ilike.%value%`` for partial match\n- Exact-match fields (site_id, project_id): equality filter\n- Date fields: use ``gte.value``, ``lte.value``, etc.\n- Date range: use created_at_gt and created_at_lt for between queries","operationId":"list_thermal_chambers_thermal_chambers_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":1000,"minimum":1,"default":100,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"id_text","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Id Text"}},{"name":"site_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Site Id"}},{"name":"project_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Id"}},{"name":"name","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"}},{"name":"manufacturer","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Manufacturer"}},{"name":"model","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model"}},{"name":"serial_number","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Serial Number"}},{"name":"created_by_email","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created By Email"}},{"name":"created_at","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At"}},{"name":"created_at_gt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At Gt"}},{"name":"created_at_lt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At Lt"}},{"name":"updated_at","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated At"}},{"name":"updated_at_gt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated At Gt"}},{"name":"updated_at_lt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated At Lt"}},{"name":"order_by","in":"query","required":false,"schema":{"enum":["name","manufacturer","model","serial_number","min_temperature_c","max_temperature_c","created_at","updated_at"],"type":"string","default":"created_at","title":"Order By"}},{"name":"order","in":"query","required":false,"schema":{"enum":["asc","desc"],"type":"string","default":"desc","title":"Order"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/thermal_chambers/{thermal_chamber_id}":{"get":{"tags":["Thermal chambers"],"summary":"Get a specific thermal chamber by id","description":"Retrieve a specific thermal chamber by its ID, scoped to the selected org.","operationId":"get_thermal_chamber_thermal_chambers__thermal_chamber_id__get","parameters":[{"name":"thermal_chamber_id","in":"path","required":true,"schema":{"type":"string","title":"Thermal Chamber Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ThermalChamber"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false},"patch":{"tags":["Thermal chambers"],"summary":"Update a specific thermal chamber by id","description":"Update an existing thermal chamber identified by its ID.\n\nOnly provided fields will be updated. The service validates the *merged*\ntemperature bounds against the stored row, so a PATCH sending only one bound\ncannot leave the chamber with an inverted range.","operationId":"update_thermal_chamber_thermal_chambers__thermal_chamber_id__patch","parameters":[{"name":"thermal_chamber_id","in":"path","required":true,"schema":{"type":"string","title":"Thermal Chamber Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Raw Data"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ThermalChamber"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false},"delete":{"tags":["Thermal chambers"],"summary":"Delete a specific thermal chamber by id","description":"Delete a thermal chamber by its ID.\n\nNothing references a thermal chamber yet, so the delete is unconditional —\nthere is no child row to cascade and no measurement history to strand.","operationId":"delete_thermal_chamber_thermal_chambers__thermal_chamber_id__delete","parameters":[{"name":"thermal_chamber_id","in":"path","required":true,"schema":{"type":"string","title":"Thermal Chamber Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/simulations":{"get":{"tags":["Simulations"],"summary":"List Simulations","description":"List simulations filtered by a parameterized model, study, or protocol.\n\nExactly one of ``parameterized_model_id``, ``study_id``, or\n``experiment_template_id`` must be provided. Returns simulation summaries\nwithout simulation_data, plus a map of model scalar parameters\ndeduplicated by parameterized_model_id.\n\nParameters\n----------\nparameterized_model_id : str, optional\n    Filter simulations belonging to this parameterized model.\nstudy_id : str, optional\n    Filter simulations assigned to this study.\nexperiment_template_id : str, optional\n    Filter simulations whose experiment references this protocol template.\nlimit : int, optional\n    Maximum number of results to return. Must be between 1 and 1000. Defaults to 100.\noffset : int, optional\n    Number of results to skip for pagination. Must be >= 0. Defaults to 0.\nstatus : str, optional\n    PostgREST filter expression on the simulation's job status, e.g.\n    ``\"eq.completed\"`` or ``\"in.(pending,processing,waiting)\"``. When\n    provided, only simulations whose job matches are returned.\nmodel_name, protocol_name : str, optional\n    Exact-match expressions (e.g. ``\"eq.My model\"``) on the joined\n    parameterized model name and protocol (experiment template) name. A\n    simulation has no name of its own, so these two are what identify it.\ncreated_at_gt, created_at_lt, updated_at_gt, updated_at_lt : str, optional\n    ISO datetime strings for date-range (between) filtering on the native\n    ``created_at`` / ``updated_at`` columns.\n\nReturns\n-------\nListSimulationsResponse\n    Simulations, model scalar parameters map, and total count.","operationId":"list_simulations_simulations_get","parameters":[{"name":"parameterized_model_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Parameterized Model Id"}},{"name":"study_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Study Id"}},{"name":"experiment_template_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Experiment Template Id"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":1000,"minimum":1,"default":100,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"}},{"name":"model_name","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model Name"}},{"name":"protocol_name","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Protocol Name"}},{"name":"created_at_gt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At Gt"}},{"name":"created_at_lt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At Lt"}},{"name":"updated_at_gt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated At Gt"}},{"name":"updated_at_lt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated At Lt"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListSimulationsResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/simulations/{simulation_id}/summary":{"get":{"tags":["Simulations"],"summary":"Get Simulation Summary","description":"Fetch a simulation summary without simulation_data. Suitable for list view refresh.","operationId":"get_simulation_summary_simulations__simulation_id__summary_get","parameters":[{"name":"simulation_id","in":"path","required":true,"schema":{"type":"string","title":"Simulation Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/simulations/{simulation_id}":{"get":{"tags":["Simulations"],"summary":"Get Simulation","operationId":"get_simulation_simulations__simulation_id__get","parameters":[{"name":"simulation_id","in":"path","required":true,"schema":{"type":"string","title":"Simulation Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false},"delete":{"tags":["Simulations"],"summary":"Delete Simulation","operationId":"delete_simulation_simulations__simulation_id__delete","parameters":[{"name":"simulation_id","in":"path","required":true,"schema":{"type":"string","title":"Simulation Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/simulations/experiment-options/{template_id}":{"get":{"tags":["Simulations"],"summary":"Get Experiment Options Route","description":"Get plot configuration options for a specific experiment type.\n\nParameters\n----------\ntemplate_id : str\n    The experiment template UUID\n\nReturns\n-------\ndict\n    Plot configuration options for all plot types","operationId":"get_experiment_options_route_simulations_experiment_options__template_id__get","parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/simulations/{simulation_id}/result":{"get":{"tags":["Simulations"],"summary":"Get Simulation Result","description":"Get stored results for a simulation.\n\nHandles multiple data formats:\n1. Parquet files in storage (newest format) - loaded from storage\n2. JSONB in simulation_data table (legacy) - migrated to parquet\n\nParameters\n----------\nsimulation_id : str\n    ID of the simulation\nuser_org_client : tuple[str, str | None, AsyncClient]\n    Current user_id, organization_id, and Supabase client\nsimulation_repository : SimulationRepository\n    Repository for simulations table\nsimulation_data_repository : SimulationDataRepository\n    Repository for simulation_data table (legacy)\ntarget_rows : int | None\n    If set, downsample time series to at most this many rows.\nx_min : float | None\n    Minimum Time [s] value to filter (for zoom).\nx_max : float | None\n    Maximum Time [s] value to filter (for zoom).\n\nReturns\n-------\ndict\n    Dictionary with time_series, steps, and metrics\n\nRaises\n------\nHTTPException\n    404 if no results found, 400 for other errors","operationId":"get_simulation_result_simulations__simulation_id__result_get","parameters":[{"name":"simulation_id","in":"path","required":true,"schema":{"type":"string","title":"Simulation Id"}},{"name":"target_rows","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Target Rows"}},{"name":"x_min","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"X Min"}},{"name":"x_max","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"X Max"}},{"name":"x_column","in":"query","required":false,"schema":{"type":"string","default":"Time [s]","title":"X Column"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/simulations/{simulation_id}/spatial-profile":{"get":{"tags":["Simulations"],"summary":"Get Simulation Spatial Profile","description":"Evaluate a one-dimensional spatial field from stored solution chunks.","operationId":"get_simulation_spatial_profile_simulations__simulation_id__spatial_profile_get","parameters":[{"name":"simulation_id","in":"path","required":true,"schema":{"type":"string","title":"Simulation Id"}},{"name":"variable","in":"query","required":true,"schema":{"type":"string","title":"Variable"}},{"name":"max_time_points","in":"query","required":false,"schema":{"type":"integer","maximum":1000,"minimum":2,"default":200,"title":"Max Time Points"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpatialProfile"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/simulations/{simulation_id}/cycles":{"get":{"tags":["Simulations"],"summary":"Get Simulation Cycles","description":"Get cycle-level metrics for a simulation.\n\nComputes metrics like discharge capacity, coulombic efficiency, capacity\nretention, etc. for each cycle from the steps.parquet file using\nionworksdata.cycle_metrics.get_cycle_metrics.\n\nParameters\n----------\nsimulation_id : str\n    ID of the simulation\nuser_org_client : tuple[str, str | None, AsyncClient]\n    Current user_id, organization_id, and Supabase client\nsimulation_repository : SimulationRepository\n    Repository for simulations table\nsimulation_data_repository : SimulationDataRepository\n    Repository for simulation_data table\n\nReturns\n-------\ndict\n    Dictionary with cycle metrics as lists, one value per cycle.\n    Keys include: Cycle number, Discharge capacity [A.h],\n    Charge capacity [A.h], Coulombic efficiency, Capacity retention, etc.\n\nRaises\n------\nHTTPException\n    404 if no results found, 500 for computation errors","operationId":"get_simulation_cycles_simulations__simulation_id__cycles_get","parameters":[{"name":"simulation_id","in":"path","required":true,"schema":{"type":"string","title":"Simulation Id"}},{"name":"max_points","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":1},{"type":"null"}],"description":"Maximum rows of the cycle series","title":"Max Points"},"description":"Maximum rows of the cycle series"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/simulations/{simulation_id}/evaluate":{"post":{"tags":["Simulations"],"summary":"Evaluate Simulation Variables","description":"Evaluate specific variables from a simulation.\n\nThis endpoint supports lazy variable evaluation:\n- If UCPSolution exists in storage: returns variables already in parquet\n- If only simulation_data exists and variables are present: returns from database\n- If variables are missing: triggers a re-run job (returns 202 Accepted)\n\nParameters\n----------\nsimulation_id : str\n    ID of the simulation\nbody : EvaluateVariablesRequest\n    Request body with list of variable names to evaluate\n\nReturns\n-------\ndict\n    Dictionary with time_series, steps, and metrics\n\nRaises\n------\nHTTPException\n    202 if re-run is triggered (includes job_id in detail)\n    404 if simulation not found","operationId":"evaluate_simulation_variables_simulations__simulation_id__evaluate_post","parameters":[{"name":"simulation_id","in":"path","required":true,"schema":{"type":"string","title":"Simulation Id"}},{"name":"target_rows","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":1},{"type":"null"}],"description":"Maximum rows per returned variable","title":"Target Rows"},"description":"Maximum rows per returned variable"},{"name":"x_min","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Lower x-range bound (inclusive)","title":"X Min"},"description":"Lower x-range bound (inclusive)"},{"name":"x_max","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Upper x-range bound (inclusive)","title":"X Max"},"description":"Upper x-range bound (inclusive)"},{"name":"x_column","in":"query","required":false,"schema":{"type":"string","description":"Column the window applies to","default":"Time [s]","title":"X Column"},"description":"Column the window applies to"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EvaluateVariablesRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/simulations/{simulation_id}/upgrade":{"post":{"tags":["Simulations"],"summary":"Upgrade Simulation To Ucp","description":"Explicitly upgrade a simulation to UCPSolution format.\n\nThis triggers a re-run of the simulation to generate and store the UCPSolution\nfile, enabling lazy variable evaluation for future requests.\n\nParameters\n----------\nsimulation_id : str\n    ID of the simulation to upgrade\n\nReturns\n-------\ndict\n    Status information about the upgrade\n    - If already upgraded: returns current solution_storage_path\n    - If upgrade triggered: returns 202 with job_id\n\nRaises\n------\nHTTPException\n    202 if re-run is triggered\n    404 if simulation not found","operationId":"upgrade_simulation_to_ucp_simulations__simulation_id__upgrade_post","parameters":[{"name":"simulation_id","in":"path","required":true,"schema":{"type":"string","title":"Simulation Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/simulations/batch-upgrade":{"post":{"tags":["Simulations"],"summary":"Batch Upgrade Simulations","description":"Batch upgrade simulations to the new storage format.\n\nTriggers re-runs for simulations that are still in the old format (JSONB in\nsimulation_data table) to migrate them to the new format (parquet files in\nstorage).\n\nParameters\n----------\nbody : BatchUpgradeRequest\n    List of simulation IDs to upgrade\n\nReturns\n-------\nlist[BatchUpgradeResult]\n    Results for each simulation upgrade attempt","operationId":"batch_upgrade_simulations_simulations_batch_upgrade_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchUpgradeRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/simulations/model/{parameterized_model_id}/voltage-components":{"get":{"tags":["Simulations"],"summary":"Get Voltage Component Variables","operationId":"get_voltage_component_variables_simulations_model__parameterized_model_id__voltage_components_get","parameters":[{"name":"parameterized_model_id","in":"path","required":true,"schema":{"type":"string","title":"Parameterized Model Id"}},{"name":"split_by_electrode","in":"query","required":false,"schema":{"type":"boolean","default":true,"title":"Split By Electrode"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/simulations/with-template/batch":{"post":{"tags":["Simulations"],"summary":"Create Simulation Batch With Template","description":"Optimized batch simulation creation with template-based experiments.\n\nThis endpoint is for creating multiple simulations using template-based\nexperiments with DOE support. For protocol-based batch simulations, use\nPOST /simulations/batch.\n\nReturns\n-------\nList[SimulationCreationResponse]\n    List of simulation creation responses with IDs, job info, and status\n\nRaises\n------\nHTTPException\n    If usage limit reached or job submission fails","operationId":"create_simulation_batch_with_template_simulations_with_template_batch_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSimulationBatchBody"}}},"required":true},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/SimulationCreationResponse"},"type":"array","title":"Response Create Simulation Batch With Template Simulations With Template Batch Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/simulations/statuses":{"post":{"tags":["Simulations"],"summary":"Get Statuses","operationId":"get_statuses_simulations_statuses_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobStatusesRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/SimulationStatusItem"},"type":"array","title":"Response Get Statuses Simulations Statuses Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/simulations/{simulation_id}/cancel":{"post":{"tags":["Simulations"],"summary":"Cancel Simulation","description":"Cancel a simulation job.","operationId":"cancel_simulation_simulations__simulation_id__cancel_post","parameters":[{"name":"simulation_id","in":"path","required":true,"schema":{"type":"string","title":"Simulation Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/doe/generate":{"post":{"tags":["doe"],"summary":"Generate Doe","description":"Generate design-parameter dictionaries from a DOE specification.\n\nParameters\n----------\nrequest\n    DOE request containing sampling method and per-parameter configs.\n\nReturns\n-------\nlist[dict[str, float]]\n    List of design-parameter mappings suitable for simulation conditions.","operationId":"generate_doe_doe_generate_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DOERequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"additionalProperties":{"type":"number"},"type":"object"},"type":"array","title":"Response Generate Doe Doe Generate Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/cells/{cell_spec_id}/parameterized_models/validate-parameters":{"post":{"tags":["parameterized_models"],"summary":"Validate Parameters","description":"Validate parameterized model parameters against reference values.\n\nFor each known reference parameter, computes the value implied by the\nsupplied parameter set, the reference value, the percentage deviation,\na status (``success``/``warning``/``error``), an explanatory message,\nand an optional autofix that would close the gap.","operationId":"validate_parameters_cells__cell_spec_id__parameterized_models_validate_parameters_post","parameters":[{"name":"cell_spec_id","in":"path","required":true,"schema":{"type":"string","title":"Cell Spec Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidateParametersBody"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidateParametersResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/cells/{cell_spec_id}/parameterized_models":{"get":{"tags":["parameterized_models"],"summary":"List parameterized models for a cell specification or project","description":"List parameterized models with pagination, filtering, and sorting, scoped\nby cell spec or project.\n\nProvide exactly one scope:\n\n- ``cell_spec_id`` lists models for a single cell specification. This is the\n  path parameter when called via ``/cells/{cell_spec_id}/parameterized_models``.\n- ``project_id`` lists models across every cell specification linked to the\n  project. ``cell_spec_id`` may additionally be passed to narrow a\n  project-scoped query to one cell specification.\n\nParameters\n----------\nmodel_id : str | None\n    Base model to narrow to, matched exactly. Composes with either scope —\n    e.g. every parameterized model in a project that derives from one model.\ncell_spec_id : str | None\n    Cell specification to scope to. Required when ``project_id`` is not given.\nproject_id : str | None\n    Project to scope to. When set, ``cell_spec_id`` is an optional further\n    filter rather than the primary scope.\nname : str | None\n    Column filter on the model name. Applies to both scopes. Values use\n    Supabase operator syntax and are validated by the field policy — e.g.\n    ``ilike.%alpha%`` for a case-insensitive substring match. A bare value\n    falls through to an exact match.\ndescription : str | None\n    Column filter on the model description. Same operator-syntax semantics\n    as ``name`` and likewise applies to both scopes.\nq : str | None\n    Free-text search on the model name plus a prefix full-text match,\n    matching the global search. Applies to both scopes and composes with\n    the ``name`` / ``description`` column filters.\norder_by : {\"name\", \"created_at\"}\n    Column to sort the cell-spec-scoped results by. Defaults to\n    ``\"created_at\"``.\norder : {\"asc\", \"desc\"}\n    Sort direction for the cell-spec-scoped results. Defaults to ``\"desc\"``.\nlimit : int\n    Maximum number of models to return per page (1-1000). Defaults to 100.\n    The upper bound is 1000 so callers (e.g. the optimization clone form)\n    can load every model for a project in one request.\noffset : int\n    Number of models to skip for pagination. Defaults to 0.","operationId":"list_parameterized_models_cells__cell_spec_id__parameterized_models_get","parameters":[{"name":"cell_spec_id","in":"path","required":true,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cell Spec Id"}},{"name":"project_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Id"}},{"name":"name","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"}},{"name":"description","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"}},{"name":"model_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model Id"}},{"name":"created_at_gt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At Gt"}},{"name":"created_at_lt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At Lt"}},{"name":"order_by","in":"query","required":false,"schema":{"enum":["name","created_at"],"type":"string","default":"created_at","title":"Order By"}},{"name":"order","in":"query","required":false,"schema":{"enum":["asc","desc"],"type":"string","default":"desc","title":"Order"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":1000,"minimum":1,"default":100,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Free-text search on parameterized model name.","title":"Q"},"description":"Free-text search on parameterized model name."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false},"post":{"tags":["parameterized_models"],"summary":"Create a new parameterized model for the current cell specification","operationId":"create_parameterized_model_cells__cell_spec_id__parameterized_models_post","parameters":[{"name":"cell_spec_id","in":"path","required":true,"schema":{"type":"string","title":"Cell Spec Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateParameterizedModelBody"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/cells/{cell_spec_id}/parameterized_models/{parameterized_model_id}":{"get":{"tags":["parameterized_models"],"summary":"Get a parameterized model by id","description":"Get a single parameterized model (with its model info) by id.\n\nLets clients fetch one model directly instead of listing every model\nin a project. Access is scoped by row-level security via the\nrequesting user's client.","operationId":"get_parameterized_model_cells__cell_spec_id__parameterized_models__parameterized_model_id__get","parameters":[{"name":"parameterized_model_id","in":"path","required":true,"schema":{"type":"string","title":"Parameterized Model Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false},"patch":{"tags":["parameterized_models"],"summary":"Update a parameterized model","description":"Update a parameterized model's name and/or description.","operationId":"update_parameterized_model_cells__cell_spec_id__parameterized_models__parameterized_model_id__patch","parameters":[{"name":"cell_spec_id","in":"path","required":true,"schema":{"type":"string","title":"Cell Spec Id"}},{"name":"parameterized_model_id","in":"path","required":true,"schema":{"type":"string","title":"Parameterized Model Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateParameterizedModelBody"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false},"delete":{"tags":["parameterized_models"],"summary":"Delete a parameterized model","description":"Delete a parameterized model by its ID for a given cell specification.","operationId":"delete_parameterized_model_cells__cell_spec_id__parameterized_models__parameterized_model_id__delete","parameters":[{"name":"cell_spec_id","in":"path","required":true,"schema":{"type":"string","title":"Cell Spec Id"}},{"name":"parameterized_model_id","in":"path","required":true,"schema":{"type":"string","title":"Parameterized Model Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/cells/{cell_spec_id}/parameterized_models/function-parameters/convert-json-to-string":{"post":{"tags":["parameterized_models"],"summary":"Convert Json To String","operationId":"convert_json_to_string_cells__cell_spec_id__parameterized_models_function_parameters_convert_json_to_string_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FunctionParametersConversionBody"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/cells/{cell_spec_id}/parameterized_models/function-parameters/convert-string-to-json":{"post":{"tags":["parameterized_models"],"summary":"Convert From String To Json","operationId":"convert_from_string_to_json_cells__cell_spec_id__parameterized_models_function_parameters_convert_string_to_json_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FunctionParametersConversionBody"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/cells/{cell_spec_id}/parameterized_models/{parameterized_model_id}/parameter-values":{"get":{"tags":["parameterized_models"],"summary":"Get Parameterized Model Parameter Values","description":"Get all parameter values from a parameterized model as JSON.\n\nThis endpoint returns the complete parameter set from a parameterized model,\nsuitable for use as baseline parameters in DataFit, parameterization, or\noptimization workflows. Version and citation metadata are excluded.\n\nParameters\n----------\nparameterized_model_id : str\n    ID of the parameterized model to fetch parameters from\nparameterized_models_repository : ParameterizedModelsRepository\n    Repository for parameterized model data access\n\nReturns\n-------\ndict\n    All parameterized model parameter values as JSON (excluding version and\n    citations)","operationId":"get_parameterized_model_parameter_values_cells__cell_spec_id__parameterized_models__parameterized_model_id__parameter_values_get","parameters":[{"name":"parameterized_model_id","in":"path","required":true,"schema":{"type":"string","title":"Parameterized Model Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/cells/{cell_spec_id}/parameterized_models/{parameterized_model_id}/variable-names":{"get":{"tags":["parameterized_models"],"summary":"Get Parameterized Model Variable Names","description":"Get variable names where domain is empty or current collector.\n\nThis endpoint returns the names of all variables in the model where the domain\nis empty or \"current collector\" (i.e. they are functions of time only).\n\nParameters\n----------\nparameterized_model_id : str\n    ID of the parameterized model to fetch variables from\nsupabase : Client\n    Supabase client for database access\n\nReturns\n-------\nlist[str]\n    List of variable names with empty or current collector domain","operationId":"get_parameterized_model_variable_names_cells__cell_spec_id__parameterized_models__parameterized_model_id__variable_names_get","parameters":[{"name":"parameterized_model_id","in":"path","required":true,"schema":{"type":"string","title":"Parameterized Model Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"type":"string"},"title":"Response Get Parameterized Model Variable Names Cells  Cell Spec Id  Parameterized Models  Parameterized Model Id  Variable Names Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/cells/{cell_spec_id}/parameterized_models/{parameterized_model_id}/spatial-variable-names":{"get":{"tags":["parameterized_models"],"summary":"Get Parameterized Model Spatial Variable Names","description":"Get variables that can be rendered as one-dimensional spatial profiles.","operationId":"get_parameterized_model_spatial_variable_names_cells__cell_spec_id__parameterized_models__parameterized_model_id__spatial_variable_names_get","parameters":[{"name":"parameterized_model_id","in":"path","required":true,"schema":{"type":"string","title":"Parameterized Model Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"type":"string"},"title":"Response Get Parameterized Model Spatial Variable Names Cells  Cell Spec Id  Parameterized Models  Parameterized Model Id  Spatial Variable Names Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/parameterized_models/validate-parameters":{"post":{"tags":["parameterized_models"],"summary":"Validate Parameters","description":"Validate parameterized model parameters against reference values.\n\nFor each known reference parameter, computes the value implied by the\nsupplied parameter set, the reference value, the percentage deviation,\na status (``success``/``warning``/``error``), an explanatory message,\nand an optional autofix that would close the gap.","operationId":"validate_parameters_parameterized_models_validate_parameters_post","parameters":[{"name":"cell_spec_id","in":"query","required":true,"schema":{"type":"string","title":"Cell Spec Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidateParametersBody"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidateParametersResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/parameterized_models":{"get":{"tags":["parameterized_models"],"summary":"List parameterized models for a cell specification or project","description":"List parameterized models with pagination, filtering, and sorting, scoped\nby cell spec or project.\n\nProvide exactly one scope:\n\n- ``cell_spec_id`` lists models for a single cell specification. This is the\n  path parameter when called via ``/cells/{cell_spec_id}/parameterized_models``.\n- ``project_id`` lists models across every cell specification linked to the\n  project. ``cell_spec_id`` may additionally be passed to narrow a\n  project-scoped query to one cell specification.\n\nParameters\n----------\nmodel_id : str | None\n    Base model to narrow to, matched exactly. Composes with either scope —\n    e.g. every parameterized model in a project that derives from one model.\ncell_spec_id : str | None\n    Cell specification to scope to. Required when ``project_id`` is not given.\nproject_id : str | None\n    Project to scope to. When set, ``cell_spec_id`` is an optional further\n    filter rather than the primary scope.\nname : str | None\n    Column filter on the model name. Applies to both scopes. Values use\n    Supabase operator syntax and are validated by the field policy — e.g.\n    ``ilike.%alpha%`` for a case-insensitive substring match. A bare value\n    falls through to an exact match.\ndescription : str | None\n    Column filter on the model description. Same operator-syntax semantics\n    as ``name`` and likewise applies to both scopes.\nq : str | None\n    Free-text search on the model name plus a prefix full-text match,\n    matching the global search. Applies to both scopes and composes with\n    the ``name`` / ``description`` column filters.\norder_by : {\"name\", \"created_at\"}\n    Column to sort the cell-spec-scoped results by. Defaults to\n    ``\"created_at\"``.\norder : {\"asc\", \"desc\"}\n    Sort direction for the cell-spec-scoped results. Defaults to ``\"desc\"``.\nlimit : int\n    Maximum number of models to return per page (1-1000). Defaults to 100.\n    The upper bound is 1000 so callers (e.g. the optimization clone form)\n    can load every model for a project in one request.\noffset : int\n    Number of models to skip for pagination. Defaults to 0.","operationId":"list_parameterized_models_parameterized_models_get","parameters":[{"name":"cell_spec_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cell Spec Id"}},{"name":"project_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Id"}},{"name":"name","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"}},{"name":"description","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"}},{"name":"model_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model Id"}},{"name":"created_at_gt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At Gt"}},{"name":"created_at_lt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At Lt"}},{"name":"order_by","in":"query","required":false,"schema":{"enum":["name","created_at"],"type":"string","default":"created_at","title":"Order By"}},{"name":"order","in":"query","required":false,"schema":{"enum":["asc","desc"],"type":"string","default":"desc","title":"Order"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":1000,"minimum":1,"default":100,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Free-text search on parameterized model name.","title":"Q"},"description":"Free-text search on parameterized model name."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false},"post":{"tags":["parameterized_models"],"summary":"Create a new parameterized model for the current cell specification","operationId":"create_parameterized_model_parameterized_models_post","parameters":[{"name":"cell_spec_id","in":"query","required":true,"schema":{"type":"string","title":"Cell Spec Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateParameterizedModelBody"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/parameterized_models/{parameterized_model_id}":{"get":{"tags":["parameterized_models"],"summary":"Get a parameterized model by id","description":"Get a single parameterized model (with its model info) by id.\n\nLets clients fetch one model directly instead of listing every model\nin a project. Access is scoped by row-level security via the\nrequesting user's client.","operationId":"get_parameterized_model_parameterized_models__parameterized_model_id__get","parameters":[{"name":"parameterized_model_id","in":"path","required":true,"schema":{"type":"string","title":"Parameterized Model Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false},"patch":{"tags":["parameterized_models"],"summary":"Update a parameterized model","description":"Update a parameterized model's name and/or description.","operationId":"update_parameterized_model_parameterized_models__parameterized_model_id__patch","parameters":[{"name":"parameterized_model_id","in":"path","required":true,"schema":{"type":"string","title":"Parameterized Model Id"}},{"name":"cell_spec_id","in":"query","required":true,"schema":{"type":"string","title":"Cell Spec Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateParameterizedModelBody"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false},"delete":{"tags":["parameterized_models"],"summary":"Delete a parameterized model","description":"Delete a parameterized model by its ID for a given cell specification.","operationId":"delete_parameterized_model_parameterized_models__parameterized_model_id__delete","parameters":[{"name":"parameterized_model_id","in":"path","required":true,"schema":{"type":"string","title":"Parameterized Model Id"}},{"name":"cell_spec_id","in":"query","required":true,"schema":{"type":"string","title":"Cell Spec Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/parameterized_models/function-parameters/convert-json-to-string":{"post":{"tags":["parameterized_models"],"summary":"Convert Json To String","operationId":"convert_json_to_string_parameterized_models_function_parameters_convert_json_to_string_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FunctionParametersConversionBody"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/parameterized_models/function-parameters/convert-string-to-json":{"post":{"tags":["parameterized_models"],"summary":"Convert From String To Json","operationId":"convert_from_string_to_json_parameterized_models_function_parameters_convert_string_to_json_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FunctionParametersConversionBody"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/parameterized_models/{parameterized_model_id}/parameter-values":{"get":{"tags":["parameterized_models"],"summary":"Get Parameterized Model Parameter Values","description":"Get all parameter values from a parameterized model as JSON.\n\nThis endpoint returns the complete parameter set from a parameterized model,\nsuitable for use as baseline parameters in DataFit, parameterization, or\noptimization workflows. Version and citation metadata are excluded.\n\nParameters\n----------\nparameterized_model_id : str\n    ID of the parameterized model to fetch parameters from\nparameterized_models_repository : ParameterizedModelsRepository\n    Repository for parameterized model data access\n\nReturns\n-------\ndict\n    All parameterized model parameter values as JSON (excluding version and\n    citations)","operationId":"get_parameterized_model_parameter_values_parameterized_models__parameterized_model_id__parameter_values_get","parameters":[{"name":"parameterized_model_id","in":"path","required":true,"schema":{"type":"string","title":"Parameterized Model Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/parameterized_models/{parameterized_model_id}/variable-names":{"get":{"tags":["parameterized_models"],"summary":"Get Parameterized Model Variable Names","description":"Get variable names where domain is empty or current collector.\n\nThis endpoint returns the names of all variables in the model where the domain\nis empty or \"current collector\" (i.e. they are functions of time only).\n\nParameters\n----------\nparameterized_model_id : str\n    ID of the parameterized model to fetch variables from\nsupabase : Client\n    Supabase client for database access\n\nReturns\n-------\nlist[str]\n    List of variable names with empty or current collector domain","operationId":"get_parameterized_model_variable_names_parameterized_models__parameterized_model_id__variable_names_get","parameters":[{"name":"parameterized_model_id","in":"path","required":true,"schema":{"type":"string","title":"Parameterized Model Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"type":"string"},"title":"Response Get Parameterized Model Variable Names Parameterized Models  Parameterized Model Id  Variable Names Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/parameterized_models/{parameterized_model_id}/spatial-variable-names":{"get":{"tags":["parameterized_models"],"summary":"Get Parameterized Model Spatial Variable Names","description":"Get variables that can be rendered as one-dimensional spatial profiles.","operationId":"get_parameterized_model_spatial_variable_names_parameterized_models__parameterized_model_id__spatial_variable_names_get","parameters":[{"name":"parameterized_model_id","in":"path","required":true,"schema":{"type":"string","title":"Parameterized Model Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"type":"string"},"title":"Response Get Parameterized Model Spatial Variable Names Parameterized Models  Parameterized Model Id  Spatial Variable Names Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/metadata/model":{"get":{"tags":["metadata"],"summary":"Get Model Metadata Endpoint","description":"Get model metadata by fetching config from database.\n\nParameters\n----------\nmodel_id : str\n    ID of the model\norganization_id : str\n    Organization ID (from header)\nmodel_repo : ModelRepository\n    Model repository dependency\nsupabase : Client\n    Supabase client for loading custom models from storage\n\nReturns\n-------\nModelMetadata\n    Model metadata with required parameters and groups","operationId":"get_model_metadata_endpoint_metadata_model_get","parameters":[{"name":"model_id","in":"query","required":true,"schema":{"type":"string","title":"Model Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/metadata/model-from-config":{"post":{"tags":["metadata"],"summary":"Get Model Metadata From Config","description":"Build model metadata directly from a config dict (no saved model needed).\n\nUsed during model creation to show parameters before the model is persisted.","operationId":"get_model_metadata_from_config_metadata_model_from_config_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModelConfigBody"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/metadata/model/library-parameter-sets/{library_parameter_set}":{"get":{"tags":["metadata"],"summary":"Get Model Library Parameters","operationId":"get_model_library_parameters_metadata_model_library_parameter_sets__library_parameter_set__get","parameters":[{"name":"library_parameter_set","in":"path","required":true,"schema":{"type":"string","title":"Library Parameter Set"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Get Model Library Parameters Metadata Model Library Parameter Sets  Library Parameter Set  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/metadata/cell":{"get":{"tags":["metadata"],"summary":"Get Cell Metadata Endpoint","operationId":"get_cell_metadata_endpoint_metadata_cell_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"x-hidden":true}},"/discovery/capabilities":{"get":{"tags":["discovery"],"summary":"Get Capabilities","description":"Discover platform domain context and schema references.\n\nReturns domain knowledge (battery data hierarchy, key\nconcepts), authentication requirements, and pointers to\nJSON Schema endpoints. For available API operations, see\nthe OpenAPI spec at /openapi.json.","operationId":"get_capabilities_discovery_capabilities_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"x-hidden":false}},"/discovery/schemas/data":{"get":{"tags":["discovery"],"summary":"Get Data Schema","description":"Return the schema for the cell data hierarchy.\n\nDescribes the required and optional fields for each level:\ncell_specification, cell_instance, cell_measurement, steps,\nand time_series. Useful for users or agents building upload\npayloads.","operationId":"get_data_schema_discovery_schemas_data_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"x-hidden":false}},"/discovery/schemas/protocol":{"get":{"tags":["discovery"],"summary":"Get Protocol Schema","description":"Return the Universal Cycler Protocol (UCP) authoring guide.\n\nDescribes the YAML input format (single-key dicts keyed by step\ntype), the supported step and end-condition forms, runnable\nexample protocols, and a machine-checkable JSON Schema\n(``input_schema``) for the authoring format. The JSON Schema is\ngenerated from the same enums the parser uses and is parity-tested\nagainst ``validate_protocol_from_dict``.","operationId":"get_protocol_schema_discovery_schemas_protocol_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"x-hidden":false}},"/discovery/schemas/project":{"get":{"tags":["discovery"],"summary":"Get Project Schema","description":"Return the schema for projects.\n\nIncludes ``create_schema`` (POST /projects body), ``update_schema``\n(PATCH /projects/{id} body), and ``response_schema`` (GET response).","operationId":"get_project_schema_discovery_schemas_project_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"x-hidden":false}},"/discovery/schemas/lab":{"get":{"tags":["discovery"],"summary":"Get Lab Schema","description":"Return the schema for the lab-view occupancy status.\n\nRead-only: ``response_schema`` is the GET\n``/projects/{project_id}/lab/status`` response shape. There is no\ncreate/update body (occupancy is derived, not stored).","operationId":"get_lab_schema_discovery_schemas_lab_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"x-hidden":false}},"/discovery/schemas/study":{"get":{"tags":["discovery"],"summary":"Get Study Schema","description":"Return the schema for studies.\n\nIncludes ``create_schema`` (POST body), ``update_schema``\n(PATCH body), ``response_schema`` (GET response), and\n``mapping_endpoints`` listing the assign/remove paths for\nsimulations and measurements (studies live under\n``/projects/{project_id}/studies``).","operationId":"get_study_schema_discovery_schemas_study_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"x-hidden":false}},"/discovery/schemas/model":{"get":{"tags":["discovery"],"summary":"Get Model Schema","description":"Return the schema for custom electrochemical models.\n\nIncludes ``create_schema`` (POST /models body),\n``update_schema`` (PATCH /models/{id} body),\n``response_schema`` (GET response), and\n``add_custom_variable_schema`` (POST\n/models/{id}/custom-variables body).","operationId":"get_model_schema_discovery_schemas_model_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"x-hidden":false}},"/discovery/pybamm_models":{"get":{"tags":["discovery"],"summary":"Get Pybamm Models","description":"List pybamm/ionworks model classes and options.\n\nUsed by clients to decide whether they can express their model as a\nconfig (``client.model.create``) or whether they need to upload a\ncustom ``pybamm.BaseModel`` subclass via\n``client.model.upload_custom``.","operationId":"get_pybamm_models_discovery_pybamm_models_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"x-hidden":false}},"/discovery/pybamm_models/validate":{"post":{"tags":["discovery"],"summary":"Validate Pybamm Model Config","description":"Try to instantiate a pybamm/ionworks model with the given options.\n\nLightweight check that catches bad combinations of model name + options\n*before* a record is persisted. Builds the model in-process — same code\npath ``ModelService.get_pybamm_model_from_config`` uses at simulation\ntime — and reports whether construction succeeded.\n\nOn failure the response carries the underlying exception's message\nverbatim (typically a pybamm ``OptionError`` / ``ValueError``) so the\ncaller can act on it.\n\nThe model is built and dropped; nothing is written to the database.","operationId":"validate_pybamm_model_config_discovery_pybamm_models_validate_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/_ValidatePybammModelBody"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Validate Pybamm Model Config Discovery Pybamm Models Validate Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/discovery/ionworks_models/serialize":{"post":{"tags":["discovery"],"summary":"Serialize Ionworks Model","description":"Build an ionworks model and return its pybamm ``Serialise`` JSON.\n\nLets callers without the licensed ``ionworkspipeline`` package use\nionworks models (``ECM``, ``LumpedSPMR``, ``GITTModel``, ...): the JSON\nloads with plain ``pybamm`` via ``Serialise.load_custom_model``. Standard\npybamm models are already usable directly, so requesting one returns 400.\n\nReturned verbatim because the JSON may contain ``Infinity``/``NaN``\nliterals; Python's ``json`` (and the SDK) parse these fine.","operationId":"serialize_ionworks_model_discovery_ionworks_models_serialize_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/_SerializeIonworksModelBody"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/discovery/schemas/parameterized_model":{"get":{"tags":["discovery"],"summary":"Get Parameterized Model Schema","description":"Return the schema for parameterized models.\n\nA parameterized model attaches concrete parameter values\nto a model and a cell_specification. Includes the create\nbody shape, the partial-update body shape (name and\ndescription only), and the full response shape.","operationId":"get_parameterized_model_schema_discovery_schemas_parameterized_model_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"x-hidden":false}},"/discovery/schemas/optimization":{"get":{"tags":["discovery"],"summary":"Get Optimization Schema","description":"Return the schema for design optimization runs.\n\nOptimization requests use a flat ``run`` body (top-level\n``project_id``, ``name``, ``cell_spec_id``,\n``optimization_template_id``) plus a nested ``config``\nobject validated by the design-optimization config schema.","operationId":"get_optimization_schema_discovery_schemas_optimization_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"x-hidden":false}},"/discovery/schemas/pipeline":{"get":{"tags":["discovery"],"summary":"Get Pipeline Schema","description":"Return the schema for parameterization pipelines.\n\nIncludes the pipeline config body (POST /pipelines), the\nfull pipeline response shape, and the supported element\ntypes (data_fit, array_data_fit, calculation, entry,\nbuilt_in_entry, validation).","operationId":"get_pipeline_schema_discovery_schemas_pipeline_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"x-hidden":false}},"/discovery/schemas/simple_pipeline":{"get":{"tags":["discovery"],"summary":"Get Simple Pipeline Schema","description":"Return the schema for SimplePipelines.\n\nIncludes the create body (POST /simple_pipelines), the\npartial-update body (PATCH /simple_pipelines/{id}), the\nresponse shape, and the supported element types\n(data_fit, array_data_fit, calculation, entry,\nvalidation). Also reports the at-most-one-expensive-element\nlimit.","operationId":"get_simple_pipeline_schema_discovery_schemas_simple_pipeline_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"x-hidden":false}},"/pipelines/entries":{"post":{"tags":["Pipeline"],"summary":"Run Entry","operationId":"run_entry_pipelines_entries_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EntryConfig"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EntryResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/pipelines/calculations":{"post":{"tags":["Pipeline"],"summary":"Run Calculation","operationId":"run_calculation_pipelines_calculations_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CalculationConfig"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CalculationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/pipelines/calculations/metadata":{"post":{"tags":["Pipeline"],"summary":"Get Calculation Metadata","operationId":"get_calculation_metadata_pipelines_calculations_metadata_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PipelineCalculationMetadataRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PipelineCalculationMetadataResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/pipelines/datafits":{"post":{"tags":["Pipeline"],"summary":"Run Datafit","operationId":"run_datafit_pipelines_datafits_post","parameters":[{"name":"project_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DataFitConfig"}}}},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/pipelines/datafits/{job_id}":{"get":{"tags":["Pipeline"],"summary":"Get Datafit","operationId":"get_datafit_pipelines_datafits__job_id__get","parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/JobResponse"},{"type":"null"}],"title":"Response Get Datafit Pipelines Datafits  Job Id  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/pipelines/datafits/{job_id}/result":{"get":{"tags":["Pipeline"],"summary":"Get Datafit Results","operationId":"get_datafit_results_pipelines_datafits__job_id__result_get","parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/DataFitResponse"},{"type":"null"}],"title":"Response Get Datafit Results Pipelines Datafits  Job Id  Result Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/pipelines/validations":{"post":{"tags":["Pipeline"],"summary":"Run Validation","operationId":"run_validation_pipelines_validations_post","parameters":[{"name":"project_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationConfig"}}}},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/pipelines/validations/{job_id}":{"get":{"tags":["Pipeline"],"summary":"Get Validation","operationId":"get_validation_pipelines_validations__job_id__get","parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/JobResponse"},{"type":"null"}],"title":"Response Get Validation Pipelines Validations  Job Id  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/pipelines/validations/{job_id}/result":{"get":{"tags":["Pipeline"],"summary":"Get Validation Results","operationId":"get_validation_results_pipelines_validations__job_id__result_get","parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/ValidationResponse"},{"type":"null"}],"title":"Response Get Validation Results Pipelines Validations  Job Id  Result Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/pipelines/validations/{job_id}/plot_data":{"get":{"tags":["Pipeline"],"summary":"Get Validation Plot Data","description":"Return decimated trace data for a single validation or data-fit plot.\n\nReads the stored ``validation_plot_config`` from the job's metadata blob,\nextracts the requested plot, filters to the given x-range, and downsamples\nto at most ``max_points`` per trace. Supports semantic zoom: callers refetch\nwith ``x_min``/``x_max`` set to the current viewport on each zoom event.\n\n``max_points`` is a per-trace ceiling, and a figure may hold several traces, so it\nis reduced where the whole response would otherwise exceed the payload cap — see\n``src.jobs.plot_data._payload_capped_budget``.","operationId":"get_validation_plot_data_pipelines_validations__job_id__plot_data_get","parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}},{"name":"objective_name","in":"query","required":true,"schema":{"type":"string","description":"Objective name within validation_plot_config","title":"Objective Name"},"description":"Objective name within validation_plot_config"},{"name":"plot_index","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Index into the plots list for this objective","default":0,"title":"Plot Index"},"description":"Index into the plots list for this objective"},{"name":"max_points","in":"query","required":false,"schema":{"type":"integer","maximum":80000,"minimum":100,"description":"Maximum points per trace","default":2000,"title":"Max Points"},"description":"Maximum points per trace"},{"name":"x_min","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Lower x-range bound (inclusive)","title":"X Min"},"description":"Lower x-range bound (inclusive)"},{"name":"x_max","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Upper x-range bound (inclusive)","title":"X Max"},"description":"Upper x-range bound (inclusive)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationPlotDataResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/pipelines/datafits/{job_id}/plot_data":{"get":{"tags":["Pipeline"],"summary":"Get Datafit Plot Data","description":"Return decimated trace data for a single data-fit validation plot.\n\nSame behaviour as ``GET /validations/{job_id}/plot_data`` but accepts\na data-fit job ID. Both job types store ``validation_plot_config`` in the\nsame metadata blob format.","operationId":"get_datafit_plot_data_pipelines_datafits__job_id__plot_data_get","parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}},{"name":"objective_name","in":"query","required":true,"schema":{"type":"string","description":"Objective name within validation_plot_config","title":"Objective Name"},"description":"Objective name within validation_plot_config"},{"name":"plot_index","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Index into the plots list for this objective","default":0,"title":"Plot Index"},"description":"Index into the plots list for this objective"},{"name":"max_points","in":"query","required":false,"schema":{"type":"integer","maximum":80000,"minimum":100,"description":"Maximum points per trace","default":2000,"title":"Max Points"},"description":"Maximum points per trace"},{"name":"x_min","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Lower x-range bound (inclusive)","title":"X Min"},"description":"Lower x-range bound (inclusive)"},{"name":"x_max","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Upper x-range bound (inclusive)","title":"X Max"},"description":"Upper x-range bound (inclusive)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationPlotDataResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/pipelines":{"post":{"tags":["Pipeline"],"summary":"Create a new pipeline","description":"Creates a new pipeline definition with its associated steps.\nThis endpoint defines the sequence of jobs but does not start execution immediately.\nUse the 'start' endpoint to begin the pipeline execution.","operationId":"create_pipeline_pipelines_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PipelineConfig"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PipelineDetail"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false},"get":{"tags":["Pipeline"],"summary":"List user's pipelines","description":"Retrieves a list of pipelines for the current user,\noptionally filtered by project and other criteria.\n\nText fields (name, description, created_by_email) take ``ilike.%value%``,\nstatus an exact value or ``in.(a,b)``, date fields ``gte.value`` /\n``lte.value``, and created_at_gt/_lt (or updated_at_gt/_lt) bound a range.\n``id`` stays alongside ``q``: it is the exact-UUID contract API clients rely\non, while ``q`` matches a UUID only as one OR-term.","operationId":"list_pipelines_pipelines_get","parameters":[{"name":"project_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Id"}},{"name":"skip","in":"query","required":false,"schema":{"type":"integer","default":0,"title":"Skip"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":100,"title":"Limit"}},{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Q"}},{"name":"id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Id"}},{"name":"name","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"}},{"name":"description","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"}},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"}},{"name":"created_by_email","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created By Email"}},{"name":"created_at","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At"}},{"name":"updated_at","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated At"}},{"name":"created_at_gt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At Gt"}},{"name":"created_at_lt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At Lt"}},{"name":"updated_at_gt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated At Gt"}},{"name":"updated_at_lt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated At Lt"}},{"name":"order_by","in":"query","required":false,"schema":{"enum":["name","id","description","status","created_at","updated_at","created_by_email"],"type":"string","default":"created_at","title":"Order By"}},{"name":"order","in":"query","required":false,"schema":{"enum":["asc","desc"],"type":"string","default":"desc","title":"Order"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PipelineListResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/pipelines/{pipeline_id}":{"patch":{"tags":["Pipeline"],"summary":"Update pipeline name/description","description":"Updates the name and/or description of a pipeline.","operationId":"update_pipeline_pipelines__pipeline_id__patch","parameters":[{"name":"pipeline_id","in":"path","required":true,"schema":{"type":"string","title":"Pipeline Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PipelineUpdateRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Pipeline"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true},"delete":{"tags":["Pipeline"],"summary":"Delete a pipeline","description":"Deletes a pipeline, its elements, associated jobs, and storage files.","operationId":"delete_pipeline_pipelines__pipeline_id__delete","parameters":[{"name":"pipeline_id","in":"path","required":true,"schema":{"type":"string","title":"Pipeline Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true},"get":{"tags":["Pipeline"],"summary":"Get pipeline metadata","description":"Retrieves pipeline metadata only (no elements).\n\nFor elements, use GET /pipelines/{pipeline_id}/elements.","operationId":"get_pipeline_pipelines__pipeline_id__get","parameters":[{"name":"pipeline_id","in":"path","required":true,"schema":{"type":"string","title":"Pipeline Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Pipeline"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/pipelines/{pipeline_id}/elements":{"get":{"tags":["Pipeline"],"summary":"Get Pipeline Elements","description":"Get all elements for a pipeline (lightweight).\n\nHeavy job_config keys (e.g. objectives) are projected out for\nperformance. GET /elements/{element_id} returns the same lightweight\nshape; the full job_config is stored separately and fetched from\nstorage when a detail view needs it.","operationId":"get_pipeline_elements_pipelines__pipeline_id__elements_get","parameters":[{"name":"pipeline_id","in":"path","required":true,"schema":{"type":"string","title":"Pipeline Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PipelineElement"},"title":"Response Get Pipeline Elements Pipelines  Pipeline Id  Elements Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/pipelines/elements/{element_id}/job_config":{"get":{"tags":["Pipeline"],"summary":"Get a pipeline element's job_config","description":"Return one element's ``job_config``, hydrated lazily on expand.\n\nThe bulk `/elements` response projects the bigger keys (`parameters`,\n`optimizer`, `cost`) out of every element so the details page loads fast;\nthis fills them back in for the one element a drawer is showing. Returns\n``{}`` for an element that does not exist or is not visible to the caller.\n\nNote this is the DB row, not the storage copy — the two differ only by\n`objectives`, the multi-MB serialized measurement payload the worker reads\ndirectly and no client needs.","operationId":"get_pipeline_element_job_config_pipelines_elements__element_id__job_config_get","parameters":[{"name":"element_id","in":"path","required":true,"schema":{"type":"string","title":"Element Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Get Pipeline Element Job Config Pipelines Elements  Element Id  Job Config Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/pipelines/elements/{element_id}":{"get":{"tags":["Pipeline"],"summary":"Get Pipeline Element","description":"Get a single pipeline element by its id","operationId":"get_pipeline_element_pipelines_elements__element_id__get","parameters":[{"name":"element_id","in":"path","required":true,"schema":{"type":"string","title":"Element Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PipelineElement"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/pipelines/{pipeline_id}/result":{"get":{"tags":["Pipeline"],"summary":"Get pipeline result","description":"Retrieves the details of a specific pipeline, including its steps and their status.","operationId":"get_pipeline_result_pipelines__pipeline_id__result_get","parameters":[{"name":"pipeline_id","in":"path","required":true,"schema":{"type":"string","title":"Pipeline Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PipelineResult"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/pipelines/{pipeline_id}/resubmit":{"post":{"tags":["Pipeline"],"summary":"Resubmit the first submission-failed element in a pipeline","description":"Resubmit the pipeline's first SUBMISSION_FAILED element.","operationId":"resubmit_pipeline_pipelines__pipeline_id__resubmit_post","parameters":[{"name":"pipeline_id","in":"path","required":true,"schema":{"type":"string","title":"Pipeline Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PipelineDetail"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/pipelines/cancel":{"post":{"tags":["Pipeline"],"summary":"Cancel multiple pipelines","description":"Cancel several pipelines in one request.\n\nMarks every selected pipeline (and its non-terminal elements) canceled and\noffloads all running-job terminations to a single background task, avoiding\nthe per-pipeline request loop the frontend used to run.","operationId":"cancel_pipelines_pipelines_cancel_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkCancelPipelinesRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkCancelPipelinesResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/pipelines/{pipeline_id}/cancel":{"post":{"tags":["Pipeline"],"summary":"Cancel a pipeline","description":"Cancel a running pipeline and all its non-terminal elements.","operationId":"cancel_pipeline_pipelines__pipeline_id__cancel_post","parameters":[{"name":"pipeline_id","in":"path","required":true,"schema":{"type":"string","title":"Pipeline Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Pipeline"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/simple_pipelines":{"post":{"tags":["simple_pipeline"],"summary":"Create and submit a SimplePipeline","description":"Create a new SimplePipeline and submit it for processing.","operationId":"create_simple_pipeline_simple_pipelines_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSimplePipelineRequest"}}}},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SimplePipeline"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false},"get":{"tags":["simple_pipeline"],"summary":"List SimplePipelines","description":"List SimplePipelines for a project with pagination, filters, and ordering.","operationId":"list_simple_pipelines_simple_pipelines_get","parameters":[{"name":"project_id","in":"query","required":true,"schema":{"type":"string","description":"Filter by project","title":"Project Id"},"description":"Filter by project"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"description":"Items per page","default":10,"title":"Limit"},"description":"Items per page"},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Number of items to skip","default":0,"title":"Offset"},"description":"Number of items to skip"},{"name":"name","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by name (use ilike.%value% for partial match).","title":"Name"},"description":"Filter by name (use ilike.%value% for partial match)."},{"name":"description","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by description (Supabase operator syntax supported).","title":"Description"},"description":"Filter by description (Supabase operator syntax supported)."},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by status (eq.completed or in.(val1,val2)).","title":"Status"},"description":"Filter by status (eq.completed or in.(val1,val2))."},{"name":"created_by_email","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by creator email (Supabase operator syntax supported).","title":"Created By Email"},"description":"Filter by creator email (Supabase operator syntax supported)."},{"name":"created_at","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter on created_at (gte./lte./eq. operator).","title":"Created At"},"description":"Filter on created_at (gte./lte./eq. operator)."},{"name":"updated_at","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter on updated_at (gte./lte./eq. operator).","title":"Updated At"},"description":"Filter on updated_at (gte./lte./eq. operator)."},{"name":"created_at_gt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Lower bound for created_at.","title":"Created At Gt"},"description":"Lower bound for created_at."},{"name":"created_at_lt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Upper bound for created_at.","title":"Created At Lt"},"description":"Upper bound for created_at."},{"name":"updated_at_gt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Lower bound for updated_at.","title":"Updated At Gt"},"description":"Lower bound for updated_at."},{"name":"updated_at_lt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Upper bound for updated_at.","title":"Updated At Lt"},"description":"Upper bound for updated_at."},{"name":"order_by","in":"query","required":false,"schema":{"enum":["id","name","description","status","created_at","updated_at","created_by_email"],"type":"string","description":"Sort column.","default":"created_at","title":"Order By"},"description":"Sort column."},{"name":"order","in":"query","required":false,"schema":{"enum":["asc","desc"],"type":"string","description":"Sort direction.","default":"desc","title":"Order"},"description":"Sort direction."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SimplePipelineListResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/simple_pipelines/{simple_pipeline_id}":{"get":{"tags":["simple_pipeline"],"summary":"Get SimplePipeline by ID","description":"Get a SimplePipeline by ID.","operationId":"get_simple_pipeline_simple_pipelines__simple_pipeline_id__get","parameters":[{"name":"simple_pipeline_id","in":"path","required":true,"schema":{"type":"string","title":"Simple Pipeline Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SimplePipeline"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false},"patch":{"tags":["simple_pipeline"],"summary":"Update SimplePipeline name/description","description":"Partially update a SimplePipeline's name and/or description.","operationId":"update_simple_pipeline_simple_pipelines__simple_pipeline_id__patch","parameters":[{"name":"simple_pipeline_id","in":"path","required":true,"schema":{"type":"string","title":"Simple Pipeline Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SimplePipelineUpdateRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SimplePipeline"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false},"delete":{"tags":["simple_pipeline"],"summary":"Delete a SimplePipeline","description":"Delete a SimplePipeline and its associated job.","operationId":"delete_simple_pipeline_simple_pipelines__simple_pipeline_id__delete","parameters":[{"name":"simple_pipeline_id","in":"path","required":true,"schema":{"type":"string","title":"Simple Pipeline Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/simple_pipelines/{simple_pipeline_id}/cancel":{"post":{"tags":["simple_pipeline"],"summary":"Cancel a running SimplePipeline","description":"Cancel a running SimplePipeline.","operationId":"cancel_simple_pipeline_simple_pipelines__simple_pipeline_id__cancel_post","parameters":[{"name":"simple_pipeline_id","in":"path","required":true,"schema":{"type":"string","title":"Simple Pipeline Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SimplePipeline"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/protocols/validate":{"post":{"tags":["protocols"],"summary":"Validate Protocol Endpoint","description":"Validate a protocol dictionary.\n\nRuns the full backend validation (Pydantic model checks, termination\ncondition inheritance, operator consistency, duplicate names, etc.)\nand returns the result.\n\nParameters\n----------\nbody : ValidateProtocolRequest\n    Request containing the protocol dict to validate\n\nReturns\n-------\ndict\n    ``{\"valid\": true}`` on success, or\n    ``{\"valid\": false, \"error\": \"...\"}`` on failure.","operationId":"validate_protocol_endpoint_protocols_validate_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidateProtocolRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Validate Protocol Endpoint Protocols Validate Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/protocols/generate":{"post":{"tags":["protocols"],"summary":"Generate Protocol Endpoint","description":"Generate a UCP protocol from a natural-language description.\n\nWhen the description leaves a value undecided that would change what runs\non the channel, the response carries ``questions`` and no protocol. Answer\nthem and call again with the full ``clarifications`` history.\n\nAny protocol that *is* returned has already passed the same validation as\n``POST /protocols/validate`` and contains no unresolved ``input[\"...\"]``\nreferences, so it can be saved as an experiment template directly.\n\nParameters\n----------\nbody : GenerateProtocolRequest\n    The natural-language prompt, any answers already given, and an\n    optional existing protocol to edit rather than replace.\n\nReturns\n-------\nGenerateProtocolResponse\n    Either the generated YAML with a suggested name, an explanation, and\n    the assumptions made — or the questions needed to write it.\n\nRaises\n------\nExternalServiceError\n    If the model could not produce a valid protocol.","operationId":"generate_protocol_endpoint_protocols_generate_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateProtocolRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateProtocolResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/protocols/check_name":{"post":{"tags":["protocols"],"summary":"Check Protocol Name Endpoint","description":"Check whether a protocol's name describes what the protocol does.\n\nAdvisory only. A 'mismatch' never blocks saving a protocol — the name is the\nuser's to choose, and a model that misreads a naming convention must not be\nable to stop work.\n\nReturns 'uncheckable' for a name that makes no claim (a codename like\n\"ETR874\", a generic \"Test\", or a name carried in from an uploaded vendor\nfile), so callers can render nothing at all in those cases.\n\nParameters\n----------\nbody : CheckProtocolNameRequest\n    The name, the protocol it names, and whether the name came from a file.\n\nReturns\n-------\nCheckProtocolNameResponse\n    The verdict, its confidence, the specific contradictions, and a\n    suggested name.","operationId":"check_protocol_name_endpoint_protocols_check_name_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckProtocolNameRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckProtocolNameResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/protocols/convert":{"post":{"tags":["protocols"],"summary":"Convert Protocol Endpoint","description":"Convert a UCP to a vendor-native protocol file.\n\nThe primary artifact is returned as base64-encoded bytes alongside a\nsuggested filename and media type. Some targets (currently Maccor with\ndrive cycles) emit additional asset files in ``assets``.","operationId":"convert_protocol_endpoint_protocols_convert_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConvertProtocolRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConvertProtocolResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/protocols/compare":{"post":{"tags":["protocols"],"summary":"Compare Protocols Endpoint","description":"Compare two UCPs and report the differences that change what a cycler does.\n\nCosmetic respellings are not differences: regenerated names, number\nformatting, redundant nesting, an explicit goto where fall-through was\nimplicit, and a dropped trailing ``End`` all leave behaviour unchanged.\nWhat is reported is what reaches the cell -- loop counts, setpoints,\nterminations, gotos, safety bounds, and block-cumulative durations.\n\nPair it with ``/protocols/convert`` to check a round trip: convert a UCP to\na vendor format, parse the result back with ``/protocols/parse``, and\ncompare the two UCPs. A difference there is a conversion that lost\nsomething.","operationId":"compare_protocols_endpoint_protocols_compare_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompareProtocolsRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompareProtocolsResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/protocols/input_references":{"post":{"tags":["protocols"],"summary":"Find Input References Endpoint","description":"Find all input references from a protocol.\n\nThis endpoint extracts all input references of the form input[\"name\"]\nfrom the provided protocol. The protocol can be provided as a dictionary\n(JSON), YAML string, or Protocol object serialized as dict.\n\nParameters\n----------\nbody : FindInputReferencesRequest\n    Request containing the protocol to analyze\n\nReturns\n-------\nlist[str]\n    List of input reference names found in the protocol\n\nRaises\n------\nBadRequestError\n    If protocol parsing fails or input references cannot be extracted","operationId":"find_input_references_endpoint_protocols_input_references_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FindInputReferencesRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"type":"string"},"type":"array","title":"Response Find Input References Endpoint Protocols Input References Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/protocols/parse":{"post":{"tags":["protocols"],"summary":"Parse Protocol File","description":"Parse an uploaded binary protocol file and return the parsed representation.\n\nAccepts cycler protocol files (Maccor, Neware, Novonix, Arbin, etc.) and\nreturns the parsed UCP YAML, human-readable text, and metadata about\nrequired drive cycles and subroutines.","operationId":"parse_protocol_file_protocols_parse_post","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_parse_protocol_file_protocols_parse_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/protocols/parse-to-template":{"post":{"tags":["protocols"],"summary":"Parse Protocol To Template","description":"Parse a raw protocol string and create (or find) a canonical experiment template.\n\nThis is the first step of a two-step protocol submission flow. Call this to\nresolve a ``template_id``, then pass that ID to\n``POST /simulations/with-template/batch`` to run simulations.\n\nParameters\n----------\nbody : ParseToTemplateRequest\n    Protocol text, name, optional drive cycle files, and experiment parameters.\n\nReturns\n-------\nParseToTemplateResponse\n    The UUID of the resolved (created or existing) experiment template.","operationId":"parse_protocol_to_template_protocols_parse_to_template_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ParseToTemplateRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ParseToTemplateResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/drive-cycles":{"get":{"summary":"List Drive Cycles For Template","description":"List drive cycles linked to experiments under a given template.\n\nParameters\n----------\ntemplate_id : str\n    Experiment template UUID.\nlimit : int\n    Maximum number of items to return (1–100). Defaults to 100.\noffset : int\n    Zero-based page offset. Defaults to 0.\n\nReturns\n-------\nDriveCycleListResponse\n    Paginated list of ``{id, name}`` items with count and total.","operationId":"list_drive_cycles_for_template_drive_cycles_get","parameters":[{"name":"template_id","in":"query","required":true,"schema":{"type":"string","title":"Template Id"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":100,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DriveCycleListResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/drive-cycles/{drive_cycle_id}":{"get":{"summary":"Get Drive Cycle","description":"Fetch a single drive cycle including its data array.\n\nParameters\n----------\ndrive_cycle_id : str\n    Drive cycle UUID.\n\nReturns\n-------\nDriveCycle\n    Full drive cycle record with data.\n\nRaises\n------\nNotFoundError\n    If the drive cycle does not exist or is not accessible.","operationId":"get_drive_cycle_drive_cycles__drive_cycle_id__get","parameters":[{"name":"drive_cycle_id","in":"path","required":true,"schema":{"type":"string","title":"Drive Cycle Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DriveCycle"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/ecm/examples":{"get":{"tags":["ecm"],"summary":"List Examples Endpoint","description":"List available example datasets.","operationId":"list_examples_endpoint_ecm_examples_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Response List Examples Endpoint Ecm Examples Get"}}}}},"x-hidden":true}},"/ecm/examples/{example_id}/data":{"get":{"tags":["ecm"],"summary":"Get Example Data Endpoint","description":"Return time-series for a built-in example dataset, at the caller's density.\n\nThe source CSV is a file on this server, so a zoom can be served by re-decimating the\nwindow rather than by spreading rows the client already has: pass ``x_min``/``x_max``\nwith a width-derived ``max_points``.","operationId":"get_example_data_endpoint_ecm_examples__example_id__data_get","parameters":[{"name":"example_id","in":"path","required":true,"schema":{"type":"string","title":"Example Id"}},{"name":"max_points","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","maximum":80000,"minimum":1},{"type":"null"}],"title":"Max Points"}},{"name":"x_min","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"X Min"}},{"name":"x_max","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"X Max"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/ecm/fit":{"post":{"tags":["ecm"],"summary":"Fit Ecm","description":"Fit an ECM to either an example dataset or an uploaded file.\n\nProvide exactly one of ``example_id`` (query param) or ``file`` (multipart\nupload). Returns model-vs-data traces and OCV/R0 parameter curves. RC-pair\nparameters are included for superadmins and users in organizations with ECM\nresults access enabled via nav_config.\n\nWhen ``fit_ocv`` is False and the data contains an\n``Open-circuit voltage [V]`` column, the provided OCV is used directly\nand only R0 + RC parameters are fitted.","operationId":"fit_ecm_ecm_fit_post","parameters":[{"name":"num_rcs","in":"query","required":false,"schema":{"type":"integer","maximum":5,"minimum":0,"default":2,"title":"Num Rcs"}},{"name":"example_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Example Id"}},{"name":"fit_ocv","in":"query","required":false,"schema":{"type":"boolean","default":true,"title":"Fit Ocv"}},{"name":"initial_soc","in":"query","required":false,"schema":{"anyOf":[{"type":"number","maximum":1.0,"minimum":0.0},{"type":"null"}],"title":"Initial Soc"}},{"name":"capacity","in":"query","required":false,"schema":{"anyOf":[{"type":"number","exclusiveMinimum":0.0},{"type":"null"}],"title":"Capacity"}},{"name":"max_points","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","maximum":80000,"minimum":1},{"type":"null"}],"description":"Width-derived row ceiling for the returned fit traces. Omitted, the server's own default applies.","title":"Max Points"},"description":"Width-derived row ceiling for the returned fit traces. Omitted, the server's own default applies."}],"requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_fit_ecm_ecm_fit_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Fit Ecm Ecm Fit Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/ecm/detect-and-read":{"post":{"tags":["ecm"],"summary":"Detect And Read","description":"Upload a cycling data file, detect its format, and return time series.","operationId":"detect_and_read_ecm_detect_and_read_post","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_detect_and_read_ecm_detect_and_read_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Detect And Read Ecm Detect And Read Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/ecm/fit-from-measurements":{"post":{"tags":["ecm-project"],"summary":"Fit From Measurements","description":"Submit an ECM fit using measurements stored in the platform.\n\nReturns ``202 Accepted`` with ``{\"job_id\": ..., \"status\": ...}``. Poll\n``GET /jobs/{job_id}`` for the result. Always includes RC-pair\nparameters in the result (authenticated endpoint).","operationId":"fit_from_measurements_ecm_fit_from_measurements_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FitFromMeasurementsRequest"}}},"required":true},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/ecm/fit-from-file":{"post":{"tags":["ecm-project"],"summary":"Fit From File","description":"Submit an ECM fit from an uploaded cycling data file.\n\nReturns ``202 Accepted`` with the ``job_id``. Always includes RC-pair\nparameters in the result. Optionally accepts known ``initial_soc`` /\n``capacity``, or an ``ocv_soc_curve``; capacity is coulomb-count estimated\nunless ``bounds_capacity`` is also given (opting in to capacity fitting).","operationId":"fit_from_file_ecm_fit_from_file_post","parameters":[{"name":"num_rcs","in":"query","required":false,"schema":{"type":"integer","maximum":5,"minimum":0,"default":2,"title":"Num Rcs"}},{"name":"fit_ocv","in":"query","required":false,"schema":{"type":"boolean","default":true,"title":"Fit Ocv"}},{"name":"initial_soc","in":"query","required":false,"schema":{"anyOf":[{"type":"number","maximum":1.0,"minimum":0.0},{"type":"null"}],"title":"Initial Soc"}},{"name":"capacity","in":"query","required":false,"schema":{"anyOf":[{"type":"number","exclusiveMinimum":0.0},{"type":"null"}],"title":"Capacity"}},{"name":"regularization","in":"query","required":false,"schema":{"type":"number","minimum":0.0,"description":"Smoothness-prior strength on R0/RC curves (never OCV). scale = 5 / regularization; 0 disables the prior. Defaults to 0 (off).","default":0.0,"title":"Regularization"},"description":"Smoothness-prior strength on R0/RC curves (never OCV). scale = 5 / regularization; 0 disables the prior. Defaults to 0 (off)."},{"name":"ocv_soc_curve","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"JSON-encoded OcvSocCurve, e.g. {\"soc\": [...], \"ocv\": [...]}. When provided OCV-fitting is skipped and OCV is interpolated from the curve.","title":"Ocv Soc Curve"},"description":"JSON-encoded OcvSocCurve, e.g. {\"soc\": [...], \"ocv\": [...]}. When provided OCV-fitting is skipped and OCV is interpolated from the curve."},{"name":"bounds_capacity","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"JSON-encoded CapacityBounds, e.g. {\"lo\": 0.5, \"hi\": 5.0}. Providing this (with ocv_soc_curve and no capacity) opts in to fitting capacity; without it capacity is coulomb-count estimated.","title":"Bounds Capacity"},"description":"JSON-encoded CapacityBounds, e.g. {\"lo\": 0.5, \"hi\": 5.0}. Providing this (with ocv_soc_curve and no capacity) opts in to fitting capacity; without it capacity is coulomb-count estimated."},{"name":"num_knots","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","maximum":64,"minimum":1},{"type":"null"}],"title":"Num Knots"}},{"name":"num_knots_r0","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","maximum":64,"minimum":1},{"type":"null"}],"title":"Num Knots R0"}},{"name":"knot_schedule","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"JSON-encoded list[int], e.g. [2,4,8].","title":"Knot Schedule"},"description":"JSON-encoded list[int], e.g. [2,4,8]."},{"name":"clamp_boundary_knots","in":"query","required":false,"schema":{"type":"boolean","description":"Clamp boundary R0/alpha/beta knot values to interior neighbours. Set False when building R_rc symbolically downstream.","default":true,"title":"Clamp Boundary Knots"},"description":"Clamp boundary R0/alpha/beta knot values to interior neighbours. Set False when building R_rc symbolically downstream."},{"name":"clamp_max_ratio","in":"query","required":false,"schema":{"type":"number","exclusiveMinimum":1.0,"default":10.0,"title":"Clamp Max Ratio"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_fit_from_file_ecm_fit_from_file_post"}}}},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/ecm/save-to-project":{"post":{"tags":["ecm-project"],"summary":"Save To Project","description":"Create a Parameterized Model from ECM fit results.\n\nUses the system ECM model and stores the fitted interpolant parameters.","operationId":"save_to_project_ecm_save_to_project_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SaveToProjectRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SaveToProjectResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/ecm/validate":{"post":{"tags":["ecm-project"],"summary":"Validate Ecm Endpoint","description":"Validate a fitted ECM on held-out data (synchronous, no fit, no pipeline).\n\nRe-simulates the fitted model forward on the held-out current using the same\nengine ``POST /ecm/fit`` runs internally, then returns model-vs-data traces\nand RMSE/MAE/Max voltage error.","operationId":"validate_ecm_endpoint_ecm_validate_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidateECMRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidateECMResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/users/me":{"get":{"tags":["users"],"summary":"Get Current User Profile","operationId":"get_current_user_profile_users_me_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"x-hidden":false},"delete":{"tags":["users"],"summary":"Delete My Account","description":"Permanently delete the caller's own account.\n\nRemoves the ``auth.users`` row; database cascades remove the dependent\n``public`` rows. Irreversible.","operationId":"delete_my_account_users_me_delete","responses":{"204":{"description":"Successful Response"}},"x-hidden":true}},"/users/me/active-organization":{"patch":{"tags":["users"],"summary":"Update Active Organization","description":"Set the current user's active organization.\n\nThe user must be a member of the target organization.","operationId":"update_active_organization_users_me_active_organization_patch","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateActiveOrganizationBody"}}},"required":true},"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/users/onboarding":{"post":{"tags":["users"],"summary":"Complete User Onboarding","description":"Completes the onboarding process for a new user after Supabase sign-up.\nThis includes creating their entry in public.users, personal organization, etc.\nUses service client as user may not exist in public.users yet.","operationId":"complete_user_onboarding_users_onboarding_post","responses":{"204":{"description":"Successful Response"}},"x-hidden":true}},"/users/me/api-key":{"get":{"tags":["users"],"summary":"Get My Api Key","description":"Return the caller's API key details for the active organization.\n\nOnly the prefix and timestamps — the key itself is unrecoverable once\ngenerated. Returns ``null`` when no key has been created yet.","operationId":"get_my_api_key_users_me_api_key_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/ApiKeyInfo"},{"type":"null"}],"title":"Response Get My Api Key Users Me Api Key Get"}}}}},"x-hidden":true},"post":{"tags":["users"],"summary":"Regenerate My Api Key","description":"Generate a new API key for the caller in the active organization.\n\nAny existing key for this (user, organization) is replaced and stops\nworking immediately. The response is the only time the full key is\navailable.","operationId":"regenerate_my_api_key_users_me_api_key_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GeneratedApiKey"}}}}},"x-hidden":true}},"/admin/users":{"get":{"tags":["admin-users"],"summary":"List Admin Users","description":"List all users with their organization memberships (super-admin only).","operationId":"list_admin_users_admin_users_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":100,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminUserListResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/admin/users/{user_id}/deactivate":{"patch":{"tags":["admin-users"],"summary":"Deactivate User Everywhere","description":"Deactivate a user across every organization they belong to.","operationId":"deactivate_user_everywhere_admin_users__user_id__deactivate_patch","parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"string","title":"User Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeactivateUserResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/admin/users/bulk-deactivate":{"post":{"tags":["admin-users"],"summary":"Bulk Deactivate Users","description":"Deactivate multiple users across all orgs; reports per-user outcomes.","operationId":"bulk_deactivate_users_admin_users_bulk_deactivate_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkDeactivateRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/DeactivateUserResponse"},"type":"array","title":"Response Bulk Deactivate Users Admin Users Bulk Deactivate Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/search":{"get":{"summary":"Search","description":"Search across all entity types within the authenticated organization.\n\nApplies ilike substring matching on name fields and Postgres prefix\ntsquery (``to_tsquery`` with ``:*``) FTS on free-form text fields (description, notes).\n\nParameters\n----------\nq : str\n    Search query, minimum 2 characters.\nlimit : int\n    Maximum number of results to return in this page (1–100).\noffset : int\n    Number of results to skip before this page.\nper_type : int\n    Maximum results to return per entity type (1–20). Defaults to 5.\nentity_types : list[str] | None\n    When provided, restrict results to these entity type strings.\n    Omit to search all types.\nproject_id : str | None\n    When set, scope project-scoped entities (pipelines, optimizations, studies)\n    to this project. Org-scoped entities are unaffected.\n\nReturns\n-------\nSearchResponse\n    Paginated results from matching entity types with ``total`` count.","operationId":"search_search_get","parameters":[{"name":"q","in":"query","required":true,"schema":{"type":"string","minLength":2,"description":"Search query (minimum 2 characters)","title":"Q"},"description":"Search query (minimum 2 characters)"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"description":"Maximum results to return in this page","default":25,"title":"Limit"},"description":"Maximum results to return in this page"},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Number of results to skip before this page","default":0,"title":"Offset"},"description":"Number of results to skip before this page"},{"name":"per_type","in":"query","required":false,"schema":{"type":"integer","maximum":20,"minimum":1,"description":"Maximum results to return per entity type (1–20).","default":5,"title":"Per Type"},"description":"Maximum results to return per entity type (1–20)."},{"name":"entity_types","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}],"description":"Restrict to these entity type strings (repeatable). Omit to search all types.","title":"Entity Types"},"description":"Restrict to these entity type strings (repeatable). Omit to search all types."},{"name":"project_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"When set, scope project-scoped entities to this project.","title":"Project Id"},"description":"When set, scope project-scoped entities to this project."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/jobs":{"post":{"tags":["jobs"],"summary":"Submit Job","description":"Submit a new job for processing.\n\nThe job will be added to the queue and processed based on priority.","operationId":"submit_job_jobs_post","parameters":[{"name":"project_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubmitJobRequest"}}}},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false},"get":{"tags":["jobs"],"summary":"List Jobs","description":"List jobs with optional filtering.\n\nReturns a paginated list of jobs with the total count.\nIf job_types is provided, it takes precedence over job_type.","operationId":"list_jobs_jobs_get","parameters":[{"name":"job_type","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/JobType"},{"type":"null"}],"description":"Filter by job type (for backward compatibility)","title":"Job Type"},"description":"Filter by job type (for backward compatibility)"},{"name":"job_types","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"$ref":"#/components/schemas/JobType"}},{"type":"null"}],"description":"Filter by multiple job types","title":"Job Types"},"description":"Filter by multiple job types"},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/JobStatus"},{"type":"null"}],"description":"Filter by job status","title":"Status"},"description":"Filter by job status"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"description":"Number of items to return","default":10,"title":"Limit"},"description":"Number of items to return"},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Number of items to skip","default":0,"title":"Offset"},"description":"Number of items to skip"},{"name":"ids","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}],"description":"Filter by job IDs","title":"Ids"},"description":"Filter by job IDs"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobListResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/jobs/{job_id}":{"get":{"tags":["jobs"],"summary":"Get Job","description":"Get details about a specific job.\n\nReturns the job's current status, result if completed, or error if failed.","operationId":"get_job_jobs__job_id__get","parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","description":"The ID of the job to retrieve","title":"Job Id"},"description":"The ID of the job to retrieve"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false},"delete":{"tags":["jobs"],"summary":"Delete Job","description":"Delete a job and all of its children.\n\nReturns 204 No Content on success, 404 if job not found.","operationId":"delete_job_jobs__job_id__delete","parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","description":"The ID of the job to delete","title":"Job Id"},"description":"The ID of the job to delete"}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/jobs/{job_id}/metadata":{"get":{"tags":["jobs"],"summary":"Get Job Metadata","description":"Get the full metadata blob for a job.\n\nReturns the JSON contents of the job's ``metadata.json.gz`` blob in the\n``job-files`` Supabase Storage bucket. API clients use this to access\nfields that are too large for the ``result`` column — for example, the\n``validation_results`` and ``validation_plot_config`` payloads written by\npipeline validation jobs.","operationId":"get_job_metadata_jobs__job_id__metadata_get","parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","description":"The ID of the job whose metadata to retrieve","title":"Job Id"},"description":"The ID of the job whose metadata to retrieve"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/jobs/{job_id}/metadata_summary":{"get":{"tags":["jobs"],"summary":"Get Job Metadata Summary","description":"Get the parts of a job's ``metadata`` a UI reads, projected server-side.\n\nThe blob is stored in the private ``job-files`` bucket rather than on the\njob row, and no client has storage grants of its own, so this endpoint is\nhow it is read. Only ``JOB_METADATA_CLIENT_KEYS`` come back — the rest is\nworker-sized and would be discarded. The response is sanitised\n(``NaN``/``Infinity`` become ``null``) and is therefore always valid JSON.\n\nReturns ``{}`` — not 404 — while the blob has not been written yet, so a\ncaller polling a running job sees an empty object rather than an error.\n``GET /jobs/{job_id}/metadata`` remains the whole-blob, 404-on-missing form\nfor scripted clients.","operationId":"get_job_metadata_summary_jobs__job_id__metadata_summary_get","parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","description":"The ID of the job whose metadata to summarise","title":"Job Id"},"description":"The ID of the job whose metadata to summarise"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Get Job Metadata Summary Jobs  Job Id  Metadata Summary Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/jobs/{job_id}/series/channels":{"get":{"tags":["jobs"],"summary":"Get Job Validation Series Channels","description":"Objectives and channel names, without the samples.\n\nWhat a client needs to build its plots. The same names can be read off ``/metadata``, but\nonly by downloading every sample of both solves -- megabytes to populate a variable\npicker.","operationId":"get_job_validation_series_channels_jobs__job_id__series_channels_get","parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","description":"Job whose validation series to describe","title":"Job Id"},"description":"Job whose validation series to describe"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/jobs/{job_id}/series":{"get":{"tags":["jobs"],"summary":"Get Job Validation Series","description":"One objective's validation series, windowed and budgeted.\n\nThe same payload ``/metadata`` carries whole. That route has to stay -- API clients read\nfields from it -- but a plot asking it for a time series downloads every sample of both\nsolves to draw a few hundred, which is what this exists to stop.","operationId":"get_job_validation_series_jobs__job_id__series_get","parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","description":"Job whose validation series to read","title":"Job Id"},"description":"Job whose validation series to read"},{"name":"objective","in":"query","required":true,"schema":{"type":"string","description":"Objective name within the payload","title":"Objective"},"description":"Objective name within the payload"},{"name":"source","in":"query","required":false,"schema":{"type":"string","description":"Which solve to read: 'optimal' or 'baseline'","default":"optimal","title":"Source"},"description":"Which solve to read: 'optimal' or 'baseline'"},{"name":"columns","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Comma-separated channels to return besides the x column. Defaults to every channel the objective carries.","title":"Columns"},"description":"Comma-separated channels to return besides the x column. Defaults to every channel the objective carries."},{"name":"x","in":"query","required":false,"schema":{"type":"string","description":"Column plotted on x, and windowed on","default":"Time [s]","title":"X"},"description":"Column plotted on x, and windowed on"},{"name":"max_points","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":1},{"type":"null"}],"description":"Row ceiling, from the plot's measured width","title":"Max Points"},"description":"Row ceiling, from the plot's measured width"},{"name":"x_min","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Window lower bound, in x's units","title":"X Min"},"description":"Window lower bound, in x's units"},{"name":"x_max","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Window upper bound, in x's units","title":"X Max"},"description":"Window upper bound, in x's units"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/jobs/{job_id}/resubmit":{"post":{"tags":["jobs"],"summary":"Resubmit Job","description":"Resubmit a job that failed during submission.\n\nOnly jobs with error_code SUBMISSION_FAILED may be resubmitted.\nReturns 404 if the job is not found, 400 if it cannot be resubmitted.","operationId":"resubmit_job_jobs__job_id__resubmit_post","parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","description":"The ID of the job to resubmit","title":"Job Id"},"description":"The ID of the job to resubmit"}],"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/jobs/{job_id}/cancel":{"post":{"tags":["jobs"],"summary":"Cancel Job","description":"Cancel a job if it hasn't been completed yet.\n\nReturns the updated job on success, 404 if job not found or already terminal.","operationId":"cancel_job_jobs__job_id__cancel_post","parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","description":"The ID of the job to cancel","title":"Job Id"},"description":"The ID of the job to cancel"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/optimize":{"get":{"tags":["optimization"],"summary":"Get Optimization With Jobs","description":"List optimization jobs and optimization records for the project.\n\nFilter parameters support Supabase filter operators:\n\n- Text fields (name, template_name, cell_name, model_name,\n  created_by_email): use ``ilike.%value%`` for partial match.\n- Status: use ``eq.completed`` or ``in.(pending,running)`` for\n  multiple values.\n- Date range: use ``created_at_gt`` and ``created_at_lt`` for\n  between queries.","operationId":"get_optimization_with_jobs_optimize_get","deprecated":true,"parameters":[{"name":"project_id","in":"query","required":true,"schema":{"type":"string","title":"Project Id"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":10,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","default":0,"title":"Offset"}},{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Q"}},{"name":"name","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"}},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"}},{"name":"template_name","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Template Name"}},{"name":"cell_name","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cell Name"}},{"name":"model_name","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model Name"}},{"name":"created_by_email","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created By Email"}},{"name":"created_at","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At"}},{"name":"created_at_gt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At Gt"}},{"name":"created_at_lt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At Lt"}},{"name":"updated_at_gt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated At Gt"}},{"name":"updated_at_lt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated At Lt"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OptimizationListResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/optimize/preview-experiment-backend":{"post":{"tags":["optimization"],"summary":"Preview Experiment Backend","description":"Check whether a UCP protocol can be run on the PyBaMM backend.\n\nThe frontend uses this to gate the simulation backend selector — when\nthe protocol is not PyBaMM-compatible, users are forced onto the UCP\nbackend.","operationId":"preview_experiment_backend_optimize_preview_experiment_backend_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExperimentBackendPreviewRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExperimentBackendPreviewResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/optimize/{id}":{"get":{"tags":["optimization"],"summary":"Get Optimization With Job","description":"Get an optimization and its linked job by optimization id or job_id.","operationId":"get_optimization_with_job_optimize__id__get","deprecated":true,"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OptimizationWithJobResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/optimize/{parent_job_id}/child-jobs":{"get":{"tags":["optimization"],"summary":"Get Child Jobs","description":"Get all child jobs for a multiprocessing optimization job.","operationId":"get_child_jobs_optimize__parent_job_id__child_jobs_get","deprecated":true,"parameters":[{"name":"parent_job_id","in":"path","required":true,"schema":{"type":"string","title":"Parent Job Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/optimizations":{"post":{"tags":["optimizations"],"summary":"Submit Optimization","description":"Submit a battery design optimization job using JSON input.","operationId":"submit_optimization_optimizations_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Body_submit_optimization_optimizations_post"}}}},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Optimization"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false},"get":{"tags":["optimizations"],"summary":"List Optimization Resources","description":"List optimizations as job-free resources for the project.\n\nSame filtering as the legacy list endpoint, but each item is an\n:class:`OptimizationResource` (flat status, no linked job). ``status``\nfilters still accept the underlying job-status vocabulary.","operationId":"list_optimization_resources_optimizations_get","parameters":[{"name":"project_id","in":"query","required":true,"schema":{"type":"string","title":"Project Id"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":10,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","default":0,"title":"Offset"}},{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Q"}},{"name":"name","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"}},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"}},{"name":"template_name","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Template Name"}},{"name":"cell_name","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cell Name"}},{"name":"model_name","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model Name"}},{"name":"created_by_email","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created By Email"}},{"name":"created_at","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At"}},{"name":"created_at_gt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At Gt"}},{"name":"created_at_lt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At Lt"}},{"name":"updated_at_gt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated At Gt"}},{"name":"updated_at_lt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated At Lt"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OptimizationResourceListResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/optimizations/{id}":{"patch":{"tags":["optimizations"],"summary":"Update Optimization","description":"Update an optimization's name and/or description.","operationId":"update_optimization_optimizations__id__patch","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateOptimizationBody"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Optimization"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false},"delete":{"tags":["optimizations"],"summary":"Delete Optimization","description":"Delete an optimization and its underlying job(s).","operationId":"delete_optimization_optimizations__id__delete","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true},"get":{"tags":["optimizations"],"summary":"Get Optimization Resource","description":"Get a single optimization as a job-free resource.\n\nAccepts an optimization id (or, transitionally, a job_id) and returns\nan :class:`OptimizationResource` with flat status and run count.","operationId":"get_optimization_resource_optimizations__id__get","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OptimizationResource"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/optimizations/{id}/cancel":{"post":{"tags":["optimizations"],"summary":"Cancel Optimization","description":"Cancel an optimization and return the refreshed resource.","operationId":"cancel_optimization_optimizations__id__cancel_post","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OptimizationResource"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/optimizations/{id}/resubmit":{"post":{"tags":["optimizations"],"summary":"Resubmit Optimization","description":"Resubmit an optimization's failed job; return the refreshed resource.","operationId":"resubmit_optimization_optimizations__id__resubmit_post","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}}],"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OptimizationResource"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/optimizations/statuses":{"get":{"tags":["optimizations"],"summary":"Get Optimization Resource Statuses","description":"Return lightweight statuses for the given optimization ids.\n\nFor list polling: ``ids`` is a comma-separated list. Returns only\nid + domain status (no config, results, or runs).","operationId":"get_optimization_resource_statuses_optimizations_statuses_get","parameters":[{"name":"ids","in":"query","required":true,"schema":{"type":"string","title":"Ids"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/OptimizationStatusItem"},"title":"Response Get Optimization Resource Statuses Optimizations Statuses Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/optimizations/{id}/runs":{"get":{"tags":["optimizations"],"summary":"List Optimization Runs","description":"List the multistart runs of an optimization in one call.\n\nEach run carries status and convergence history (read server-side),\nso the frontend renders per-run progress without touching jobs.","operationId":"list_optimization_runs_optimizations__id__runs_get","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/OptimizationRun"},"title":"Response List Optimization Runs Optimizations  Id  Runs Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/optimizations/{id}/config":{"get":{"tags":["optimizations"],"summary":"Get Optimization Config","description":"Return the resolved config blob for an optimization.\n\nRead server-side from storage and sanitised (NaN/Infinity -> null) so\nclients no longer fetch the job params blob from storage directly.","operationId":"get_optimization_config_optimizations__id__config_get","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Get Optimization Config Optimizations  Id  Config Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/optimizations/{id}/series/channels":{"get":{"tags":["optimizations"],"summary":"Get Optimization Series Channels","description":"Objectives and channel names for this optimization's validation series.\n\nScoped to the optimization rather than the job, because the job's id is not something a\nclient can see: the optimization resource does not carry it, and the adapter's `job_id`\nis the optimization's own id kept for legacy lookups. Resolving it here is the same step\n``/metadata`` already takes.","operationId":"get_optimization_series_channels_optimizations__id__series_channels_get","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/optimizations/{id}/series":{"get":{"tags":["optimizations"],"summary":"Get Optimization Series","description":"One objective's validation series, windowed and budgeted.\n\nThe same rows ``/metadata`` carries whole. A plot reading them from there downloads every\nsample of both solves to draw a few hundred points.","operationId":"get_optimization_series_optimizations__id__series_get","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}},{"name":"objective","in":"query","required":true,"schema":{"type":"string","description":"Objective name within the payload","title":"Objective"},"description":"Objective name within the payload"},{"name":"source","in":"query","required":false,"schema":{"type":"string","description":"Which solve: 'optimal' or 'baseline'","default":"optimal","title":"Source"},"description":"Which solve: 'optimal' or 'baseline'"},{"name":"columns","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Comma-separated channels besides the x column","title":"Columns"},"description":"Comma-separated channels besides the x column"},{"name":"x","in":"query","required":false,"schema":{"type":"string","description":"Column plotted on x, and windowed on","default":"Time [s]","title":"X"},"description":"Column plotted on x, and windowed on"},{"name":"max_points","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":1},{"type":"null"}],"description":"Row ceiling, from the plot's measured width","title":"Max Points"},"description":"Row ceiling, from the plot's measured width"},{"name":"x_min","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Window lower bound, in x's units","title":"X Min"},"description":"Window lower bound, in x's units"},{"name":"x_max","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Window upper bound, in x's units","title":"X Max"},"description":"Window upper bound, in x's units"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/optimizations/{id}/metadata":{"get":{"tags":["optimizations"],"summary":"Get Optimization Metadata","description":"Return the metadata blob for an optimization (server-side, sanitised).","operationId":"get_optimization_metadata_optimizations__id__metadata_get","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Get Optimization Metadata Optimizations  Id  Metadata Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/variables/convert-expression-to-json":{"post":{"tags":["variables"],"summary":"Convert Expression To Json","description":"Convert a PyBaMM expression string to JSON-serialized format.\n\nThe expression can use:\n- CoupledVariable(\"Variable Name\") for model variables\n- Parameter(\"Parameter Name\") for model parameters\n- InputParameter(\"Input Name\") for optimization inputs\n- Standard math operations (+, -, *, /, **)\n\nExample expression:\n    CoupledVariable(\"Voltage [V]\") - Parameter(\"Target Voltage\")\n\nParameters\n----------\nrequest : ExpressionToJsonRequest\n    Request body containing the expression string\n\nReturns\n-------\nExpressionToJsonResponse\n    Response with the JSON-serialized PyBaMM symbol","operationId":"convert_expression_to_json_variables_convert_expression_to_json_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExpressionToJsonRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExpressionToJsonResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/variables/convert-json-to-expression":{"post":{"tags":["variables"],"summary":"Convert Json To Expression","description":"Convert a JSON-serialized PyBaMM symbol back to an expression string.\n\nThis reconstructs a PyBaMM expression string from the JSON representation.\nThe resulting expression can be evaluated back to the same symbol.\n\nParameters\n----------\nrequest : JsonToExpressionRequest\n    Request body containing the JSON-serialized PyBaMM symbol\n\nReturns\n-------\nJsonToExpressionResponse\n    Response with the expression string","operationId":"convert_json_to_expression_variables_convert_json_to_expression_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JsonToExpressionRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JsonToExpressionResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/variables/evaluate-expression":{"post":{"tags":["variables"],"summary":"Evaluate Expression","description":"Evaluate a dependent parameter expression using current parameter values.\n\nThe expression is given as a JSON-serialized PyBaMM symbol (json_value).\nParameters are the full frontend parameters dict; they are converted and\nused to substitute Parameter(\"...\") nodes, then the expression is\nevaluated to a scalar.\n\nParameters\n----------\nrequest : EvaluateExpressionRequest\n    json_value: JSON symbol tree; parameters: current parameters dict\n\nReturns\n-------\nEvaluateExpressionResponse\n    value: evaluated numeric result","operationId":"evaluate_expression_variables_evaluate_expression_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EvaluateExpressionRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EvaluateExpressionResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/variables/format-expression":{"post":{"tags":["variables"],"summary":"Format Expression","description":"Format a PyBaMM expression string using black.\n\nWraps the expression in a dummy assignment, runs black, then\nstrips the assignment back off so the caller gets just the\nformatted expression.\n\nParameters\n----------\nrequest : FormatExpressionRequest\n    expression: Raw PyBaMM expression string\n\nReturns\n-------\nFormatExpressionResponse\n    expression: Black-formatted expression string","operationId":"format_expression_variables_format_expression_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FormatExpressionRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FormatExpressionResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/variables/validate-expression":{"post":{"tags":["variables"],"summary":"Validate Expression Endpoint","description":"Validate a custom variable expression against a model.\n\nChecks syntax, variable/parameter references, and cycle detection.\nAccepts either ``model_id`` (for existing models) or ``config`` (for\nmodels being created).\n\nParameters\n----------\nrequest : ValidateExpressionRequest\n    Expression plus either model_id or config, and optional existing\n    custom variables.\nmodel_repo : ModelRepository\n    Injected model repository.\n\nReturns\n-------\nValidationResult\n    Validation results including errors, warnings, and references.","operationId":"validate_expression_endpoint_variables_validate_expression_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidateExpressionRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/src__services__variable_validation_service__ValidationResult"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/optimization_templates":{"get":{"tags":["optimization_templates"],"summary":"List Optimization Templates","description":"List all optimization templates accessible from the given project.\n\nReturns the project's own templates combined with system-level templates.\n\nParameters\n----------\nproject_id : str\n    The owner project whose templates should be retrieved.\nq : str | None, optional\n    Free-text search on template name plus prefix full-text match, matching\n    the global search. Pushed into each source query (project + system) as a\n    SQL filter before the in-memory merge, rather than a Python substring.\ncreated_at_gt, created_at_lt, updated_at_gt, updated_at_lt : str | None, optional\n    ISO datetime strings for date-range (between) filtering on the\n    ``created_at`` / ``updated_at`` columns.\n\nReturns\n-------\nlist[OptimizationTemplate]\n    Owned templates followed by system templates.","operationId":"list_optimization_templates_optimization_templates_get","parameters":[{"name":"project_id","in":"query","required":true,"schema":{"type":"string","title":"Project Id"}},{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Free-text search on template name plus prefix full-text match, matching the global search.","title":"Q"},"description":"Free-text search on template name plus prefix full-text match, matching the global search."},{"name":"created_at_gt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At Gt"}},{"name":"created_at_lt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At Lt"}},{"name":"updated_at_gt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated At Gt"}},{"name":"updated_at_lt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated At Lt"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/OptimizationTemplate"},"title":"Response List Optimization Templates Optimization Templates Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true},"post":{"tags":["optimization_templates"],"summary":"Create Optimization Template","description":"Create a new project-level optimization template.\n\nParameters\n----------\nbody : CreateOptimizationTemplate\n    Template creation data including the owner project_id.\n\nReturns\n-------\nOptimizationTemplate\n    Created optimization template.\n\nRaises\n------\nConflictError\n    If a template with the same name already exists in the project.","operationId":"create_optimization_template_optimization_templates_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateOptimizationTemplate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OptimizationTemplate"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/optimization_templates/{template_id}":{"patch":{"tags":["optimization_templates"],"summary":"Update Optimization Template","description":"Update the name and/or description of a project-level optimization template.\n\nParameters\n----------\ntemplate_id : str\n    The ID of the template to update.\nbody : UpdateOptimizationTemplate\n    Fields to update (name, description).\n\nReturns\n-------\nOptimizationTemplate\n    The updated template.\n\nRaises\n------\nNotFoundError\n    If no template with the given ID exists.\nConflictError\n    If a template with the new name already exists in the project.","operationId":"update_optimization_template_optimization_templates__template_id__patch","parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateOptimizationTemplate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OptimizationTemplate"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true},"delete":{"tags":["optimization_templates"],"summary":"Delete Optimization Template","description":"Delete a project-level optimization template.\n\nParameters\n----------\ntemplate_id : str\n    The ID of the template to delete.\n\nRaises\n------\nNotFoundError\n    If no template with the given ID exists.","operationId":"delete_optimization_template_optimization_templates__template_id__delete","parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/optimization_templates/from-optimization":{"post":{"tags":["optimization_templates"],"summary":"Create Template From Optimization","description":"Create a project optimization template from an existing optimization.\n\nCopies the optimization's saved config into the new template's\n``initial_form_data`` (both follow the same schema), so the client no longer\nre-maps the config through the optimization form to save a template.\n\nParameters\n----------\nbody : FromOptimizationRequest\n    The source optimization id plus the new template's name/description.\n\nReturns\n-------\nOptimizationTemplate\n    The created project-level template.\n\nRaises\n------\nNotFoundError\n    If the optimization does not exist.\nBadRequestError\n    If the name is blank or the optimization has no valid saved\n    configuration to turn into a template.\nConflictError\n    If a template with the same name already exists in the project.","operationId":"create_template_from_optimization_optimization_templates_from_optimization_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FromOptimizationRequest"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OptimizationTemplate"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/optimization_templates/{template_id}/copy":{"post":{"tags":["optimization_templates"],"summary":"Copy Template To Project","description":"Copy an existing template into a target project as a new template.\n\nParameters\n----------\ntemplate_id : str\n    The ID of the source template to copy.\nbody : CopyOptimizationTemplateRequest\n    The target project ID.\n\nReturns\n-------\nOptimizationTemplate\n    The newly created copy in the target project.\n\nRaises\n------\nNotFoundError\n    If no template with the given ID exists.\nConflictError\n    If a template with the same name already exists in the target project.","operationId":"copy_template_to_project_optimization_templates__template_id__copy_post","parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CopyOptimizationTemplateRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OptimizationTemplate"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/organizations/current/usage":{"get":{"tags":["Organizations"],"summary":"Current organization usage and limits for the active billing period","description":"Return the org-wide usage for the current calendar month and configured limits.\n\nUsage is aggregated across all members of the organization (limits are\norg-level) for the current calendar-month period and resets on the first of\neach month. Simulation usage is a single figure; compute usage is broken\ndown by job type with the total in ``compute.usage``. All values are in\nhours; a ``None`` limit means that usage type is unconstrained.","operationId":"get_current_organization_usage_organizations_current_usage_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrganizationUsageResponse"}}}}},"x-hidden":false}},"/organizations":{"get":{"tags":["Organizations"],"summary":"List organizations accessible to the user","description":"Retrieve organizations the user has access to (filtered by RLS).","operationId":"list_organizations_organizations_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/Organization"},"type":"array","title":"Response List Organizations Organizations Get"}}}}},"x-hidden":true},"post":{"tags":["Organizations"],"summary":"Create a new organization (Basic)","description":"Create a new organization and assign the current user as admin.","operationId":"create_organization_organizations_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrganizationCreate"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Organization"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/organizations/{organization_id}":{"get":{"tags":["Organizations"],"summary":"Get a specific organization by ID","description":"Retrieve a specific organization by its ID, if the user has access.","operationId":"get_organization_organizations__organization_id__get","parameters":[{"name":"organization_id","in":"path","required":true,"schema":{"type":"string","title":"Organization Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Organization"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true},"patch":{"tags":["Organizations"],"summary":"Update an organization","description":"Update an existing organization identified by its ID.\n\nOnly provided fields will be updated.","operationId":"update_organization_organizations__organization_id__patch","parameters":[{"name":"organization_id","in":"path","required":true,"schema":{"type":"string","title":"Organization Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateOrganization"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Organization"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true},"delete":{"tags":["Organizations"],"summary":"Delete an organization","description":"Delete an organization including all cell specs, instances, measurements, and\nassociated storage files.","operationId":"delete_organization_organizations__organization_id__delete","parameters":[{"name":"organization_id","in":"path","required":true,"schema":{"type":"string","title":"Organization Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/organizations/{organization_id}/logo/initiate-upload":{"post":{"tags":["Organizations"],"summary":"Initiate a signed-URL logo upload","description":"Return a signed URL the client PUTs the image to.\n\nThe bytes go straight to storage rather than through this API, so the\nbucket's own limits bound them: it rejects an object over 2 MiB (413) or of\nan unlisted type (415). Call the confirm endpoint afterwards to record the\nlogo on the organization.","operationId":"initiate_organization_logo_upload_organizations__organization_id__logo_initiate_upload_post","parameters":[{"name":"organization_id","in":"path","required":true,"schema":{"type":"string","title":"Organization Id"}},{"name":"variant","in":"query","required":false,"schema":{"$ref":"#/components/schemas/LogoVariant","description":"Which mark to address: 'light' (the default) or 'dark'. On the GET, an unset variant falls back to the other one.","default":"light"},"description":"Which mark to address: 'light' (the default) or 'dark'. On the GET, an unset variant falls back to the other one."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InitiateLogoUploadRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InitiateLogoUploadResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/organizations/{organization_id}/logo/confirm-upload":{"post":{"tags":["Organizations"],"summary":"Confirm a signed-URL logo upload","description":"Record an uploaded logo, replacing any existing one of that variant.\n\nThe storage path is recomputed server-side from ``organization_id``, the\ncontent type, and the variant; a client-supplied path is never trusted.\nReturns the updated organization so the client can refresh its cache without\na follow-up read.","operationId":"confirm_organization_logo_upload_organizations__organization_id__logo_confirm_upload_post","parameters":[{"name":"organization_id","in":"path","required":true,"schema":{"type":"string","title":"Organization Id"}},{"name":"variant","in":"query","required":false,"schema":{"$ref":"#/components/schemas/LogoVariant","description":"Which mark to address: 'light' (the default) or 'dark'. On the GET, an unset variant falls back to the other one.","default":"light"},"description":"Which mark to address: 'light' (the default) or 'dark'. On the GET, an unset variant falls back to the other one."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfirmLogoUploadRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Organization"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/organizations/{organization_id}/logo":{"get":{"tags":["Organizations"],"summary":"Fetch a signed URL for the organization logo","description":"Return a short-lived signed URL for the organization's logo.\n\n``variant`` selects the preferred mark and falls back to the other when it\nis unset, so a client can ask for the dark logo without first checking\nwhether one exists. 404 means the organization has no mark at all.\n\nDeliberately JSON rather than a 307 to the signed URL. A redirect reads like\nthe natural fit for an ``<img src>``, but an ``<img>`` tag cannot send an\n``Authorization`` header, so the request arrives unauthenticated, is\nrejected, and the browser blocks the cross-origin response (ORB) before the\nredirect is ever followed. The client fetches this endpoint with its normal\nauthenticated transport and puts the returned storage URL in the tag; that\nURL carries its own signature and needs no header.","operationId":"get_organization_logo_organizations__organization_id__logo_get","parameters":[{"name":"organization_id","in":"path","required":true,"schema":{"type":"string","title":"Organization Id"}},{"name":"variant","in":"query","required":false,"schema":{"$ref":"#/components/schemas/LogoVariant","description":"Which mark to address: 'light' (the default) or 'dark'. On the GET, an unset variant falls back to the other one.","default":"light"},"description":"Which mark to address: 'light' (the default) or 'dark'. On the GET, an unset variant falls back to the other one."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrganizationLogoUrl"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true},"delete":{"tags":["Organizations"],"summary":"Remove the organization logo","description":"Remove one of the organization's marks.\n\nOnly the named variant is removed; the other keeps serving both themes via\nthe fallback. Idempotent — removing an absent logo succeeds.","operationId":"delete_organization_logo_organizations__organization_id__logo_delete","parameters":[{"name":"organization_id","in":"path","required":true,"schema":{"type":"string","title":"Organization Id"}},{"name":"variant","in":"query","required":false,"schema":{"$ref":"#/components/schemas/LogoVariant","description":"Which mark to address: 'light' (the default) or 'dark'. On the GET, an unset variant falls back to the other one.","default":"light"},"description":"Which mark to address: 'light' (the default) or 'dark'. On the GET, an unset variant falls back to the other one."}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/organizations/{organization_id}/users":{"get":{"tags":["Organizations"],"summary":"List all users with their roles in an organization","description":"Retrieve all users with their roles within a specific organization.","operationId":"list_users_in_organization_organizations__organization_id__users_get","parameters":[{"name":"organization_id","in":"path","required":true,"schema":{"type":"string","title":"Organization Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/UserWithRoles"},"title":"Response List Users In Organization Organizations  Organization Id  Users Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/organizations/{organization_id}/users/by-email":{"post":{"tags":["Organizations"],"summary":"Add a user to the organization by email as Admin","description":"Add a user to the organization by email with Admin role.\n\nInvites the email if it is not registered yet; otherwise links the\nexisting account. ``invite_sent`` in the response tells the caller\nwhether an invitation email was actually dispatched.","operationId":"add_user_to_organization_by_email_organizations__organization_id__users_by_email_post","parameters":[{"name":"organization_id","in":"path","required":true,"schema":{"type":"string","title":"Organization Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddUserByEmailRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddUserByEmailResult"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/organizations/{organization_id}/users/{user_id}/role":{"patch":{"tags":["Organizations"],"summary":"Update a user's organization role by role name","description":"Update a user's role within the organization.","operationId":"update_user_org_role_organizations__organization_id__users__user_id__role_patch","parameters":[{"name":"organization_id","in":"path","required":true,"schema":{"type":"string","title":"Organization Id"}},{"name":"user_id","in":"path","required":true,"schema":{"type":"string","title":"User Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateUserOrgRoleRequest"}}}},"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/organizations/{organization_id}/users/{user_id}":{"patch":{"tags":["Organizations"],"summary":"Activate or deactivate a user's organization membership","description":"Activate or deactivate a user's membership in the organization.\n\nDeactivating preserves the membership and role but blocks the user's access\nto this organization; reactivating restores it.","operationId":"set_user_active_in_organization_organizations__organization_id__users__user_id__patch","parameters":[{"name":"organization_id","in":"path","required":true,"schema":{"type":"string","title":"Organization Id"}},{"name":"user_id","in":"path","required":true,"schema":{"type":"string","title":"User Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateUserActiveRequest"}}}},"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true},"delete":{"tags":["Organizations"],"summary":"Remove a user from an organization","description":"Remove a user from an organization.","operationId":"remove_user_from_organization_organizations__organization_id__users__user_id__delete","parameters":[{"name":"organization_id","in":"path","required":true,"schema":{"type":"string","title":"Organization Id"}},{"name":"user_id","in":"path","required":true,"schema":{"type":"string","title":"User Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/organizations/{organization_id}/users/{user_id}/resend-invite":{"post":{"tags":["Organizations"],"summary":"Resend the invitation email to an organization member as Admin","description":"Resend the sign-up invitation email to a not-yet-confirmed member.","operationId":"resend_invite_to_user_organizations__organization_id__users__user_id__resend_invite_post","parameters":[{"name":"organization_id","in":"path","required":true,"schema":{"type":"string","title":"Organization Id"}},{"name":"user_id","in":"path","required":true,"schema":{"type":"string","title":"User Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/organizations/{organization_id}/users/{user_id}/send-password-reset":{"post":{"tags":["Organizations"],"summary":"Send a password reset email to an organization member as Admin","description":"Send a password recovery email to a member who already has an account.","operationId":"send_password_reset_to_user_organizations__organization_id__users__user_id__send_password_reset_post","parameters":[{"name":"organization_id","in":"path","required":true,"schema":{"type":"string","title":"Organization Id"}},{"name":"user_id","in":"path","required":true,"schema":{"type":"string","title":"User Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/activity-logs/":{"get":{"tags":["activity-logs"],"summary":"List Activity Logs","description":"List activity logs for the current user's organization.\nOnly users with Admin role can access activity logs for auditing purposes.\n\n- **user_id**: Optional filter by user ID\n- **activity_type**: Optional filter by activity type\n- **project_id**: Optional filter by project ID. Activities with no project\n  (organization-scoped ones) are excluded when this filter is set.\n- **limit**: Maximum number of logs to return (1-1000, default 100)\n- **offset**: Number of logs to skip for pagination","operationId":"list_activity_logs_activity_logs__get","parameters":[{"name":"user_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"User Id"}},{"name":"activity_type","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/ActivityType"},{"type":"null"}],"title":"Activity Type"}},{"name":"project_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Id"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":1000,"minimum":1,"default":100,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":0},{"type":"null"}],"title":"Offset"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ActivityLog"},"title":"Response List Activity Logs Activity Logs  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/roles/organization":{"get":{"tags":["roles"],"summary":"List all organization roles with their permissions","description":"List every organization role together with the permissions it grants.","operationId":"list_organization_roles_roles_organization_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/OrganizationRoleWithPermissions"},"type":"array","title":"Response List Organization Roles Roles Organization Get"}}}}},"x-hidden":true}},"/roles/project":{"get":{"tags":["roles"],"summary":"List all project roles with their permissions","description":"List every project role together with the permissions it grants.","operationId":"list_project_roles_roles_project_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/ProjectRoleWithPermissions"},"type":"array","title":"Response List Project Roles Roles Project Get"}}}}},"x-hidden":true}},"/permissions":{"get":{"tags":["permissions"],"summary":"List all permissions with the roles that grant them","description":"List every permission together with the org/project roles referencing it.","operationId":"list_permissions_permissions_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/PermissionWithRoles"},"type":"array","title":"Response List Permissions Permissions Get"}}}}},"x-hidden":true}},"/projects":{"post":{"summary":"Create a new project within an organization, assigning creator as Project Admin","operationId":"create_project_projects_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProject"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Project"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false},"get":{"summary":"List projects for an organization","description":"List projects for an organization with pagination, filtering, and sorting.\n\nFilter parameters support Supabase filter operators, per the field's\ndeclared policy:\n- Text fields (name, description): use ``ilike.%value%`` for partial match\n- Date fields: use ``gte.value``, ``lte.value``, etc.\n- Date range: use created_at_gt and created_at_lt for between queries\n\nThere is no ``created_by_email`` filter: the projects table records no\ncreator, so there is nothing to match against.","operationId":"list_projects_for_organization_endpoint_projects_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":100,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"name","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"}},{"name":"description","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"}},{"name":"created_at","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At"}},{"name":"created_at_gt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At Gt"}},{"name":"created_at_lt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At Lt"}},{"name":"updated_at","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated At"}},{"name":"updated_at_gt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated At Gt"}},{"name":"updated_at_lt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated At Lt"}},{"name":"order_by","in":"query","required":false,"schema":{"enum":["name","created_at","updated_at"],"type":"string","default":"created_at","title":"Order By"}},{"name":"order","in":"query","required":false,"schema":{"enum":["asc","desc"],"type":"string","default":"desc","title":"Order"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_Project_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/projects/{project_id}":{"get":{"summary":"Get a specific project by ID within an organization","operationId":"get_project_projects__project_id__get","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","title":"Project Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Project"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false},"patch":{"summary":"Update a project within an organization","operationId":"update_project_projects__project_id__patch","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","title":"Project Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Project"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false},"delete":{"summary":"Delete a project from an organization","operationId":"delete_project_projects__project_id__delete","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","title":"Project Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/projects/{project_id}/members":{"post":{"summary":"Add a user to a project or update their project role","description":"Upsert (insert or update) a user's role for a project.\n\nThe caller must have ``project:manage_members`` on the project's\norganization — enforced by RLS on the user-scoped client. The target\nuser must already belong to the caller's organization.","operationId":"upsert_project_member_projects__project_id__members_post","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","title":"Project Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpsertProjectMemberBody"}}}},"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/projects/{project_id}/members/{user_id}":{"patch":{"summary":"Update a user's project role","description":"Update the project role for an existing member.\n\nThe caller must have ``project:manage_members`` on the project's\norganization — enforced by RLS on the user-scoped client.","operationId":"update_project_member_projects__project_id__members__user_id__patch","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","title":"Project Id"}},{"name":"user_id","in":"path","required":true,"schema":{"type":"string","title":"User Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProjectMemberBody"}}}},"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false},"delete":{"summary":"Remove a user from a project","description":"Remove a user from a project.\n\nThe caller must have ``project:manage_members`` on the project's\norganization — enforced by RLS on the user-scoped client.","operationId":"remove_project_member_projects__project_id__members__user_id__delete","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","title":"Project Id"}},{"name":"user_id","in":"path","required":true,"schema":{"type":"string","title":"User Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/projects/{project_id}/webhooks":{"get":{"tags":["project-webhooks"],"summary":"List webhooks for a project","description":"List project webhooks (signing secrets omitted).","operationId":"list_project_webhooks_projects__project_id__webhooks_get","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","title":"Project Id"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":100,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_ProjectWebhook_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false},"post":{"tags":["project-webhooks"],"summary":"Create a project webhook","description":"Create a webhook; returns the signing secret once.","operationId":"create_project_webhook_projects__project_id__webhooks_post","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","title":"Project Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProjectWebhook"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectWebhookCreated"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/projects/{project_id}/webhooks/{webhook_id}":{"patch":{"tags":["project-webhooks"],"summary":"Update a project webhook","description":"Partially update URL, events, or enabled flag.","operationId":"update_project_webhook_projects__project_id__webhooks__webhook_id__patch","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","title":"Project Id"}},{"name":"webhook_id","in":"path","required":true,"schema":{"type":"string","title":"Webhook Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProjectWebhook"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectWebhook"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false},"delete":{"tags":["project-webhooks"],"summary":"Delete a project webhook","description":"Delete a webhook and cascade its delivery history.","operationId":"delete_project_webhook_projects__project_id__webhooks__webhook_id__delete","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","title":"Project Id"}},{"name":"webhook_id","in":"path","required":true,"schema":{"type":"string","title":"Webhook Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/projects/{project_id}/webhooks/{webhook_id}/test":{"post":{"tags":["project-webhooks"],"summary":"Enqueue a test webhook delivery","description":"Enqueue a signed test ping to the webhook URL.","operationId":"test_project_webhook_projects__project_id__webhooks__webhook_id__test_post","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","title":"Project Id"}},{"name":"webhook_id","in":"path","required":true,"schema":{"type":"string","title":"Webhook Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookTestResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/projects/{project_id}/webhooks/{webhook_id}/deliveries":{"get":{"tags":["project-webhooks"],"summary":"List recent deliveries for a webhook","description":"Return recent delivery history for a webhook.","operationId":"list_webhook_deliveries_projects__project_id__webhooks__webhook_id__deliveries_get","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","title":"Project Id"}},{"name":"webhook_id","in":"path","required":true,"schema":{"type":"string","title":"Webhook Id"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":50,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_WebhookDelivery_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/models/validate-custom-model":{"post":{"summary":"Validate Custom Model","description":"Validate a custom PyBaMM model JSON file and return variable information.\n\nValidates that the JSON can be successfully loaded as a PyBaMM model and\nreturns the variable names from model.rhs and model.algebraic.\n\nParameters\n----------\nfile : UploadFile\n    The PyBaMM serialized model JSON file\n\nReturns\n-------\nCustomModelValidationResult\n    Validation result with success status, error message, and variable info","operationId":"validate_custom_model_models_validate_custom_model_post","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_validate_custom_model_models_validate_custom_model_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomModelValidationResult"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/models/validate-config":{"post":{"summary":"Validate Model Config","description":"Validate that a model config can be used to build a PyBaMM model.\n\nReturns validation result with success status and error message if validation fails.","operationId":"validate_model_config_models_validate_config_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidateModelConfigBody"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/models/upload-custom":{"post":{"summary":"Upload a custom PyBaMM model JSON file","description":"Upload a custom PyBaMM model from a serialized JSON file.\n\nThe model JSON is stored compressed (zstd) directly in the custom_model_data\ncolumn. Custom models are identified by having non-null custom_model_data.\n\nNon-JSON-compliant values (Infinity, -Infinity, NaN) are sanitized to strings\nbefore storing to ensure the JSON can be parsed by JavaScript.\n\nParameters\n----------\nname : str\n    Name for the custom model\ndescription : str, optional\n    Optional description for the model\nfile : UploadFile\n    The PyBaMM serialized model JSON file\n\nReturns\n-------\nModel\n    The created model record","operationId":"upload_custom_model_models_upload_custom_post","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_upload_custom_model_models_upload_custom_post"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Model"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/models":{"post":{"summary":"Create a new model within an organization","description":"Create a new model in the specified organization.","operationId":"create_model_models_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateModel"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Model"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false},"get":{"summary":"List models for an organization","description":"List models for an organization with pagination, filtering, and sorting.\n\nFilter parameters support Supabase filter operators, per the field's\ndeclared policy:\n- Text fields (name, description, created_by_email): use ``ilike.%value%``\n  for partial match\n- Date fields: use ``gte.value``, ``lte.value``, etc.\n- Date range: use created_at_gt and created_at_lt for between queries","operationId":"list_models_for_organization_endpoint_models_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":100,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Free-text search on model name and search_vector.","title":"Q"},"description":"Free-text search on model name and search_vector."},{"name":"name","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"}},{"name":"description","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"}},{"name":"created_by_email","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created By Email"}},{"name":"created_at","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At"}},{"name":"created_at_gt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At Gt"}},{"name":"created_at_lt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At Lt"}},{"name":"updated_at","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated At"}},{"name":"updated_at_gt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated At Gt"}},{"name":"updated_at_lt","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated At Lt"}},{"name":"order_by","in":"query","required":false,"schema":{"enum":["name","created_at","updated_at"],"type":"string","default":"created_at","title":"Order By"}},{"name":"order","in":"query","required":false,"schema":{"enum":["asc","desc"],"type":"string","default":"desc","title":"Order"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_Model_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/models/{model_id}":{"get":{"summary":"Get a specific model by ID within an organization","description":"Get a specific model by ID with config.\n\nValidates it belongs to the organization or is a system model.","operationId":"get_model_models__model_id__get","parameters":[{"name":"model_id","in":"path","required":true,"schema":{"type":"string","title":"Model Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModelWithConfig"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false},"patch":{"summary":"Update a model within an organization","description":"Update a model, validating it belongs to the organization.","operationId":"update_model_models__model_id__patch","parameters":[{"name":"model_id","in":"path","required":true,"schema":{"type":"string","title":"Model Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateModel"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Model"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false},"delete":{"summary":"Delete a model from an organization","description":"Delete a model, validating it belongs to the organization.","operationId":"delete_model_models__model_id__delete","parameters":[{"name":"model_id","in":"path","required":true,"schema":{"type":"string","title":"Model Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/models/{model_id}/custom-model-debug":{"get":{"summary":"Debug endpoint to inspect raw custom model data","description":"Debug endpoint to see raw data format for troubleshooting.","operationId":"get_custom_model_debug_models__model_id__custom_model_debug_get","parameters":[{"name":"model_id","in":"path","required":true,"schema":{"type":"string","title":"Model Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/models/{model_id}/custom-model-json":{"get":{"summary":"Get the custom model JSON for a custom model","description":"Get the raw JSON content of a custom model.\n\nOnly works for models with custom_model_data (custom uploaded models).\nReturns the full JSON structure of the serialized PyBaMM model.\n\nParameters\n----------\nmodel_id : str\n    The model ID\n\nReturns\n-------\ndict\n    The custom model JSON content","operationId":"get_custom_model_json_models__model_id__custom_model_json_get","parameters":[{"name":"model_id","in":"path","required":true,"schema":{"type":"string","title":"Model Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/models/{model_id}/custom-variables":{"post":{"summary":"Add a custom variable to an existing model","description":"Append a new custom variable to a model's config (append-only).\n\nValidates the expression, serializes it to JSON, and stores it.\nCustom variables cannot be edited or deleted after creation because\nevaluated values are persisted in simulation result files.","operationId":"add_custom_variable_models__model_id__custom_variables_post","parameters":[{"name":"model_id","in":"path","required":true,"schema":{"type":"string","title":"Model Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddCustomVariable"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModelWithConfig"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/projects/{project_id}/studies":{"post":{"tags":["studies"],"summary":"Create a new study","description":"Create a new study associated with a specific project.","operationId":"create_study_projects__project_id__studies_post","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","title":"Project Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StudyCreatePayload"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Study"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false},"get":{"tags":["studies"],"summary":"List studies for a project","description":"Retrieve studies associated with a specific project with pagination.","operationId":"list_studies_for_project_projects__project_id__studies_get","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","title":"Project Id"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":100,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/projects/{project_id}/studies/has-measurements":{"get":{"tags":["studies"],"summary":"Check if the project has any cell measurements","description":"Return whether any cell measurements exist for this project.","operationId":"project_has_measurements_projects__project_id__studies_has_measurements_get","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","title":"Project Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/_HasMeasurementsResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/projects/{project_id}/studies/{study_id}":{"get":{"tags":["studies"],"summary":"Get a specific study by ID","description":"Retrieve a specific study by its unique ID.","operationId":"get_study_projects__project_id__studies__study_id__get","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","title":"Project Id"}},{"name":"study_id","in":"path","required":true,"schema":{"type":"string","title":"Study Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Study"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false},"patch":{"tags":["studies"],"summary":"Update a study","description":"Update an existing study.","operationId":"update_study_projects__project_id__studies__study_id__patch","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","title":"Project Id"}},{"name":"study_id","in":"path","required":true,"schema":{"type":"string","title":"Study Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateStudy"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Study"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false},"delete":{"tags":["studies"],"summary":"Delete a study","description":"Delete a study by its ID.","operationId":"delete_study_projects__project_id__studies__study_id__delete","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","title":"Project Id"}},{"name":"study_id","in":"path","required":true,"schema":{"type":"string","title":"Study Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/projects/{project_id}/studies/{study_id}/simulations/{simulation_id}":{"post":{"tags":["studies"],"summary":"Assign a simulation to a study","description":"Assign a simulation to a study.\n\nIdempotent: returns the existing mapping (200) if already assigned.","operationId":"assign_simulation_to_study_projects__project_id__studies__study_id__simulations__simulation_id__post","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","title":"Project Id"}},{"name":"study_id","in":"path","required":true,"schema":{"type":"string","title":"Study Id"}},{"name":"simulation_id","in":"path","required":true,"schema":{"type":"string","title":"Simulation Id"}}],"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StudySimulationMapping"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false},"delete":{"tags":["studies"],"summary":"Remove a simulation from a study","description":"Remove a simulation assignment from a study.","operationId":"remove_simulation_from_study_projects__project_id__studies__study_id__simulations__simulation_id__delete","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","title":"Project Id"}},{"name":"study_id","in":"path","required":true,"schema":{"type":"string","title":"Study Id"}},{"name":"simulation_id","in":"path","required":true,"schema":{"type":"string","title":"Simulation Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/projects/{project_id}/studies/{study_id}/measurements/{measurement_id}":{"post":{"tags":["studies"],"summary":"Assign a measurement to a study","description":"Assign a measurement to a study.","operationId":"assign_measurement_to_study_projects__project_id__studies__study_id__measurements__measurement_id__post","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","title":"Project Id"}},{"name":"study_id","in":"path","required":true,"schema":{"type":"string","title":"Study Id"}},{"name":"measurement_id","in":"path","required":true,"schema":{"type":"string","title":"Measurement Id"}}],"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StudyMeasurementMapping"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false},"delete":{"tags":["studies"],"summary":"Remove a measurement from a study","description":"Remove a measurement assignment from a study.","operationId":"remove_measurement_from_study_projects__project_id__studies__study_id__measurements__measurement_id__delete","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","title":"Project Id"}},{"name":"study_id","in":"path","required":true,"schema":{"type":"string","title":"Study Id"}},{"name":"measurement_id","in":"path","required":true,"schema":{"type":"string","title":"Measurement Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/projects/{project_id}/studies/{study_id}/measurements":{"get":{"tags":["studies"],"summary":"List measurements assigned to a study","description":"Retrieve measurements assigned to a study with pagination.","operationId":"list_measurements_for_study_projects__project_id__studies__study_id__measurements_get","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","title":"Project Id"}},{"name":"study_id","in":"path","required":true,"schema":{"type":"string","title":"Study Id"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":1000,"minimum":1,"default":100,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/projects/{project_id}/studies/{study_id}/simulation_boards":{"post":{"tags":["simulation_boards"],"summary":"Create a simulation board for a study","description":"Create a new simulation board within a study.","operationId":"create_simulation_board_projects__project_id__studies__study_id__simulation_boards_post","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","title":"Project Id"}},{"name":"study_id","in":"path","required":true,"schema":{"type":"string","title":"Study Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SimulationBoardCreatePayload"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SimulationBoard"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true},"get":{"tags":["simulation_boards"],"summary":"List simulation boards in a study","description":"List simulation boards belonging to a study.","operationId":"list_simulation_boards_projects__project_id__studies__study_id__simulation_boards_get","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","title":"Project Id"}},{"name":"study_id","in":"path","required":true,"schema":{"type":"string","title":"Study Id"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":100,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/SimulationBoard"},"title":"Response List Simulation Boards Projects  Project Id  Studies  Study Id  Simulation Boards Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/projects/{project_id}/studies/{study_id}/simulation_boards/{board_id}":{"patch":{"tags":["simulation_boards"],"summary":"Update a simulation board","description":"Update an existing simulation board.","operationId":"update_simulation_board_projects__project_id__studies__study_id__simulation_boards__board_id__patch","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","title":"Project Id"}},{"name":"study_id","in":"path","required":true,"schema":{"type":"string","title":"Study Id"}},{"name":"board_id","in":"path","required":true,"schema":{"type":"string","title":"Board Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSimulationBoard"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SimulationBoard"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true},"delete":{"tags":["simulation_boards"],"summary":"Delete a simulation board","description":"Delete a simulation board by its ID.","operationId":"delete_simulation_board_projects__project_id__studies__study_id__simulation_boards__board_id__delete","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","title":"Project Id"}},{"name":"study_id","in":"path","required":true,"schema":{"type":"string","title":"Study Id"}},{"name":"board_id","in":"path","required":true,"schema":{"type":"string","title":"Board Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/projects/{project_id}/studies/{study_id}/validate":{"post":{"tags":["study-validation"],"summary":"Run validation simulations for measurements","description":"Submit drive-cycle validation simulations for one or more measurements.\n\nEach measurement is processed independently. Partial success is returned\nwhen some measurements fail (e.g. missing columns) but at least one\nsucceeds. A 400 error is raised only if every measurement fails.","operationId":"validate_study_measurements_projects__project_id__studies__study_id__validate_post","parameters":[{"name":"study_id","in":"path","required":true,"schema":{"type":"string","title":"Study Id"}},{"name":"project_id","in":"path","required":true,"schema":{"type":"string","title":"Project Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidateRequest"}}}},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidateResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/projects/{project_id}/studies/{study_id}/validation-pairs":{"get":{"tags":["study-validation"],"summary":"Get simulation-measurement pairs for the validation report","description":"Return simulation-measurement pairs associated with a study.\n\nJoins through study_simulation_mappings → simulations →\nvalidation_simulation_measurements → cell_measurements to produce\na flat list of pairs for the validation report tab.","operationId":"get_validation_pairs_projects__project_id__studies__study_id__validation_pairs_get","parameters":[{"name":"study_id","in":"path","required":true,"schema":{"type":"string","title":"Study Id"}},{"name":"project_id","in":"path","required":true,"schema":{"type":"string","title":"Project Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ValidationPair"},"title":"Response Get Validation Pairs Projects  Project Id  Studies  Study Id  Validation Pairs Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/projects/{project_id}/studies/{study_id}/validation-metrics":{"get":{"tags":["study-validation"],"summary":"Model-vs-data metrics for every pair in a study","description":"RMSE, MAE and max residual per pair, each computed over every sample.\n\nThe report's table shows these for all pairs at once, which is why they are served\napart from the channels: downloading both full datasets per pair just to fill three\nnumbers in a row would be wasteful.\n\nA pair whose simulation has no results is omitted rather than failing the batch — its\nrow renders as pending, which is what it is.","operationId":"get_validation_report_metrics_projects__project_id__studies__study_id__validation_metrics_get","parameters":[{"name":"study_id","in":"path","required":true,"schema":{"type":"string","title":"Study Id"}},{"name":"project_id","in":"path","required":true,"schema":{"type":"string","title":"Project Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ValidationPairMetrics"},"title":"Response Get Validation Report Metrics Projects  Project Id  Studies  Study Id  Validation Metrics Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/projects/{project_id}/studies/{study_id}/validation-series":{"get":{"tags":["study-validation"],"summary":"One validation pair's model and measurement series, windowed","description":"Both sides of one pair, plus the residual, at the density the client asked for.\n\nThe residual channels are computed before anything is thinned, so what is drawn is a\nselection of the real residual rather than a residual of selected rows.","operationId":"get_validation_series_projects__project_id__studies__study_id__validation_series_get","parameters":[{"name":"study_id","in":"path","required":true,"schema":{"type":"string","title":"Study Id"}},{"name":"project_id","in":"path","required":true,"schema":{"type":"string","title":"Project Id"}},{"name":"simulation_id","in":"query","required":true,"schema":{"type":"string","title":"Simulation Id"}},{"name":"measurement_id","in":"query","required":true,"schema":{"type":"string","title":"Measurement Id"}},{"name":"max_points","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":1},{"type":"null"}],"description":"Row ceiling per side.","title":"Max Points"},"description":"Row ceiling per side."},{"name":"x_min","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Window start, in seconds.","title":"X Min"},"description":"Window start, in seconds."},{"name":"x_max","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Window end, in seconds.","title":"X Max"},"description":"Window end, in seconds."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}},"/projects/{project_id}/lab/status":{"get":{"tags":["Lab"],"summary":"Get the lab-view occupancy status for a project","description":"Return the project's sites, cyclers, and channels with occupancy state.\n\nEach channel carries a derived ``free`` / ``occupied`` / ``stale`` state\n(there is no live telemetry; state comes from linked measurements'\n``end_time`` and update recency). Includes per-cycler and project-level\noccupancy counts. Each occupied/stale channel's measurement carries a\n``watched`` flag for the requesting user, so the \"My Channels\" filter needs\nno extra round-trip.","operationId":"get_lab_status_projects__project_id__lab_status_get","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","title":"Project Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LabStatus"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/projects/{project_id}/lab/report":{"get":{"tags":["Lab"],"summary":"Build a lab status report for a project","description":"Return a point-in-time lab operations report, rendered as Markdown.\n\nCovers momentum over the trend window, utilization (whole lab, per site,\nper program, and against yesterday), channels released in the recent past,\nchannels forecast to free up soon, the planned measurements queued next,\nplans that should already have started, equipment service — channels and\nwhole cyclers out, calibration falling due, and booked visits — and healthy\nchannels sitting idle. The response\ncarries every section as structured data *and* the whole thing as a\nMarkdown document in ``markdown``, so a caller can convert it to PDF or\npaste it into a message without re-deriving anything.\n\nThis endpoint only builds the report; it does not deliver it anywhere.","operationId":"get_lab_report_projects__project_id__lab_report_get","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","title":"Project Id"}},{"name":"sections","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"$ref":"#/components/schemas/LabReportSection"}},{"type":"null"}],"description":"Sections to include. Repeat the parameter for several. Omit for the full report.","title":"Sections"},"description":"Sections to include. Repeat the parameter for several. Omit for the full report."},{"name":"recently_stopped_hours","in":"query","required":false,"schema":{"type":"integer","maximum":2160,"minimum":1,"description":"Lookback for stopped channels","default":24,"title":"Recently Stopped Hours"},"description":"Lookback for stopped channels"},{"name":"stopping_soon_hours","in":"query","required":false,"schema":{"type":"integer","maximum":2160,"minimum":1,"description":"Forecast window for channels freeing up","default":24,"title":"Stopping Soon Hours"},"description":"Forecast window for channels freeing up"},{"name":"idle_thresholds_days","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"type":"integer","maximum":365,"minimum":1}},{"type":"null"}],"description":"Idle thresholds in days, e.g. 2 and 3. Channels past the lowest are listed; the rest become counts. Defaults to 2 and 3.","title":"Idle Thresholds Days"},"description":"Idle thresholds in days, e.g. 2 and 3. Channels past the lowest are listed; the rest become counts. Defaults to 2 and 3."},{"name":"queue_limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"description":"Maximum queued measurements to list","default":20,"title":"Queue Limit"},"description":"Maximum queued measurements to list"},{"name":"queue_horizon_days","in":"query","required":false,"schema":{"type":"integer","maximum":365,"minimum":1,"description":"How far ahead the queue looks","default":7,"title":"Queue Horizon Days"},"description":"How far ahead the queue looks"},{"name":"service_horizon_days","in":"query","required":false,"schema":{"type":"integer","maximum":365,"minimum":1,"description":"How far ahead booked service is reported","default":30,"title":"Service Horizon Days"},"description":"How far ahead booked service is reported"},{"name":"trend_window_days","in":"query","required":false,"schema":{"type":"integer","maximum":90,"minimum":1,"description":"Length of the momentum trend window","default":7,"title":"Trend Window Days"},"description":"Length of the momentum trend window"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LabReport"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/projects/{project_id}/lab/watched":{"get":{"tags":["Lab"],"summary":"List the measurement IDs the current user is watching","description":"Return the IDs of measurements the current user is watching.\n\nA flat list of IDs for membership testing on the client. Includes watches on\nmeasurements that may since have finished; the Lab wall intersects them with\nits live channels, so finished watches simply do not surface.","operationId":"get_watched_measurements_projects__project_id__lab_watched_get","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","title":"Project Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WatchedMeasurementIds"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/projects/{project_id}/planned_measurements":{"get":{"tags":["Planned Measurements"],"summary":"List planned measurements for a project","description":"List a project's planned measurements.\n\n``name`` supports Supabase filter operators (e.g. ``ilike.%formation%``\nfor a partial match, ``eq.Formation`` for an exact match).\n\n``q`` is the search box's free-text query, which also matches the related\nnames the table shows; it composes with the column filters above.","operationId":"list_planned_measurements_projects__project_id__planned_measurements_get","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","title":"Project Id"}},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/PlannedMeasurementStatus"},{"type":"null"}],"title":"Status"}},{"name":"channel_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Channel Id"}},{"name":"name","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"}},{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Free-text search on the plan name plus prefix full-text match on the protocol, cell spec, program, cycler and channel names the scheduler table displays, matching the global search.","title":"Q"},"description":"Free-text search on the plan name plus prefix full-text match on the protocol, cell spec, program, cycler and channel names the scheduler table displays, matching the global search."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":1000,"minimum":1,"default":100,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"order_by","in":"query","required":false,"schema":{"enum":["planned_start_time","planned_end_time","created_at","updated_at","name","status"],"type":"string","default":"planned_start_time","title":"Order By"}},{"name":"order","in":"query","required":false,"schema":{"enum":["asc","desc"],"type":"string","default":"asc","title":"Order"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false},"post":{"tags":["Planned Measurements"],"summary":"Create a planned measurement","description":"Create a requested or scheduled planned measurement.","operationId":"create_planned_measurement_projects__project_id__planned_measurements_post","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","title":"Project Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePlannedMeasurement"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlannedMeasurement"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/projects/{project_id}/planned_measurements/next_available":{"get":{"tags":["Planned Measurements"],"summary":"Earliest free start time on a channel","description":"Return the earliest start time a channel is free for ``duration_seconds``.\n\n``next_available_start`` is ``null`` when the channel is occupied by a\nrunning measurement with no known end time.","operationId":"next_available_start_projects__project_id__planned_measurements_next_available_get","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","title":"Project Id"}},{"name":"channel_id","in":"query","required":true,"schema":{"type":"string","title":"Channel Id"}},{"name":"duration_seconds","in":"query","required":true,"schema":{"type":"integer","minimum":1,"title":"Duration Seconds"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/projects/{project_id}/planned_measurements/auto_schedule_proposal":{"post":{"tags":["Planned Measurements"],"summary":"Propose reservations for selected requested tests","description":"Return a transient earliest-gap schedule for the selected test requests.","operationId":"auto_schedule_proposal_projects__project_id__planned_measurements_auto_schedule_proposal_post","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","title":"Project Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AutoScheduleRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AutoScheduleProposal"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/projects/{project_id}/planned_measurements/apply_auto_schedule_proposal":{"post":{"tags":["Planned Measurements"],"summary":"Apply selected auto-schedule assignments","description":"Turn reviewed proposal assignments into scheduled planned measurements.","operationId":"apply_auto_schedule_proposal_projects__project_id__planned_measurements_apply_auto_schedule_proposal_post","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","title":"Project Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApplyAutoScheduleProposal"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PlannedMeasurement"},"title":"Response Apply Auto Schedule Proposal Projects  Project Id  Planned Measurements Apply Auto Schedule Proposal Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/projects/{project_id}/planned_measurements/{planned_measurement_id}":{"get":{"tags":["Planned Measurements"],"summary":"Get a planned measurement","description":"Get a planned measurement by id within a project.","operationId":"get_planned_measurement_projects__project_id__planned_measurements__planned_measurement_id__get","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","title":"Project Id"}},{"name":"planned_measurement_id","in":"path","required":true,"schema":{"type":"string","title":"Planned Measurement Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlannedMeasurement"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false},"patch":{"tags":["Planned Measurements"],"summary":"Update a planned measurement","description":"Patch a planned measurement.","operationId":"update_planned_measurement_projects__project_id__planned_measurements__planned_measurement_id__patch","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","title":"Project Id"}},{"name":"planned_measurement_id","in":"path","required":true,"schema":{"type":"string","title":"Planned Measurement Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdatePlannedMeasurement"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlannedMeasurement"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false},"delete":{"tags":["Planned Measurements"],"summary":"Delete a planned measurement","description":"Delete a planned measurement. Not-found is idempotent.","operationId":"delete_planned_measurement_projects__project_id__planned_measurements__planned_measurement_id__delete","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","title":"Project Id"}},{"name":"planned_measurement_id","in":"path","required":true,"schema":{"type":"string","title":"Planned Measurement Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/projects/{project_id}/planned_measurements/{planned_measurement_id}/estimate_duration":{"patch":{"tags":["Planned Measurements"],"summary":"Estimate a planned measurement's duration from its protocol","description":"Work out how long this planned test will take, before it runs.\n\nSimulates the whole protocol with the cell specification's default model and\nwrites the total into ``estimated_duration_seconds`` -- the value scheduling\nbooks channel windows off, which until now was always typed in by hand.\n\n``buffer_pct`` pads the simulated figure by that percentage before booking it,\ndefaulting to ``DEFAULT_BUFFER_PCT``. A protocol whose duration is fixed by the\nprotocol alone is never padded.\n\nReturns immediately with ``estimated_duration_status`` set to ``estimating``;\nthe job worker fills the duration in when the simulation finishes. Poll the\nplan, or watch the status. When the simulation was already run for an\nidentical protocol and model, the estimate comes back ``ready`` instead.\n\nFor a test that has already started, use the cell measurement's\n``estimate_end_time`` endpoint instead: that one replays the measured steps\nand forecasts only what remains.","operationId":"estimate_planned_measurement_duration_projects__project_id__planned_measurements__planned_measurement_id__estimate_duration_patch","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","title":"Project Id"}},{"name":"planned_measurement_id","in":"path","required":true,"schema":{"type":"string","title":"Planned Measurement Id"}}],"requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/EstimateDurationRequest"},{"type":"null"}],"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlannedMeasurement"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":false}},"/":{"get":{"summary":"Root","operationId":"root__get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"x-hidden":true}},"/healthz":{"get":{"tags":["Health check"],"summary":"Health Check","description":"Health check endpoint, carrying the commit this instance was built from.\n\nNotes\n-----\n``commit`` lets a caller distinguish *which* build answered, not merely that\nsomething did. Porter serves old and new pods simultaneously during a rollout,\nso a bare liveness reply cannot tell a deploy gate whether the build it is about\nto test is actually live. Empty when unset (local runs, older images).","operationId":"health_check_healthz_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"x-hidden":false}},"/user/billing-portal":{"get":{"summary":"Redirect To Billing Portal Endpoint","operationId":"redirect_to_billing_portal_endpoint_user_billing_portal_get","parameters":[{"name":"customer_id","in":"query","required":true,"schema":{"type":"string","title":"Customer Id"}},{"name":"return_url","in":"query","required":true,"schema":{"type":"string","title":"Return Url"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-hidden":true}}},"components":{"schemas":{"ActivityLog":{"properties":{"id":{"type":"string","title":"Id"},"user_id":{"type":"string","title":"User Id"},"organization_id":{"type":"string","title":"Organization Id"},"project_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Id"},"type":{"$ref":"#/components/schemas/ActivityType"},"metadata":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Metadata"},"usage_quantity":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Usage Quantity"},"compute_time":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Compute Time"},"core_seconds":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Core Seconds"},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["id","user_id","organization_id","type","created_at"],"title":"ActivityLog","description":"Activity log model for auditing purposes."},"ActivityType":{"type":"string","enum":["simulation_created","simulation_completed","optimization_run","file_uploaded","file_deleted","project_created","project_updated","project_deleted","optimization_created","optimization_deleted","datafit_completed","optimization_completed","validation_completed","simple_pipeline_completed","cycler_protocol_run","cycler_protocol_completed","pipeline_created","pipeline_deleted","member_added","member_role_updated","member_deactivated","member_reactivated","member_removed","cell_specification_created","cell_specification_deleted","cell_instance_created","cell_instance_deleted","cell_measurement_created","cell_measurement_deleted","protocol_template_created","protocol_template_deleted","study_created","study_deleted","model_created","model_deleted"],"title":"ActivityType","description":"Activity types for auditing purposes.\n\nEvery member here must also exist in the ``public.activity_type`` Postgres\nenum, and vice versa — a value present on only one side is unusable (an\ninsert fails, or a stored row cannot be parsed). ``test_activity_type_enum_\nparity`` in ``tests/integration_db/schema/`` asserts the two lists match."},"AddCustomVariable":{"properties":{"name":{"type":"string","minLength":1,"title":"Name","description":"Display name of the custom variable."},"expression":{"type":"string","title":"Expression","description":"PyBaMM expression string (e.g. CoupledVariable('Voltage [V]') - Parameter('Offset'))."}},"type":"object","required":["name","expression"],"title":"AddCustomVariable","description":"Request body for adding a custom variable to an existing model."},"AddMessageRequest":{"properties":{"role":{"type":"string","pattern":"^(user|assistant|system)$","title":"Role"},"content":{"additionalProperties":true,"type":"object","title":"Content"}},"type":"object","required":["role","content"],"title":"AddMessageRequest","description":"Body for persisting one rendered message."},"AddUserByEmailRequest":{"properties":{"email":{"type":"string","title":"Email"}},"type":"object","required":["email"],"title":"AddUserByEmailRequest","description":"Request model to add an existing user to an organization by email."},"AddUserByEmailResult":{"properties":{"user_id":{"type":"string","title":"User Id","description":"ID of the (invited or pre-existing) user that was added."},"invite_sent":{"type":"boolean","title":"Invite Sent","description":"True when the email was not registered yet and an invitation email was dispatched. False when the email already belonged to a registered user, in which case the existing account was linked and no email was sent."}},"type":"object","required":["user_id","invite_sent"],"title":"AddUserByEmailResult","description":"Result of adding a user to an organization by email.\n\nReturned by the service and used verbatim as the route's response model."},"AdminUserListItem":{"properties":{"id":{"type":"string","title":"Id"},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email"},"organizations":{"items":{"$ref":"#/components/schemas/AdminUserOrgMembership"},"type":"array","title":"Organizations"}},"type":"object","required":["id"],"title":"AdminUserListItem"},"AdminUserListResponse":{"properties":{"items":{"items":{"$ref":"#/components/schemas/AdminUserListItem"},"type":"array","title":"Items"},"count":{"type":"integer","title":"Count"},"total":{"type":"integer","title":"Total"}},"type":"object","required":["items","count","total"],"title":"AdminUserListResponse"},"AdminUserOrgMembership":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"deactivated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Deactivated At"}},"type":"object","required":["id","name"],"title":"AdminUserOrgMembership"},"AgentMessage":{"properties":{"id":{"type":"string","title":"Id"},"session_id":{"type":"string","title":"Session Id"},"role":{"type":"string","title":"Role","description":"user | assistant | system"},"content":{"additionalProperties":true,"type":"object","title":"Content"},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"additionalProperties":false,"type":"object","required":["id","session_id","role","content","created_at"],"title":"AgentMessage","description":"A persisted message in a session; ``content`` is the rendered parts."},"AgentSession":{"properties":{"id":{"type":"string","title":"Id"},"user_id":{"type":"string","title":"User Id"},"organization_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Organization Id"},"project_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Id"},"title":{"type":"string","title":"Title"},"sdk_session_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sdk Session Id"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"additionalProperties":false,"type":"object","required":["id","user_id","title","created_at","updated_at"],"title":"AgentSession","description":"A persisted chat session, scoped to a user/organization/project."},"AmbientTemperatureStep":{"properties":{"kind":{"type":"string","const":"ambient_temperature","title":"Kind","description":"The type of this step","default":"ambient_temperature"},"temperature_setpoint":{"type":"number","exclusiveMinimum":-273.15,"title":"Temperature Setpoint","description":"Ambient temperature setpoint for this step [°C]."},"temperature_ramp_rate":{"type":"number","exclusiveMinimum":0.0,"title":"Temperature Ramp Rate","description":"Ambient temperature ramp rate [°C/min].","default":2.0},"note":{"type":"string","title":"Note","description":"An optional note for the step.","default":""},"resolution":{"$ref":"#/components/schemas/ResolutionConfig","description":"Resolution for saving data for this step."}},"additionalProperties":false,"type":"object","required":["temperature_setpoint"],"title":"AmbientTemperatureStep","description":"A step that sets the ambient temperature."},"Analysis":{"properties":{"measurement_id":{"type":"string","title":"Measurement Id","description":"ID of the parent cell measurement this analysis is derived from."},"name":{"type":"string","title":"Name","description":"User-provided analysis name."},"analysis_type":{"type":"string","minLength":1,"title":"Analysis Type","description":"Kind of analysis, e.g. 'ecm_from_eis'. Free-form; see KNOWN_ANALYSIS_TYPES for the advisory set the frontend offers."},"columns":{"items":{"$ref":"#/components/schemas/AnalysisColumnSpec"},"type":"array","title":"Columns","description":"Columns present in the analysis parquet, for header preview."},"metadata":{"additionalProperties":true,"type":"object","title":"Metadata","description":"Loose metadata: source RPT/cycle identity, extractor parameters, etc."},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes","description":"Free-text human description of how the analysis was performed."},"source_pipeline_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Pipeline Id","description":"FK to the pipeline this analysis was computed from."},"source_simple_pipeline_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Simple Pipeline Id","description":"FK to the simple pipeline this analysis was computed from."},"source_analysis_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Analysis Id","description":"FK to another analysis this analysis was computed from."},"source_label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Label","description":"Free-text provenance note."},"id":{"type":"string","title":"Id","description":"Unique identifier."},"organization_id":{"type":"string","title":"Organization Id","description":"Organization that owns this analysis."},"project_id":{"type":"string","title":"Project Id","description":"Project this analysis belongs to, denormalized from the parent measurement."},"created_by":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created By","description":"User ID of the creator."},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"Creation timestamp."},"updated_at":{"type":"string","format":"date-time","title":"Updated At","description":"Last update timestamp."}},"type":"object","required":["measurement_id","name","analysis_type","id","organization_id","project_id","created_at","updated_at"],"title":"Analysis","description":"An analysis record as returned by the API."},"AnalysisColumnSpec":{"properties":{"name":{"type":"string","title":"Name","description":"Column name in the parquet."},"unit":{"type":"string","title":"Unit","description":"Physical unit; empty string if unitless.","default":""},"dtype":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Dtype","description":"Optional dtype hint, e.g. 'float' or 'int'."}},"type":"object","required":["name"],"title":"AnalysisColumnSpec","description":"One column in an analysis parquet, for frontend header preview."},"AndEnd":{"properties":{"type":{"type":"string","const":"And","title":"Type","description":"Type of end condition","default":"And"},"conditions":{"items":{"anyOf":[{"$ref":"#/components/schemas/CustomEnd"},{"$ref":"#/components/schemas/DurationEnd"},{"$ref":"#/components/schemas/CapacityEnd"},{"$ref":"#/components/schemas/LoopNumberEnd"},{"$ref":"#/components/schemas/VariableEnd"},{"$ref":"#/components/schemas/AndEnd"},{"$ref":"#/components/schemas/OrEnd"}]},"type":"array","minItems":2,"title":"Conditions","description":"List of child conditions (all must be true simultaneously)"},"goto":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Goto","description":"Step to transition to when all conditions are met"}},"additionalProperties":false,"type":"object","required":["conditions"],"title":"AndEnd","description":"Compound end condition where all child conditions must be true simultaneously.\n\nFor state conditions (Voltage, Current, etc.), this creates a combined PyBaMM\nevent that fires only when all conditions are met at the same instant.\nFor variable conditions, they are evaluated at step start."},"ApiKeyInfo":{"properties":{"key_prefix":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Key Prefix"},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At"}},"type":"object","title":"ApiKeyInfo","description":"Non-secret description of a user's API key for one organization.\n\nDeliberately carries no ``key_hash``: the full key is returned exactly once,\nwhen it is generated, and only its prefix is retrievable afterwards.\n\nNo expiry field: ``api_keys`` has no ``expires_at`` column in any deployed\nenvironment (verified against staging and production), and nothing in the\nauth path enforces one — ``_auth_from_api_key`` matches on ``key_hash``\nalone. Surfacing an expiry would promise a guarantee that does not exist."},"ApplyAutoScheduleProposal":{"properties":{"assignments":{"items":{"$ref":"#/components/schemas/AutoScheduleAssignment"},"type":"array","maxItems":100,"minItems":1,"title":"Assignments"}},"type":"object","required":["assignments"],"title":"ApplyAutoScheduleProposal","description":"The selected scheduled assignments from a transient proposal."},"AttachRawData":{"properties":{"raw_data_ids":{"items":{"type":"string"},"type":"array","minItems":1,"title":"Raw Data Ids","description":"Raw-data IDs to attach to the measurement."}},"type":"object","required":["raw_data_ids"],"title":"AttachRawData","description":"Body for bulk-attaching raw-data records to a measurement."},"AutoScheduleAssignment":{"properties":{"planned_measurement_id":{"type":"string","title":"Planned Measurement Id"},"planned_measurement_name":{"type":"string","title":"Planned Measurement Name"},"planned_measurement_updated_at":{"type":"string","format":"date-time","title":"Planned Measurement Updated At"},"channel_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Channel Id"},"channel_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Channel Name"},"cycler_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cycler Name"},"planned_start_time":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Planned Start Time"},"planned_end_time":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Planned End Time"},"unscheduled_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Unscheduled Reason"}},"type":"object","required":["planned_measurement_id","planned_measurement_name","planned_measurement_updated_at"],"title":"AutoScheduleAssignment","description":"One transient assignment returned by the auto-scheduling proposal."},"AutoScheduleProposal":{"properties":{"generated_at":{"type":"string","format":"date-time","title":"Generated At"},"assignments":{"items":{"$ref":"#/components/schemas/AutoScheduleAssignment"},"type":"array","title":"Assignments"}},"type":"object","required":["generated_at","assignments"],"title":"AutoScheduleProposal","description":"A non-persistent set of proposed test reservations."},"AutoScheduleRequest":{"properties":{"planned_measurement_ids":{"items":{"type":"string"},"type":"array","maxItems":100,"minItems":1,"title":"Planned Measurement Ids"},"start_after":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Start After"}},"type":"object","required":["planned_measurement_ids"],"title":"AutoScheduleRequest","description":"The requested tests to place, in scheduling-priority order."},"AuxiliaryStep":{"properties":{"kind":{"type":"string","enum":["increment_cycle_number","end","pause","end_loop"],"title":"Kind","description":"The type of this step"},"note":{"type":"string","title":"Note","description":"An optional note for the step.","default":""}},"additionalProperties":false,"type":"object","required":["kind"],"title":"AuxiliaryStep","description":"A special step to increment the cycle number counter."},"BatchCondition":{"properties":{"experiment_parameters":{"additionalProperties":{"anyOf":[{"type":"string"},{"type":"number"}]},"type":"object","title":"Experiment Parameters"},"design_parameters":{"additionalProperties":{"anyOf":[{"type":"string"},{"type":"number"}]},"type":"object","title":"Design Parameters"}},"type":"object","title":"BatchCondition","description":"A single paired condition for batch simulation creation.\n\nUsed when each simulation needs its own specific experiment and design\nparameter combination, as opposed to the DOE cross-product approach."},"BatchUpgradeRequest":{"properties":{"simulation_ids":{"items":{"type":"string"},"type":"array","title":"Simulation Ids","description":"List of simulation IDs to upgrade"}},"type":"object","required":["simulation_ids"],"title":"BatchUpgradeRequest","description":"Request body for batch upgrade endpoint."},"Body_create_analysis_analyses_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File"},"measurement_id":{"type":"string","title":"Measurement Id"},"name":{"type":"string","title":"Name","description":"User-provided analysis name"},"analysis_type":{"type":"string","title":"Analysis Type","description":"Kind of analysis, e.g. 'ecm_from_eis' (free-form)"},"columns":{"type":"string","title":"Columns","description":"JSON array of column specs: [{\"name\": \"R0\", \"unit\": \"Ohm\"}, ...]","default":"[]"},"metadata":{"type":"string","title":"Metadata","description":"JSON object of loose metadata for the analysis","default":"{}"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes","description":"Free-text description of how the analysis was performed"},"source_pipeline_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Pipeline Id","description":"FK to the pipeline this analysis was computed from"},"source_simple_pipeline_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Simple Pipeline Id","description":"FK to the simple pipeline this analysis was computed from"},"source_analysis_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Analysis Id","description":"FK to another analysis this analysis was computed from"},"source_label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Label","description":"Free-text provenance note"}},"type":"object","required":["file","measurement_id","name","analysis_type"],"title":"Body_create_analysis_analyses_post"},"Body_create_material_property_dataset_material_property_datasets_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File"},"material_id":{"type":"string","title":"Material Id"},"project_id":{"type":"string","title":"Project Id"},"name":{"type":"string","title":"Name","description":"User-provided dataset name"},"columns":{"type":"string","title":"Columns","description":"JSON array of column specs: [{\"name\": \"c_e\", \"unit\": \"mol/L\"}, ...]"},"no_header":{"type":"boolean","title":"No Header","description":"Set to true when the CSV has no header row. Each column spec must include source_column_index to identify its position in the file.","default":false},"source_pipeline_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Pipeline Id"},"source_simple_pipeline_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Simple Pipeline Id"},"source_analysis_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Analysis Id"},"source_label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Label"}},"type":"object","required":["file","material_id","project_id","name","columns"],"title":"Body_create_material_property_dataset_material_property_datasets_post"},"Body_detect_and_read_ecm_detect_and_read_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File"}},"type":"object","required":["file"],"title":"Body_detect_and_read_ecm_detect_and_read_post"},"Body_fit_ecm_ecm_fit_post":{"properties":{"file":{"anyOf":[{"type":"string","contentMediaType":"application/octet-stream"},{"type":"null"}],"title":"File"}},"type":"object","title":"Body_fit_ecm_ecm_fit_post"},"Body_fit_from_file_ecm_fit_from_file_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File"}},"type":"object","required":["file"],"title":"Body_fit_from_file_ecm_fit_from_file_post"},"Body_parse_protocol_file_protocols_parse_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File"}},"type":"object","required":["file"],"title":"Body_parse_protocol_file_protocols_parse_post"},"Body_replace_material_property_file_material_property_datasets__property_id__file_patch":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"columns":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Columns","description":"JSON array of column specs. If omitted, existing column specs are reused. [{\"name\": \"c_e\", \"unit\": \"mol/L\"}, ...]"},"no_header":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"No Header","description":"Override the no-header flag. If omitted, the stored value is preserved."}},"type":"object","required":["file"],"title":"Body_replace_material_property_file_material_property_datasets__property_id__file_patch"},"Body_submit_optimization_optimizations_post":{"properties":{"project_id":{"type":"string","title":"Project Id"},"config":{"additionalProperties":true,"type":"object","title":"Config"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"cell_spec_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cell Spec Id"},"optimization_template_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Optimization Template Id"}},"type":"object","required":["project_id","config"],"title":"Body_submit_optimization_optimizations_post"},"Body_upload_custom_model_models_upload_custom_post":{"properties":{"name":{"type":"string","title":"Name","description":"Name for the custom model"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"Optional description"},"chemistry":{"type":"string","title":"Chemistry","description":"Model chemistry kind (lithium_ion, lithium_sulfur, ecm, generic). Defaults to lithium_ion.","default":"lithium_ion"},"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File","description":"PyBaMM serialized model JSON file"}},"type":"object","required":["name","file"],"title":"Body_upload_custom_model_models_upload_custom_post"},"Body_validate_custom_model_models_validate_custom_model_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File","description":"PyBaMM serialized model JSON file"}},"type":"object","required":["file"],"title":"Body_validate_custom_model_models_validate_custom_model_post"},"BulkCancelPipelinesRequest":{"properties":{"pipeline_ids":{"items":{"type":"string"},"type":"array","maxItems":100,"minItems":1,"title":"Pipeline Ids"}},"type":"object","required":["pipeline_ids"],"title":"BulkCancelPipelinesRequest"},"BulkCancelPipelinesResponse":{"properties":{"canceled_pipeline_ids":{"items":{"type":"string"},"type":"array","title":"Canceled Pipeline Ids"}},"type":"object","required":["canceled_pipeline_ids"],"title":"BulkCancelPipelinesResponse"},"BulkDeactivateRequest":{"properties":{"user_ids":{"items":{"type":"string"},"type":"array","minItems":1,"title":"User Ids"}},"type":"object","required":["user_ids"],"title":"BulkDeactivateRequest"},"CalculationConfig":{"properties":{"calculation":{"type":"string","title":"Calculation"},"electrode":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Electrode"},"method":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Method"},"existing_parameters":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Existing Parameters"}},"type":"object","required":["calculation"],"title":"CalculationConfig"},"CalculationResponse":{"properties":{"parameter_values":{"additionalProperties":true,"type":"object","title":"Parameter Values"}},"type":"object","required":["parameter_values"],"title":"CalculationResponse"},"CalibrationRow":{"properties":{"cycler_id":{"type":"string","title":"Cycler Id","description":"Cycler ID"},"cycler_name":{"type":"string","title":"Cycler Name","description":"Cycler name"},"site_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Site Name","description":"Site the cycler sits at"},"channel_count":{"type":"integer","title":"Channel Count","description":"Channels that go offline when this cycler is serviced"},"last_calibrated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Calibrated At","description":"When it was last calibrated; null if never"},"calibration_due_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Calibration Due At","description":"When calibration next falls due"},"days_until_due":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Days Until Due","description":"Days until ``calibration_due_at``, to one decimal. Negative when already overdue. Null when the cycler has never been calibrated, which is not the same as being zero days from due."},"is_overdue":{"type":"boolean","title":"Is Overdue","description":"``calibration_due_at`` has passed","default":false},"never_calibrated":{"type":"boolean","title":"Never Calibrated","description":"On a calibration schedule but with no recorded calibration, so no due date can be derived. Listed first: it is the least visible state and the one most likely to have been forgotten.","default":false}},"type":"object","required":["cycler_id","cycler_name","channel_count"],"title":"CalibrationRow","description":"A cycler's position against its calibration schedule.\n\nOnly cyclers actually on a schedule appear: one with no\n``calibration_interval_days`` has not opted in, and reporting it as \"never\ncalibrated\" would be a finding about configuration, not about equipment."},"CapacityBounds":{"properties":{"lo":{"type":"number","exclusiveMinimum":0.0,"title":"Lo","description":"Lower bound (Ah)."},"hi":{"type":"number","exclusiveMinimum":0.0,"title":"Hi","description":"Upper bound (Ah)."}},"type":"object","required":["lo","hi"],"title":"CapacityBounds","description":"Search bounds for capacity fitting (Ah)."},"CapacityEnd":{"properties":{"type":{"type":"string","const":"Capacity","title":"Type","description":"Type of end condition","default":"Capacity"},"value":{"type":"string","title":"Value","description":"Capacity value"},"operator":{"type":"string","enum":["<",">","<=",">="],"title":"Operator","description":"Comparison against the capacity threshold","default":">"},"goto":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Goto","description":"Step to transition to after end is reached"}},"additionalProperties":false,"type":"object","required":["value"],"title":"CapacityEnd","description":"A capacity end condition."},"CellComponent":{"properties":{"component_type":{"$ref":"#/components/schemas/ComponentType","description":"Type of the component"},"material_id":{"type":"string","title":"Material Id","description":"ID of the material"},"properties":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Properties","description":"Application properties using Quantity format for numerics. Example: {'diameter': {'value': 14, 'unit': 'mm'}, 'binder': 'PVDF'}"},"id":{"type":"string","title":"Id","description":"Unique identifier for the component"},"organization_id":{"type":"string","title":"Organization Id","description":"Organization ID of the component"},"project_id":{"type":"string","title":"Project Id","description":"Project the component is scoped to, derived from the cell specification(s) that reference it."},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"Timestamp when the component was created"},"updated_at":{"type":"string","format":"date-time","title":"Updated At","description":"Timestamp when the component was last updated"},"created_by":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created By","description":"User ID of the creator."}},"type":"object","required":["component_type","material_id","id","organization_id","project_id","created_at","updated_at"],"title":"CellComponent","description":"Model representing a cell component as returned by the API."},"CellComponentWithMaterial":{"properties":{"component_type":{"$ref":"#/components/schemas/ComponentType","description":"Type of the component"},"material_id":{"type":"string","title":"Material Id","description":"ID of the material"},"properties":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Properties","description":"Application properties using Quantity format for numerics. Example: {'diameter': {'value': 14, 'unit': 'mm'}, 'binder': 'PVDF'}"},"id":{"type":"string","title":"Id","description":"Unique identifier for the component"},"organization_id":{"type":"string","title":"Organization Id","description":"Organization ID of the component"},"project_id":{"type":"string","title":"Project Id","description":"Project the component is scoped to, derived from the cell specification(s) that reference it."},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"Timestamp when the component was created"},"updated_at":{"type":"string","format":"date-time","title":"Updated At","description":"Timestamp when the component was last updated"},"created_by":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created By","description":"User ID of the creator."},"material":{"anyOf":[{"$ref":"#/components/schemas/Material"},{"type":"null"}],"description":"The material for this component"}},"type":"object","required":["component_type","material_id","id","organization_id","project_id","created_at","updated_at"],"title":"CellComponentWithMaterial","description":"Cell component with nested material information."},"CellInstance":{"properties":{"name":{"type":"string","title":"Name","description":"Name of the cell instance (serial number)"},"batch":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Batch","description":"Batch number/identifier"},"date_manufactured":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Date Manufactured","description":"Date of manufacture"},"measured_properties":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Measured Properties","description":"Measured (not designed) properties of this specific cell, grouped by component. Numeric values use the Quantity format. Example: {'cathode': {'loading': {'value': 7.06, 'unit': 'mg.cm-2'}}, 'cell': {'initial_capacity': {'value': 1.08, 'unit': 'A.h'}}}. Designed properties (target loading, rated capacity) belong on the cell specification."},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes","description":"Free-text notes about the cell instance"},"id":{"type":"string","title":"Id","description":"Unique identifier for the cell instance"},"cell_specification_id":{"type":"string","title":"Cell Specification Id","description":"Foreign key to the cell specification"},"organization_id":{"type":"string","title":"Organization Id","description":"Organization this cell instance belongs to."},"project_id":{"type":"string","title":"Project Id","description":"Project this cell instance belongs to"},"created_by":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created By","description":"User ID of the user who created this instance"},"created_by_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created By Email","description":"Email of the user who created this instance"},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"Timestamp when the instance was created"},"updated_at":{"type":"string","format":"date-time","title":"Updated At","description":"Timestamp when the instance was last updated"},"measurement_ids":{"anyOf":[{"items":{"additionalProperties":true,"type":"object"},"type":"array"},{"type":"null"}],"title":"Measurement Ids","description":"List of measurement IDs associated with the cell instance"}},"type":"object","required":["name","id","cell_specification_id","organization_id","project_id","created_at","updated_at"],"title":"CellInstance","description":"Model representing a cell instance as returned by the API."},"CellMeasurement":{"properties":{"name":{"type":"string","maxLength":255,"minLength":1,"title":"Name"},"protocol":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Protocol","description":"Protocol information. Typical keys: 'name' (str), 'ambient_temperature_degc' (float), 'definition' (dict | str — a UCP protocol definition or another protocol format)."},"start_time":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Start Time","description":"ISO 8601 datetime with timezone (UTC preferred) marking when the test started."},"end_time":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"End Time","description":"ISO 8601 datetime with timezone (UTC preferred) marking when the test finished. Leave null while the test is still running; set it once the measurement is complete. A null end_time means the cell is still considered 'on test' in the Lab view."},"estimated_end_time":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Estimated End Time","description":"ISO 8601 datetime with timezone (UTC preferred) forecasting when a still-running test will finish. Distinct from end_time (the actual finish): this is an estimate. Null when no estimate has been computed yet."},"estimated_end_time_note":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Estimated End Time Note","description":"Free-text explanation of how estimated_end_time was derived."},"estimated_end_time_calculated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Estimated End Time Calculated At","description":"ISO 8601 datetime with timezone marking when estimated_end_time was last computed."},"test_setup":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Test Setup","description":"Physical test setup. Typical keys: 'cycler' (model), 'operator', 'lab', 'channel_number' (int)."},"step_labels_validated":{"type":"boolean","title":"Step Labels Validated","description":"Set to true only once step-type labels (Rest, CC charge, CV, discharge, etc.) have been manually reviewed. Server-inferred labels should leave this false.","default":false},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes","description":"Free-text notes about the cell measurement"},"measurement_type":{"$ref":"#/components/schemas/MeasurementType","description":"What shape of data this measurement holds. Determines which fields are populated and which upload flow applies. See the class docstring.","default":"time_series"},"properties":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Properties","description":"Flat key/value measurements, populated only when measurement_type is 'properties'. Numeric values use the Quantity format. Example: {'thickness': {'value': 0.52, 'unit': 'mm'}, 'DCIR': {'value': 12, 'unit': 'mohm'}}."},"file_metadata":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"File Metadata","description":"Metadata about uploaded files (MIME types, dimensions, etc.)"},"channel_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Channel Id","description":"Optional ID of the channel this measurement ran on."},"protocol_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Protocol Id","description":"Optional ID of the experiment template (protocol) this measurement was run against."},"program_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Program Id","description":"Optional catalog program for this measurement (copied from a linked planned measurement when present)."},"id":{"type":"string","title":"Id"},"cell_instance_id":{"type":"string","title":"Cell Instance Id"},"organization_id":{"type":"string","title":"Organization Id","description":"Organization this measurement belongs to."},"project_id":{"type":"string","title":"Project Id","description":"Project this measurement belongs to"},"created_by":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created By","description":"User ID of the user who created this measurement"},"created_by_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created By Email","description":"Email of the user who created this measurement"},"processing_status":{"$ref":"#/components/schemas/MeasurementProcessingStatus","description":"Lifecycle of server-side step processing. 'ready' once steps are available; 'pending'/'running' while the upload is being processed asynchronously; 'failed' if processing failed (see processing_error).","default":"ready"},"processing_error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Processing Error","description":"Reason processing failed, when processing_status is 'failed'. Also carries why an extend did not apply, in which case the status is back to 'ready' and this is advisory only."},"source_etag":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Etag"},"row_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Row Count"},"time_series_bytes":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Time Series Bytes"},"estimated_end_time_status":{"anyOf":[{"$ref":"#/components/schemas/EstimationStatus"},{"type":"null"}]},"estimated_end_time_job_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Estimated End Time Job Id"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"extend_claim_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Extend Claim Id","description":"Opaque token identifying the in-flight extend that holds this measurement, and the staging prefix its delta is uploaded to. Non-null exactly while processing_status is 'awaiting_extend' or 'extending'."},"extend_in_progress_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Extend In Progress At","description":"Deprecated and always null. Use processing_status."},"extend_claimed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Extend Claimed At","description":"When the in-flight extend claim was taken. Written only by the claim itself, so an unrelated update to the measurement does not age it. Null when no extend holds the measurement."}},"type":"object","required":["name","id","cell_instance_id","organization_id","project_id","created_at","updated_at"],"title":"CellMeasurement"},"CellMeasurementDetail":{"properties":{"name":{"type":"string","maxLength":255,"minLength":1,"title":"Name"},"protocol":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Protocol","description":"Protocol information. Typical keys: 'name' (str), 'ambient_temperature_degc' (float), 'definition' (dict | str — a UCP protocol definition or another protocol format)."},"start_time":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Start Time","description":"ISO 8601 datetime with timezone (UTC preferred) marking when the test started."},"end_time":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"End Time","description":"ISO 8601 datetime with timezone (UTC preferred) marking when the test finished. Leave null while the test is still running; set it once the measurement is complete. A null end_time means the cell is still considered 'on test' in the Lab view."},"estimated_end_time":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Estimated End Time","description":"ISO 8601 datetime with timezone (UTC preferred) forecasting when a still-running test will finish. Distinct from end_time (the actual finish): this is an estimate. Null when no estimate has been computed yet."},"estimated_end_time_note":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Estimated End Time Note","description":"Free-text explanation of how estimated_end_time was derived."},"estimated_end_time_calculated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Estimated End Time Calculated At","description":"ISO 8601 datetime with timezone marking when estimated_end_time was last computed."},"test_setup":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Test Setup","description":"Physical test setup. Typical keys: 'cycler' (model), 'operator', 'lab', 'channel_number' (int)."},"step_labels_validated":{"type":"boolean","title":"Step Labels Validated","description":"Set to true only once step-type labels (Rest, CC charge, CV, discharge, etc.) have been manually reviewed. Server-inferred labels should leave this false.","default":false},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes","description":"Free-text notes about the cell measurement"},"measurement_type":{"$ref":"#/components/schemas/MeasurementType","description":"What shape of data this measurement holds. Determines which fields are populated and which upload flow applies. See the class docstring.","default":"time_series"},"properties":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Properties","description":"Flat key/value measurements, populated only when measurement_type is 'properties'. Numeric values use the Quantity format. Example: {'thickness': {'value': 0.52, 'unit': 'mm'}, 'DCIR': {'value': 12, 'unit': 'mohm'}}."},"file_metadata":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"File Metadata","description":"Metadata about uploaded files (MIME types, dimensions, etc.)"},"channel_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Channel Id","description":"Optional ID of the channel this measurement ran on."},"protocol_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Protocol Id","description":"Optional ID of the experiment template (protocol) this measurement was run against."},"program_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Program Id","description":"Optional catalog program for this measurement (copied from a linked planned measurement when present)."},"id":{"type":"string","title":"Id"},"cell_instance_id":{"type":"string","title":"Cell Instance Id"},"organization_id":{"type":"string","title":"Organization Id","description":"Organization this measurement belongs to."},"project_id":{"type":"string","title":"Project Id","description":"Project this measurement belongs to"},"created_by":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created By","description":"User ID of the user who created this measurement"},"created_by_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created By Email","description":"Email of the user who created this measurement"},"processing_status":{"$ref":"#/components/schemas/MeasurementProcessingStatus","description":"Lifecycle of server-side step processing. 'ready' once steps are available; 'pending'/'running' while the upload is being processed asynchronously; 'failed' if processing failed (see processing_error).","default":"ready"},"processing_error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Processing Error","description":"Reason processing failed, when processing_status is 'failed'. Also carries why an extend did not apply, in which case the status is back to 'ready' and this is advisory only."},"source_etag":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Etag"},"row_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Row Count"},"time_series_bytes":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Time Series Bytes"},"estimated_end_time_status":{"anyOf":[{"$ref":"#/components/schemas/EstimationStatus"},{"type":"null"}]},"estimated_end_time_job_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Estimated End Time Job Id"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"extend_claim_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Extend Claim Id","description":"Opaque token identifying the in-flight extend that holds this measurement, and the staging prefix its delta is uploaded to. Non-null exactly while processing_status is 'awaiting_extend' or 'extending'."},"extend_in_progress_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Extend In Progress At","description":"Deprecated and always null. Use processing_status."},"extend_claimed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Extend Claimed At","description":"When the in-flight extend claim was taken. Written only by the claim itself, so an unrelated update to the measurement does not age it. Null when no extend holds the measurement."},"steps":{"anyOf":[{"additionalProperties":{"items":{"anyOf":[{"type":"number"},{"type":"integer"},{"type":"string"},{"type":"null"}]},"type":"array"},"type":"object"},{"type":"null"}],"title":"Steps"},"time_series":{"anyOf":[{"additionalProperties":{"items":{"type":"number"},"type":"array"},"type":"object"},{"type":"null"}],"title":"Time Series"},"cycles":{"anyOf":[{"additionalProperties":{"items":{"anyOf":[{"type":"number"},{"type":"integer"},{"type":"null"}]},"type":"array"},"type":"object"},{"type":"null"}],"title":"Cycles"},"specification":{"$ref":"#/components/schemas/CellSpecification"},"instance":{"$ref":"#/components/schemas/CellInstance"}},"type":"object","required":["name","id","cell_instance_id","organization_id","project_id","created_at","updated_at","specification","instance"],"title":"CellMeasurementDetail","description":"Response model for the /detail endpoint for a single measurement."},"CellSpecification":{"properties":{"name":{"type":"string","title":"Name","description":"Name of the cell specification"},"form_factor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Form Factor","description":"Physical form factor. Common values: '18650', '21700', 'R2032' (coin cell), 'pouch', 'prismatic', 'cylindrical'."},"manufacturer":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Manufacturer","description":"Who assembled/manufactured the cell"},"ratings":{"$ref":"#/components/schemas/Ratings","description":"Electrical ratings from the spec sheet / design targets (rated capacity, voltage min/max, optional nominal voltage, energy, energy densities, max charge/discharge C-rates). See :class:`Ratings`."},"anode_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Anode Id","description":"ID of the anode component"},"cathode_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cathode Id","description":"ID of the cathode component"},"electrolyte_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Electrolyte Id","description":"ID of the electrolyte component"},"separator_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Separator Id","description":"ID of the separator component"},"case_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Case Id","description":"ID of the case component"},"properties":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Properties","description":"Other design-level properties that are not electrical ratings and not tied to a specific component — e.g. assembly method, overall cell dimensions, mass, target thickness. Numeric values must use the Quantity format ({'value': ..., 'unit': ...})."},"source":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Source","description":"Provenance of the design. Typical keys: 'doi', 'citation', 'publication_date' (ISO 8601), 'license', 'creator_name', 'creator_orcid'. Lives on the specification (not the instance) because it describes the published design."},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes","description":"Free-text notes about the cell specification"},"id":{"type":"string","title":"Id","description":"Unique identifier for the cell specification"},"organization_id":{"type":"string","title":"Organization Id","description":"Organization ID of the cell specification"},"project_id":{"type":"string","title":"Project Id","description":"Project this cell specification belongs to"},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At","description":"When this specification was created"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At","description":"When this specification was last modified"},"created_by":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created By","description":"User ID of the user who created this specification"},"created_by_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created By Email","description":"Email of the user who created this specification"},"instance_ids":{"anyOf":[{"items":{"additionalProperties":true,"type":"object"},"type":"array"},{"type":"null"}],"title":"Instance Ids","description":"List of instance IDs associated with the cell specification"},"default_parameterized_model_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Default Parameterized Model Id","description":"ID of the parameterized model marked as this specification's default model, or None if unset."}},"type":"object","required":["name","ratings","id","organization_id","project_id"],"title":"CellSpecification","description":"Model representing a cell specification as returned by the API."},"CellSpecificationWithComponents":{"properties":{"name":{"type":"string","title":"Name","description":"Name of the cell specification"},"form_factor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Form Factor","description":"Physical form factor. Common values: '18650', '21700', 'R2032' (coin cell), 'pouch', 'prismatic', 'cylindrical'."},"manufacturer":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Manufacturer","description":"Who assembled/manufactured the cell"},"ratings":{"$ref":"#/components/schemas/Ratings","description":"Electrical ratings from the spec sheet / design targets (rated capacity, voltage min/max, optional nominal voltage, energy, energy densities, max charge/discharge C-rates). See :class:`Ratings`."},"anode_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Anode Id","description":"ID of the anode component"},"cathode_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cathode Id","description":"ID of the cathode component"},"electrolyte_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Electrolyte Id","description":"ID of the electrolyte component"},"separator_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Separator Id","description":"ID of the separator component"},"case_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Case Id","description":"ID of the case component"},"properties":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Properties","description":"Other design-level properties that are not electrical ratings and not tied to a specific component — e.g. assembly method, overall cell dimensions, mass, target thickness. Numeric values must use the Quantity format ({'value': ..., 'unit': ...})."},"source":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Source","description":"Provenance of the design. Typical keys: 'doi', 'citation', 'publication_date' (ISO 8601), 'license', 'creator_name', 'creator_orcid'. Lives on the specification (not the instance) because it describes the published design."},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes","description":"Free-text notes about the cell specification"},"id":{"type":"string","title":"Id","description":"Unique identifier for the cell specification"},"organization_id":{"type":"string","title":"Organization Id","description":"Organization ID of the cell specification"},"project_id":{"type":"string","title":"Project Id","description":"Project this cell specification belongs to"},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At","description":"When this specification was created"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At","description":"When this specification was last modified"},"created_by":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created By","description":"User ID of the user who created this specification"},"created_by_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created By Email","description":"Email of the user who created this specification"},"instance_ids":{"anyOf":[{"items":{"additionalProperties":true,"type":"object"},"type":"array"},{"type":"null"}],"title":"Instance Ids","description":"List of instance IDs associated with the cell specification"},"default_parameterized_model_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Default Parameterized Model Id","description":"ID of the parameterized model marked as this specification's default model, or None if unset."},"anode":{"anyOf":[{"$ref":"#/components/schemas/CellComponentWithMaterial"},{"type":"null"}],"description":"Anode component with material"},"cathode":{"anyOf":[{"$ref":"#/components/schemas/CellComponentWithMaterial"},{"type":"null"}],"description":"Cathode component with material"},"electrolyte":{"anyOf":[{"$ref":"#/components/schemas/CellComponentWithMaterial"},{"type":"null"}],"description":"Electrolyte component with material"},"separator":{"anyOf":[{"$ref":"#/components/schemas/CellComponentWithMaterial"},{"type":"null"}],"description":"Separator component with material"},"case":{"anyOf":[{"$ref":"#/components/schemas/CellComponentWithMaterial"},{"type":"null"}],"description":"Case component with material"}},"type":"object","required":["name","ratings","id","organization_id","project_id"],"title":"CellSpecificationWithComponents","description":"Cell specification with nested component information."},"Channel":{"properties":{"name":{"type":"string","title":"Name","description":"Name of the channel"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes","description":"Free-text notes about the channel"},"cycler_id":{"type":"string","title":"Cycler Id","description":"Foreign key to the parent cycler"},"max_amps":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max Amps","description":"Maximum rated current for the channel, in amps (A)."},"min_volts":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Volts","description":"Minimum rated voltage for the channel, in volts (V)."},"max_volts":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max Volts","description":"Maximum rated voltage for the channel, in volts (V)."},"id":{"type":"string","title":"Id","description":"Unique identifier for the channel"},"out_of_commission":{"type":"boolean","title":"Out Of Commission","description":"Whether the channel is deliberately out of service (broken or under maintenance). An out-of-commission channel is shown as such in the Lab view and is not counted as available.","default":false},"organization_id":{"type":"string","title":"Organization Id","description":"Organization this channel belongs to."},"project_id":{"type":"string","title":"Project Id","description":"Project that owns this channel (inherited from its cycler)"},"created_by":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created By","description":"User ID of the user who created this channel"},"created_by_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created By Email","description":"Email of the user who created this channel"},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"Timestamp when the channel was created"},"updated_at":{"type":"string","format":"date-time","title":"Updated At","description":"Timestamp when the channel was last updated"}},"type":"object","required":["name","cycler_id","id","organization_id","project_id","created_at","updated_at"],"title":"Channel","description":"Model representing a channel as returned by the API."},"ChannelRecovery":{"properties":{"recovered":{"type":"integer","title":"Recovered","description":"Outages closed during the period — channels repaired"},"taken_out":{"type":"integer","title":"Taken Out","description":"Outages opened during the period — channels removed"},"net":{"type":"integer","title":"Net","description":"recovered - taken_out. Positive means capacity returning."},"mean_repair_hours":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Mean Repair Hours","description":"Mean hours from outage start to resolution over the period's closed incidents, excluding rows whose start was estimated by the backfill. Null when nothing measurable was resolved."},"by_category":{"additionalProperties":{"type":"integer"},"type":"object","title":"By Category","description":"Count of the period's closed outages by cause"}},"type":"object","required":["recovered","taken_out","net"],"title":"ChannelRecovery","description":"Channels repaired and taken out of service during the period.\n\nCounted from ``channel_incidents`` outage spans, so these are maintenance\nevents rather than the capacity proxy this once carried: ``recovered`` means\nan outage was closed, not that a channel happened to start running again.\n\n``taken_out`` is deliberately not called ``dropped``. The proxy's \"dropped\"\nmeant \"stopped running anything\", which a fully-booked lab produces all the\ntime; this counts only a deliberate removal from service."},"ChannelRef":{"properties":{"channel_id":{"type":"string","title":"Channel Id","description":"Channel ID"},"channel_name":{"type":"string","title":"Channel Name","description":"Channel name"},"cycler_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cycler Id","description":"Owning cycler ID"},"cycler_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cycler Name","description":"Owning cycler name"},"site_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Site Name","description":"Site the cycler sits at"}},"type":"object","required":["channel_id","channel_name"],"title":"ChannelRef","description":"Where a channel lives, denormalized so a report row stands alone."},"ChannelState":{"type":"string","enum":["free","occupied","stale","out_of_commission"],"title":"ChannelState","description":"Derived occupancy state of a channel in the Lab view.\n\nThere is no live telemetry; state is derived from the channel's linked\nmeasurements (a measurement references its channel via ``channel_id``):\n\n- ``free`` — no linked measurement, or every linked measurement has an\n  ``end_time`` set (all tests finished). The channel is available.\n- ``occupied`` — a linked measurement has ``end_time`` null and was updated\n  within the staleness window (data is fresh); a cell is on test now.\n- ``stale`` — a linked measurement has ``end_time`` null but has not been\n  updated within the staleness window. Likely a stopped or silently failed\n  test, or one someone forgot to mark complete; needs a human to resolve\n  (mark it complete to free the channel).\n- ``out_of_commission`` — the channel is deliberately out of service\n  (broken / maintenance). This overrides any derived state above."},"CheckProtocolNameRequest":{"properties":{"name":{"type":"string","maxLength":200,"title":"Name","description":"The protocol name to check, as the user typed it."},"protocol":{"anyOf":[{"type":"string"},{"additionalProperties":true,"type":"object"}],"title":"Protocol","description":"The protocol as UCP YAML text or a parsed mapping."},"name_from_file":{"type":"boolean","title":"Name From File","description":"True when the name came from an uploaded protocol file rather than from the user. The check then returns 'uncheckable' without calling the model: the name is the vendor file's, so a mismatch is not something the user can act on.","default":false}},"type":"object","required":["name","protocol"],"title":"CheckProtocolNameRequest","description":"Request body for checking a protocol name against its protocol."},"CheckProtocolNameResponse":{"properties":{"verdict":{"type":"string","title":"Verdict","description":"'match' when nothing in the name contradicts the protocol, 'mismatch' when something does, 'uncheckable' when the name makes no claim to check (a codename, an identifier, or a name carried in from a file). Only 'mismatch' should surface anything in the UI."},"confidence":{"type":"number","title":"Confidence","description":"Confidence in a 'mismatch' verdict, 0-1. Above 0.8 is a contradiction pinned to a number; around 0.5 is a judgement call on wording. Always 1.0 for 'match' and 'uncheckable'."},"mismatches":{"items":{"$ref":"#/components/schemas/NameMismatchResponse"},"type":"array","title":"Mismatches","description":"One entry per contradicted claim, most important first."},"summary":{"type":"string","title":"Summary","description":"One sentence naming the contradiction. Empty unless mismatched.","default":""},"suggested_name":{"type":"string","title":"Suggested Name","description":"A corrected name in the user's own style, or empty when there is nothing to correct or the correction equals the current name.","default":""}},"type":"object","required":["verdict","confidence"],"title":"CheckProtocolNameResponse","description":"The verdict on whether a name describes its protocol."},"ClarificationAnswer":{"properties":{"question":{"type":"string","maxLength":2000,"title":"Question"},"answer":{"type":"string","maxLength":4000,"title":"Answer"}},"type":"object","required":["question","answer"],"title":"ClarificationAnswer","description":"One question the user has already answered."},"ClarifyingQuestionResponse":{"properties":{"question":{"type":"string","title":"Question"},"why":{"type":"string","title":"Why","default":""},"options":{"items":{"type":"string"},"type":"array","title":"Options"}},"type":"object","required":["question"],"title":"ClarifyingQuestionResponse","description":"A question the user must answer before the protocol can be written."},"ColumnSpec":{"properties":{"name":{"type":"string","title":"Name","description":"Display name stored in the processed parquet"},"unit":{"type":"string","title":"Unit","description":"Physical unit, e.g. 'mol.L-1' or 'S.m-1'. Empty string for unitless quantities.","default":""},"source_column_index":{"type":"integer","title":"Source Column Index","description":"0-based column position in the uploaded file. The column at this position is selected and stored under ``name``. Required for all uploads regardless of whether the file has a header row."}},"type":"object","required":["name","source_column_index"],"title":"ColumnSpec","description":"One column in a material property dataset, with its unit and role."},"CompareProtocolsRequest":{"properties":{"left":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"string"}],"title":"Left","description":"First UCP, as a dict or YAML string."},"right":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"string"}],"title":"Right","description":"Second UCP, as a dict or YAML string."}},"type":"object","required":["left","right"],"title":"CompareProtocolsRequest","description":"Request body for comparing two UCPs for semantic equality."},"CompareProtocolsResponse":{"properties":{"equal":{"type":"boolean","title":"Equal","description":"True when the protocols would make a cycler do the same thing. Differences that no tolerance explains make this False rather than being ignored."},"differences":{"items":{"$ref":"#/components/schemas/ProtocolDifference"},"type":"array","title":"Differences","description":"Every difference found, earliest first. Empty when equal."}},"type":"object","required":["equal"],"title":"CompareProtocolsResponse","description":"Result of comparing two protocols."},"ComparisonWindow":{"properties":{"days":{"type":"integer","title":"Days","description":"Length of each window, in days"},"current_start":{"type":"string","format":"date-time","title":"Current Start","description":"Start of the window the metrics describe"},"current_end":{"type":"string","format":"date-time","title":"Current End","description":"End of that window — the report's own generation time"},"previous_start":{"type":"string","format":"date-time","title":"Previous Start","description":"Start of the window immediately before it. It ends where the current one starts, so the two are adjacent and non-overlapping."}},"type":"object","required":["days","current_start","current_end","previous_start"],"title":"ComparisonWindow","description":"The two windows a period-over-period delta compares.\n\nCarried in the payload rather than left implicit so a reader — and an API\nconsumer — never has to work out what \"the previous period\" was. A delta of\n+2 repairs means nothing until you know whether it is against last week or\nlast month, and the report states it once per section instead of appending a\nvague suffix to every metric."},"ComponentType":{"type":"string","enum":["cathode","anode","electrolyte","separator","case","cell"],"title":"ComponentType","description":"Enum for cell component types."},"ComputeJobType":{"type":"string","enum":["simulation","datafit","optimization","validation","pipeline"],"title":"ComputeJobType","description":"Job types whose backend runtime accrues toward compute usage."},"ComputeUsage":{"properties":{"usage":{"type":"number","title":"Usage","default":0},"usage_by_type":{"additionalProperties":{"type":"number"},"propertyNames":{"$ref":"#/components/schemas/ComputeJobType"},"type":"object","title":"Usage By Type","default":{}},"limit":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Limit"}},"type":"object","title":"ComputeUsage","description":"Current compute usage and its configured limit, in hours.\n\n``usage`` is the total across all job types; ``usage_by_type`` breaks it\ndown (informational — the ``limit`` applies to the total)."},"ConfirmLogoUploadRequest":{"properties":{"content_type":{"type":"string","title":"Content Type","description":"MIME type used for the upload. Must match the initiate request, since it determines the path the object was written to."}},"type":"object","required":["content_type"],"title":"ConfirmLogoUploadRequest","description":"Record a logo that has been uploaded to its signed URL."},"ConfirmRawDataUploadRequest":{"properties":{"project_id":{"type":"string","title":"Project Id","description":"Owning project ID (required)."},"name":{"type":"string","title":"Name","description":"User-provided label for the raw file."},"source":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source","description":"Free-text provenance: where this raw file came from (a URL, DOI, S3 URI, vendor/cycler export description, etc.)."},"metadata":{"additionalProperties":true,"type":"object","title":"Metadata","description":"Loose free-form metadata."},"filename":{"type":"string","title":"Filename","description":"Filename that was uploaded."},"content_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Content Type","description":"MIME type, if known."},"size_bytes":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Size Bytes","description":"File size in bytes, computed client-side."},"process":{"type":"boolean","title":"Process","description":"Start server-side ingestion (parse, validate, review queue) immediately. Defaults to False: clients that process the file themselves and upload the resulting measurement would otherwise get a second, server-derived attempt at the same file. Records left unprocessed are still picked up by the raw-data scan.","default":false}},"type":"object","required":["project_id","name","filename"],"title":"ConfirmRawDataUploadRequest","description":"Body for POST /raw_data/{raw_data_id}/confirm-upload.\n\nRepeats the record metadata (same as initiate, so no orphan record is\ncreated if the PUT fails) plus the uploaded file's filename, content type,\nand client-computed size. The server recomputes the storage path from\norganization_id + raw_data_id + filename; a client-supplied path is never\ntrusted."},"ConfirmUploadRequest":{"properties":{"cell_instance_id":{"type":"string","title":"Cell Instance Id","description":"Parent cell instance ID"},"measurement":{"additionalProperties":true,"type":"object","title":"Measurement","description":"Measurement data with custom fields"},"measurement_type":{"$ref":"#/components/schemas/MeasurementType","description":"Type of measurement being confirmed.","default":"time_series"},"steps":{"additionalProperties":true,"type":"object","title":"Steps","description":"Optional steps. Auto-calculated from time series if omitted"},"filenames":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Filenames","description":"Filenames that were uploaded (for file-type measurements). When provided, skips the slow storage listing verification."}},"type":"object","required":["cell_instance_id","measurement"],"title":"ConfirmUploadRequest","description":"Request model for confirming a signed URL upload."},"ControlStep":{"properties":{"kind":{"type":"string","const":"control","title":"Kind","description":"The type of this step","default":"control"},"set_variable":{"items":{"$ref":"#/components/schemas/SetVariable"},"type":"array","title":"Set Variable","description":"Variables to set based on this step"},"note":{"type":"string","title":"Note","description":"An optional note for the step.","default":""},"goto":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Goto","description":"Optional goto target step name after executing this control step."}},"additionalProperties":false,"type":"object","title":"ControlStep","description":"A step for control logic that does not run a simulation."},"ConvertProtocolRequest":{"properties":{"protocol":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"string"}],"title":"Protocol","description":"UCP as a dict or YAML string."},"target":{"type":"string","enum":["maccor","arbin","arbin_sdx","neware","biologic_bttest","novonix"],"title":"Target","description":"Vendor target: 'maccor', 'arbin', 'neware', 'biologic_bttest', or 'novonix'."},"drive_cycles":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Drive Cycles","description":"Optional mapping of drive cycle name → samples. Required when the protocol references DriveCycle steps."},"filename_stem":{"type":"string","title":"Filename Stem","description":"Stem for the returned primary filename (no extension).","default":"protocol"},"nominal_capacity_ah":{"anyOf":[{"type":"number","exclusiveMinimum":0.0},{"type":"null"}],"title":"Nominal Capacity Ah","description":"Rated cell capacity in A.h, from the cell specification. Required for 'neware' when the protocol uses C-rate steps or cutoffs: Neware sets current in absolute mA and has no C-rate mode, so the rate cannot be resolved without it. Ignored by other targets, which express C-rate natively."},"verify":{"type":"boolean","title":"Verify","description":"Round-trip the emitted file back through its parser and refuse the conversion (400) if the protocol no longer means the same thing. A writer that drops a loop count, a goto, or a safety bound emits a valid file that simulates identically, so the loss would otherwise only show up on hardware. A re-encoding the target format forces — a C-rate resolved to absolute amps on a format with no C-rate type — is allowed. Off by default: the checker still reports two benign round-trip artifacts of Maccor/Arbin/Neware (explicit fall-through gotos and an appended terminal step) as differences, so enabling it by default would refuse most valid conversions to those targets.","default":false}},"type":"object","required":["protocol","target"],"title":"ConvertProtocolRequest","description":"Request body for converting a UCP to a vendor-native protocol file."},"ConvertProtocolResponse":{"properties":{"target":{"type":"string","title":"Target"},"primary":{"$ref":"#/components/schemas/ConvertedFile"},"assets":{"items":{"$ref":"#/components/schemas/ConvertedFile"},"type":"array","title":"Assets"},"warnings":{"items":{"type":"string"},"type":"array","title":"Warnings"}},"type":"object","required":["target","primary"],"title":"ConvertProtocolResponse"},"ConvertedFile":{"properties":{"filename":{"type":"string","title":"Filename"},"content_base64":{"type":"string","title":"Content Base64"},"media_type":{"type":"string","title":"Media Type"}},"type":"object","required":["filename","content_base64","media_type"],"title":"ConvertedFile"},"CopyOptimizationTemplateRequest":{"properties":{"project_id":{"type":"string","title":"Project Id"}},"type":"object","required":["project_id"],"title":"CopyOptimizationTemplateRequest","description":"Request body for copying a template to another project."},"CreateCellComponent":{"properties":{"component_type":{"$ref":"#/components/schemas/ComponentType","description":"Type of the component"},"material_id":{"type":"string","title":"Material Id","description":"ID of the material"},"properties":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Properties","description":"Application properties using Quantity format for numerics. Example: {'diameter': {'value': 14, 'unit': 'mm'}, 'binder': 'PVDF'}"},"project_id":{"type":"string","title":"Project Id","description":"Project the component is scoped to. Required."}},"type":"object","required":["component_type","material_id","project_id"],"title":"CreateCellComponent","description":"Model for creating a new cell component."},"CreateCellSpecificationNested":{"properties":{"name":{"type":"string","title":"Name","description":"Name of the cell specification"},"form_factor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Form Factor","description":"Form factor (e.g., R2032, 18650, pouch)"},"manufacturer":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Manufacturer","description":"Who assembled/manufactured the cell"},"ratings":{"$ref":"#/components/schemas/Ratings","description":"Electrical ratings from spec sheet"},"properties":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Properties","description":"Non-electrical design properties (assembly_method, etc.)"},"source":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Source","description":"Source/provenance info: doi, license, publication_date, citation, creator_name, creator_orcid"},"anode":{"anyOf":[{"$ref":"#/components/schemas/NestedComponentInput"},{"type":"null"}],"description":"Anode component with material"},"cathode":{"anyOf":[{"$ref":"#/components/schemas/NestedComponentInput"},{"type":"null"}],"description":"Cathode component with material"},"electrolyte":{"anyOf":[{"$ref":"#/components/schemas/NestedComponentInput"},{"type":"null"}],"description":"Electrolyte component with material"},"separator":{"anyOf":[{"$ref":"#/components/schemas/NestedComponentInput"},{"type":"null"}],"description":"Separator component with material"},"case":{"anyOf":[{"$ref":"#/components/schemas/NestedComponentInput"},{"type":"null"}],"description":"Case component with material"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes","description":"Optional notes about the cell specification"},"project_id":{"type":"string","title":"Project Id","description":"Project to associate with"}},"type":"object","required":["name","ratings","project_id"],"title":"CreateCellSpecificationNested","description":"Model for creating a cell specification with nested component/material data.\n\nComponents and materials are upserted based on uniqueness constraints:\n- Materials: unique on (organization_id, name, manufacturer, product_id)\n- Components: unique on (organization_id, component_type, material_id, properties)"},"CreateExperimentTemplateBody":{"properties":{"name":{"type":"string","title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"protocol_config":{"additionalProperties":true,"type":"object","title":"Protocol Config"},"parameters_schema":{"additionalProperties":true,"type":"object","title":"Parameters Schema","default":{}},"time_series_spec":{"additionalProperties":true,"type":"object","title":"Time Series Spec","default":{}},"metrics_spec":{"additionalProperties":true,"type":"object","title":"Metrics Spec","default":{}},"source_protocol":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Protocol"},"force_create":{"type":"boolean","title":"Force Create","default":false},"project_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Id"},"protocol_group_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Protocol Group Id"}},"type":"object","required":["name","protocol_config"],"title":"CreateExperimentTemplateBody","description":"Request body for creating an experiment template."},"CreateMaterial":{"properties":{"name":{"type":"string","title":"Name","description":"Name of the material"},"definition":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Definition","description":"Material definition (formula, type, constituents)"},"manufacturer":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Manufacturer","description":"Manufacturer of the material"},"product_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Product Id","description":"Supplier product ID"},"project_id":{"type":"string","title":"Project Id","description":"Project the material is scoped to. Required."}},"type":"object","required":["name","project_id"],"title":"CreateMaterial","description":"Model for creating a new material."},"CreateMeasurementResponse":{"properties":{"name":{"type":"string","maxLength":255,"minLength":1,"title":"Name"},"protocol":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Protocol","description":"Protocol information. Typical keys: 'name' (str), 'ambient_temperature_degc' (float), 'definition' (dict | str — a UCP protocol definition or another protocol format)."},"start_time":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Start Time","description":"ISO 8601 datetime with timezone (UTC preferred) marking when the test started."},"end_time":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"End Time","description":"ISO 8601 datetime with timezone (UTC preferred) marking when the test finished. Leave null while the test is still running; set it once the measurement is complete. A null end_time means the cell is still considered 'on test' in the Lab view."},"estimated_end_time":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Estimated End Time","description":"ISO 8601 datetime with timezone (UTC preferred) forecasting when a still-running test will finish. Distinct from end_time (the actual finish): this is an estimate. Null when no estimate has been computed yet."},"estimated_end_time_note":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Estimated End Time Note","description":"Free-text explanation of how estimated_end_time was derived."},"estimated_end_time_calculated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Estimated End Time Calculated At","description":"ISO 8601 datetime with timezone marking when estimated_end_time was last computed."},"test_setup":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Test Setup","description":"Physical test setup. Typical keys: 'cycler' (model), 'operator', 'lab', 'channel_number' (int)."},"step_labels_validated":{"type":"boolean","title":"Step Labels Validated","description":"Set to true only once step-type labels (Rest, CC charge, CV, discharge, etc.) have been manually reviewed. Server-inferred labels should leave this false.","default":false},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes","description":"Free-text notes about the cell measurement"},"measurement_type":{"$ref":"#/components/schemas/MeasurementType","description":"What shape of data this measurement holds. Determines which fields are populated and which upload flow applies. See the class docstring.","default":"time_series"},"properties":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Properties","description":"Flat key/value measurements, populated only when measurement_type is 'properties'. Numeric values use the Quantity format. Example: {'thickness': {'value': 0.52, 'unit': 'mm'}, 'DCIR': {'value': 12, 'unit': 'mohm'}}."},"file_metadata":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"File Metadata","description":"Metadata about uploaded files (MIME types, dimensions, etc.)"},"channel_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Channel Id","description":"Optional ID of the channel this measurement ran on."},"protocol_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Protocol Id","description":"Optional ID of the experiment template (protocol) this measurement was run against."},"program_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Program Id","description":"Optional catalog program for this measurement (copied from a linked planned measurement when present)."},"id":{"type":"string","title":"Id"},"cell_instance_id":{"type":"string","title":"Cell Instance Id"},"organization_id":{"type":"string","title":"Organization Id","description":"Organization this measurement belongs to."},"project_id":{"type":"string","title":"Project Id","description":"Project this measurement belongs to"},"created_by":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created By","description":"User ID of the user who created this measurement"},"created_by_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created By Email","description":"Email of the user who created this measurement"},"processing_status":{"$ref":"#/components/schemas/MeasurementProcessingStatus","description":"Lifecycle of server-side step processing. 'ready' once steps are available; 'pending'/'running' while the upload is being processed asynchronously; 'failed' if processing failed (see processing_error).","default":"ready"},"processing_error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Processing Error","description":"Reason processing failed, when processing_status is 'failed'. Also carries why an extend did not apply, in which case the status is back to 'ready' and this is advisory only."},"source_etag":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Etag"},"row_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Row Count"},"time_series_bytes":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Time Series Bytes"},"estimated_end_time_status":{"anyOf":[{"$ref":"#/components/schemas/EstimationStatus"},{"type":"null"}]},"estimated_end_time_job_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Estimated End Time Job Id"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"extend_claim_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Extend Claim Id","description":"Opaque token identifying the in-flight extend that holds this measurement, and the staging prefix its delta is uploaded to. Non-null exactly while processing_status is 'awaiting_extend' or 'extending'."},"extend_in_progress_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Extend In Progress At","description":"Deprecated and always null. Use processing_status."},"extend_claimed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Extend Claimed At","description":"When the in-flight extend claim was taken. Written only by the claim itself, so an unrelated update to the measurement does not age it. Null when no extend holds the measurement."},"instance":{"$ref":"#/components/schemas/CellInstance"},"steps_created":{"type":"integer","title":"Steps Created"}},"type":"object","required":["name","id","cell_instance_id","organization_id","project_id","created_at","updated_at","instance","steps_created"],"title":"CreateMeasurementResponse","description":"Flat response after confirming a signed URL upload.\n\nMeasurement fields (id, name, measurement_type, etc.) are at the top level,\nalongside the parent instance and upload metadata."},"CreateModel":{"properties":{"name":{"type":"string","title":"Name","description":"The name of the model."},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"An optional description for the model."},"pybamm_version":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Pybamm Version","description":"PyBaMM version used for this model. If not provided, will be read from pybamm.__version__."},"chemistry":{"type":"string","enum":["lithium_ion","lithium_sulfur","ecm","generic"],"title":"Chemistry","description":"Model chemistry kind: 'lithium_ion' (default — assumes pybamm lithium-ion conventions), 'lithium_sulfur', 'ecm', or 'generic' (no chemistry-specific enrichment).","default":"lithium_ion"},"simulation_settings":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Simulation Settings","description":"Optional persistent simulation kwargs (var_pts / submesh_types / spatial_methods / geometry / solver) in the flat canonical form, re-applied at simulation time. None uses the model defaults."},"config":{"additionalProperties":true,"type":"object","title":"Config","description":"Model configuration stored as JSON."}},"type":"object","required":["name","config"],"title":"CreateModel","description":"Model for creating a new model."},"CreateOptimizationTemplate":{"properties":{"name":{"type":"string","title":"Name","description":"The name of the optimization template."},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"An optional description for the template."},"initial_form_data":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Initial Form Data","description":"Initial form data values."},"project_id":{"type":"string","title":"Project Id","description":"The ID of the project this template belongs to."}},"type":"object","required":["name","project_id"],"title":"CreateOptimizationTemplate","description":"Model for creating a new optimization template.\n\nValidates initial_form_data against DesignOptimizationDataFitConfigSchema\nto ensure new templates conform to the current schema."},"CreateParameterizedModelBody":{"properties":{"name":{"type":"string","title":"Name"},"description":{"type":"string","title":"Description","default":""},"model_id":{"type":"string","title":"Model Id"},"parameters":{"additionalProperties":true,"type":"object","title":"Parameters","default":{}},"simulation_settings":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Simulation Settings"}},"type":"object","required":["name","model_id"],"title":"CreateParameterizedModelBody","description":"Request body for creating a parameterized model.\n\nThe frontend sends all parameter values directly - no library presets or BPX."},"CreatePlannedMeasurement":{"properties":{"name":{"type":"string","maxLength":255,"minLength":1,"title":"Name"},"cell_specification_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cell Specification Id","description":"Cell specification the requester wants tested (set at request time)."},"cell_instance_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cell Instance Id","description":"Cell instance this future measurement will run on."},"channel_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Channel Id","description":"Channel reserved for this measurement, once scheduled."},"set_temperature_c":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Set Temperature C","description":"Temperature this test must run at, in degrees Celsius, held fixed for the whole test. None means ambient: the test runs outside a thermal chamber."},"thermal_chamber_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Thermal Chamber Id","description":"Chamber this test's channel sits in for the reservation. Recorded per reservation rather than per channel, because channels move between chambers."},"protocol_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Protocol Id","description":"Named protocol (experiment_template) this measurement will run. Required on create; a planned measurement must name a protocol."},"program_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Program Id","description":"Optional catalog program (Formation, Cycling, …) for this test request."},"test_setup":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Test Setup","description":"Planned physical setup."},"planned_start_time":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Planned Start Time","description":"When setup/run is planned to start."},"planned_end_time":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Planned End Time","description":"When this planned measurement is expected to release the channel."},"estimated_duration_seconds":{"anyOf":[{"type":"integer","minimum":1.0},{"type":"null"}],"title":"Estimated Duration Seconds","description":"Expected run duration before scheduled times exist."},"setup_duration_seconds":{"type":"integer","minimum":0.0,"title":"Setup Duration Seconds","description":"Operator setup duration before the test starts.","default":0},"teardown_duration_seconds":{"type":"integer","minimum":0.0,"title":"Teardown Duration Seconds","description":"Operator teardown duration after the test finishes.","default":0},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes","description":"Free-text planning notes."},"status":{"$ref":"#/components/schemas/PlannedMeasurementStatus","description":"Initial planned measurement status.","default":"requested"}},"type":"object","required":["name"],"title":"CreatePlannedMeasurement","description":"Request model for creating a planned measurement."},"CreateProject":{"properties":{"name":{"type":"string","title":"Name","description":"The name of the project."},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"An optional description for the project."}},"type":"object","required":["name"],"title":"CreateProject"},"CreateProjectWebhook":{"properties":{"url":{"type":"string","title":"Url","description":"HTTPS destination URL."},"events":{"items":{"$ref":"#/components/schemas/WebhookEvent"},"type":"array","minItems":1,"title":"Events","description":"Events that should trigger delivery."},"enabled":{"type":"boolean","title":"Enabled","description":"Whether the webhook is active.","default":true}},"type":"object","required":["url","events"],"title":"CreateProjectWebhook","description":"Request body for creating a project webhook."},"CreatePropertiesMeasurementRequest":{"properties":{"name":{"type":"string","maxLength":255,"minLength":1,"title":"Name"},"protocol":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Protocol","description":"Protocol information. Typical keys: 'name' (str), 'ambient_temperature_degc' (float), 'definition' (dict | str — a UCP protocol definition or another protocol format)."},"start_time":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Start Time","description":"ISO 8601 datetime with timezone (UTC preferred) marking when the test started."},"end_time":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"End Time","description":"ISO 8601 datetime with timezone (UTC preferred) marking when the test finished. Leave null while the test is still running; set it once the measurement is complete. A null end_time means the cell is still considered 'on test' in the Lab view."},"estimated_end_time":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Estimated End Time","description":"ISO 8601 datetime with timezone (UTC preferred) forecasting when a still-running test will finish. Distinct from end_time (the actual finish): this is an estimate. Null when no estimate has been computed yet."},"estimated_end_time_note":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Estimated End Time Note","description":"Free-text explanation of how estimated_end_time was derived."},"estimated_end_time_calculated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Estimated End Time Calculated At","description":"ISO 8601 datetime with timezone marking when estimated_end_time was last computed."},"test_setup":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Test Setup","description":"Physical test setup. Typical keys: 'cycler' (model), 'operator', 'lab', 'channel_number' (int)."},"step_labels_validated":{"type":"boolean","title":"Step Labels Validated","description":"Set to true only once step-type labels (Rest, CC charge, CV, discharge, etc.) have been manually reviewed. Server-inferred labels should leave this false.","default":false},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes","description":"Free-text notes about the cell measurement"},"measurement_type":{"$ref":"#/components/schemas/MeasurementType","description":"Must be 'properties' for this endpoint.","default":"properties"},"properties":{"additionalProperties":true,"type":"object","title":"Properties","description":"Key-value measurements using Quantity format for numerics. Example: {'thickness': {'value': 0.52, 'unit': 'mm'}}"},"file_metadata":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"File Metadata","description":"Metadata about uploaded files (MIME types, dimensions, etc.)"},"channel_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Channel Id","description":"Optional ID of the channel this measurement ran on."},"protocol_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Protocol Id","description":"Optional ID of the experiment template (protocol) this measurement was run against."},"program_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Program Id","description":"Optional catalog program for this measurement (copied from a linked planned measurement when present)."}},"type":"object","required":["name","properties"],"title":"CreatePropertiesMeasurementRequest","description":"Request model for creating a properties-type measurement directly (no upload).\n\nInherits field validation (including ``validate_properties``) from\n``CellMeasurementBase``.  Overrides ``measurement_type`` default and\nmakes ``properties`` required."},"CreateProtocolGroupBody":{"properties":{"name":{"type":"string","title":"Name","description":"Name of the group, unique within the project"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"Optional description"},"project_id":{"type":"string","title":"Project Id","description":"Project that will own the group"}},"type":"object","required":["name","project_id"],"title":"CreateProtocolGroupBody","description":"Request body for creating a protocol group."},"CreateSessionRequest":{"properties":{"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title"}},"type":"object","title":"CreateSessionRequest","description":"Body for creating a chat session."},"CreateSimplePipelineRequest":{"properties":{"project_id":{"type":"string","title":"Project Id","description":"Project ID to associate the pipeline with"},"name":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Name","description":"Optional human-readable name for the pipeline"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"Optional human-readable description for the pipeline"},"config":{"additionalProperties":true,"type":"object","title":"Config","description":"Pipeline configuration with elements dict. At most one datafit/validation element, any number of cheap elements."},"options":{"anyOf":[{"$ref":"#/components/schemas/PipelineOptions"},{"type":"null"}],"description":"Runtime execution options (e.g. live_progress_updates). Submission metadata, not stored in the pipeline config."}},"type":"object","required":["project_id","config"],"title":"CreateSimplePipelineRequest","description":"Request body for creating a SimplePipeline."},"CreateSimulationBatchBody":{"properties":{"parameterized_model":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"string"}],"title":"Parameterized Model"},"experiment_template_id":{"type":"string","title":"Experiment Template Id"},"conditions":{"anyOf":[{"items":{"$ref":"#/components/schemas/BatchCondition"},"type":"array"},{"type":"null"}],"title":"Conditions"},"experiment_parameter_sets":{"anyOf":[{"items":{"additionalProperties":true,"type":"object"},"type":"array"},{"type":"null"}],"title":"Experiment Parameter Sets"},"experiment_conditions":{"anyOf":[{"items":{"additionalProperties":{"type":"string"},"type":"object"},"type":"array"},{"type":"null"}],"title":"Experiment Conditions"},"design_parameters_doe":{"anyOf":[{"$ref":"#/components/schemas/DOERequest"},{"type":"null"}]},"study_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Study Id"},"project_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Id"},"max_backward_jumps":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Max Backward Jumps"},"extra_variables":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Extra Variables"},"variable_callback_rules":{"anyOf":[{"items":{"additionalProperties":true,"type":"object"},"type":"array"},{"type":"null"}],"title":"Variable Callback Rules"},"termination_condition_rules":{"anyOf":[{"items":{"additionalProperties":true,"type":"object"},"type":"array"},{"type":"null"}],"title":"Termination Condition Rules"},"treat_pause_as_rest":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Treat Pause As Rest"},"force_rerun":{"type":"boolean","title":"Force Rerun","default":false}},"type":"object","required":["parameterized_model","experiment_template_id"],"title":"CreateSimulationBatchBody","description":"Request body for creating multiple simulations with single model/template."},"CustomEnd":{"properties":{"type":{"type":"string","enum":["Voltage","Current","C-rate","Temperature","AnodePotential","CathodePotential"],"title":"Type","description":"Type of end condition"},"operator":{"type":"string","enum":["<",">","<=",">="],"title":"Operator","description":"Operator for the condition, e.g. '>', '<', '>=', or '<='"},"value":{"type":"string","title":"Value","description":"Value of the end condition"},"derivative":{"type":"integer","enum":[0,1],"title":"Derivative","description":"Which time derivative to use for the end condition: 0 for the value itself, 1 for the first derivative.","default":0},"goto":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Goto","description":"Step to transition to after end is reached"},"aux_channel":{"anyOf":[{"type":"integer","minimum":1.0},{"type":"null"}],"title":"Aux Channel","description":"Auxiliary temperature-sensor input index for a Temperature end, on cyclers where the end targets one of several aux sensors wired to the channel (e.g. Maccor/Arbin's per-channel Nth-assigned sensor indexing, both 1-based). None uses the cycler's default/first sensor."}},"additionalProperties":false,"type":"object","required":["type","operator","value"],"title":"CustomEnd","description":"End condition for a step."},"CustomModelValidationResult":{"properties":{"success":{"type":"boolean","title":"Success"},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error"},"rhs_variables":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Rhs Variables"},"algebraic_variables":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Algebraic Variables"}},"type":"object","required":["success"],"title":"CustomModelValidationResult"},"Cycler":{"properties":{"name":{"type":"string","title":"Name","description":"Name of the cycler"},"manufacturer":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Manufacturer","description":"Manufacturer (make) of the cycler (e.g. Arbin, Maccor)"},"model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model","description":"Model (type) of the cycler (e.g. LBT-5V, Series 4000)"},"version":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Version","description":"Hardware/product version of the cycler. Distinct from firmware_version, which changes without the hardware changing."},"serial_number":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Serial Number","description":"Manufacturer serial number of the cycler"},"firmware_version":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Firmware Version","description":"Firmware revision currently installed on the cycler"},"hostname":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Hostname","description":"DNS name of the cycler control host on the lab network. Null for an instrument reachable only by IP."},"ip_address":{"anyOf":[{"type":"string","format":"ipvanyaddress"},{"type":"null"}],"title":"Ip Address","description":"IP address of the cycler control host (IPv4 or IPv6)"},"port":{"anyOf":[{"type":"integer","maximum":65535.0,"minimum":1.0},{"type":"null"}],"title":"Port","description":"TCP port the cycler control software listens on (1-65535)"},"last_calibrated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Calibrated At","description":"When the cycler was last calibrated. Null means never calibrated or not tracked — which reads as unknown, not as overdue."},"calibration_interval_days":{"anyOf":[{"type":"integer","exclusiveMinimum":0.0},{"type":"null"}],"title":"Calibration Interval Days","description":"Maximum time allowed between calibrations, in days. Null means the cycler is not on a calibration schedule."},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes","description":"Free-text notes about the cycler"},"site_id":{"type":"string","title":"Site Id","description":"Foreign key to the parent site"},"project_id":{"type":"string","title":"Project Id","description":"Project that owns this cycler"},"id":{"type":"string","title":"Id","description":"Unique identifier for the cycler"},"organization_id":{"type":"string","title":"Organization Id","description":"Organization this cycler belongs to."},"created_by":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created By","description":"User ID of the user who created this cycler"},"created_by_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created By Email","description":"Email of the user who created this cycler"},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"Timestamp when the cycler was created"},"updated_at":{"type":"string","format":"date-time","title":"Updated At","description":"Timestamp when the cycler was last updated"},"calibration_due_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Calibration Due At","description":"When calibration next falls due: last_calibrated_at plus calibration_interval_days. Read-only — a generated database column, so it can never disagree with the two fields it derives from. Null when either is unset (the cycler is not on a schedule, or has never been calibrated)."},"channel_ids":{"anyOf":[{"items":{"additionalProperties":true,"type":"object"},"type":"array"},{"type":"null"}],"title":"Channel Ids","description":"List of channel IDs belonging to this cycler"}},"type":"object","required":["name","site_id","project_id","id","organization_id","created_at","updated_at"],"title":"Cycler","description":"Model representing a cycler as returned by the API."},"CyclerServiceEvent":{"properties":{"id":{"type":"string","title":"Id","description":"Unique identifier for the service event"},"organization_id":{"type":"string","title":"Organization Id","description":"Organization this service event belongs to."},"project_id":{"type":"string","title":"Project Id","description":"Project that owns the cycler (pinned to it by FK)"},"cycler_id":{"type":"string","title":"Cycler Id","description":"The cycler being serviced"},"event_type":{"$ref":"#/components/schemas/ServiceEventType","description":"What kind of work this is"},"scheduled_for":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Scheduled For","description":"When the visit is booked. Required while the event is open; null is allowed on an event recorded after the fact."},"scheduled_until":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Scheduled Until","description":"When the booked visit is expected to end, making the booking a span rather than a start instant. Null on rows predating the column and on events recorded after the fact. A plan, not a constraint: a visit may legitimately run past it."},"performed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Performed At","description":"When the service was actually done. Null means the event is still open — at most one such event per cycler."},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes","description":"Free-text detail about the service"},"created_by":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created By","description":"User who opened or recorded the event"},"performed_by":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Performed By","description":"User who recorded the service as done"},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"Timestamp when the event row was created"},"updated_at":{"type":"string","format":"date-time","title":"Updated At","description":"Timestamp when the event row was last updated"}},"type":"object","required":["id","organization_id","project_id","cycler_id","event_type","created_at","updated_at"],"title":"CyclerServiceEvent","description":"One instrument-level service on a cycler.\n\nA service event is the thing a channel incident belongs to when the whole\ncycler is down. Calibration is performed on the *instrument*, so a\n40-channel cycler going in for its annual calibration is one event, not 40\nunrelated outages that happen to share a category. Channel incidents opened\nfor the event carry its id in ``service_event_id``, which is what lets one\naction close them together.\n\nAt most one event per cycler may be open (``performed_at`` null) — a unique\npartial index enforces it, so \"the current service\" is a single unambiguous\nrow and the open-event write path is safe to retry."},"DOERequest":{"properties":{"sampling":{"type":"string","title":"Sampling","default":"grid"},"rows":{"items":{"anyOf":[{"$ref":"#/components/schemas/DiscreteParam"},{"$ref":"#/components/schemas/RangeParam"},{"$ref":"#/components/schemas/NormalParam"}]},"type":"array","title":"Rows"},"count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Count"}},"type":"object","title":"DOERequest","description":"Design of Experiments request with rows.\n\nParameters\n----------\nsampling\n    Sampling strategy. Supported: ``grid`` (cartesian product).\nrows\n    List of parameter rows; each carries its own type and config fields.\ncount\n    Number of samples for non-grid methods (required). Ignored for\n    ``grid`` sampling."},"DailyUtilizationPoint":{"properties":{"sampled_at":{"type":"string","format":"date-time","title":"Sampled At","description":"Instant this point describes"},"channels_in_use":{"type":"integer","title":"Channels In Use","description":"Channels running a test then"},"utilization_percent":{"type":"number","title":"Utilization Percent","description":"channels_in_use over today's channel count"},"channels_out_of_service":{"type":"integer","title":"Channels Out Of Service","description":"Channels under an open outage at that instant","default":0},"utilization_of_available_percent":{"type":"number","title":"Utilization Of Available Percent","description":"channels_in_use over the channels that were actually usable then — today's channel count less those out of service at that instant. Computable historically only because outages have spans.","default":0.0}},"type":"object","required":["sampled_at","channels_in_use","utilization_percent"],"title":"DailyUtilizationPoint","description":"Lab utilization reconstructed at one instant in the trend window."},"DataFitConfig":{"properties":{"objectives":{"additionalProperties":true,"type":"object","title":"Objectives"},"parameters":{"additionalProperties":true,"type":"object","title":"Parameters"},"optimizer":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Optimizer"},"cost":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Cost"},"options":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Options"},"multistarts":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Multistarts"},"baseline_parameters":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Baseline Parameters"},"existing_parameters":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Existing Parameters"},"timeout":{"anyOf":[{"type":"integer","maximum":86400.0,"minimum":1.0},{"type":"null"}],"title":"Timeout","default":3600},"job_type":{"type":"string","title":"Job Type","description":"Job type: 'datafit' or 'optimize' (must match JobType enum values)","default":"datafit"},"selected_cell":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Selected Cell"},"selected_model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Selected Model"}},"type":"object","required":["objectives","parameters"],"title":"DataFitConfig"},"DataFitResponse":{"properties":{"parameter_values":{"additionalProperties":true,"type":"object","title":"Parameter Values"}},"type":"object","required":["parameter_values"],"title":"DataFitResponse"},"DeactivateUserResponse":{"properties":{"user_id":{"type":"string","title":"User Id"},"status":{"type":"string","title":"Status"},"deactivated_count":{"type":"integer","title":"Deactivated Count","default":0},"organizations":{"items":{"$ref":"#/components/schemas/AdminUserOrgMembership"},"type":"array","title":"Organizations"},"deactivated_organization_ids":{"items":{"type":"string"},"type":"array","title":"Deactivated Organization Ids"},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message"}},"type":"object","required":["user_id","status"],"title":"DeactivateUserResponse","description":"Per-user summary returned by single and bulk deactivation."},"DiscreteParam":{"properties":{"type":{"type":"string","const":"discrete","title":"Type","default":"discrete"},"name":{"type":"string","title":"Name"},"values":{"items":{"type":"number"},"type":"array","title":"Values"}},"type":"object","required":["name"],"title":"DiscreteParam","description":"Discrete parameter configuration.\n\nParameters\n----------\nname\n    Parameter name.\nvalues\n    List of allowed numeric values."},"DomainStatus":{"type":"string","enum":["queued","running","succeeded","failed","canceled"],"title":"DomainStatus","description":"Frontend-facing lifecycle status for an async resource."},"DriveCycle":{"properties":{"id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Id","description":"Unique identifier"},"name":{"type":"string","title":"Name","description":"Drive cycle filename (e.g. WLTP_5Ah_10%%_1800s.txt)"},"data":{"items":{"items":{"type":"number"},"type":"array"},"type":"array","title":"Data","description":"Two-column array [[time, current], ...]"},"content_hash":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Content Hash","description":"SHA-256 hash of name + canonical data for deduplication"},"organization_id":{"type":"string","title":"Organization Id","description":"Owning organization"},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At","description":"Creation timestamp"},"measurement_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Measurement Id","description":"Source measurement ID when drive cycle was extracted from measurement data"},"created_by":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created By","description":"User ID of the uploader. Drive cycles are deduplicated by content hash, so this is whoever uploaded the content first."}},"type":"object","required":["name","data","organization_id"],"title":"DriveCycle","description":"Pydantic model for the drive_cycles table."},"DriveCycleListItem":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"}},"type":"object","required":["id","name"],"title":"DriveCycleListItem","description":"Lightweight projection used in list responses."},"DriveCycleListResponse":{"properties":{"items":{"items":{"$ref":"#/components/schemas/DriveCycleListItem"},"type":"array","title":"Items"},"count":{"type":"integer","title":"Count"},"total":{"type":"integer","title":"Total"}},"type":"object","required":["items","count","total"],"title":"DriveCycleListResponse","description":"Paginated list of drive cycle list items."},"DriveCycleStep":{"properties":{"kind":{"type":"string","const":"drive_cycle","title":"Kind","description":"The type of this step","default":"drive_cycle"},"name":{"type":"string","title":"Name","description":"Name/key of the drive cycle data"},"mode":{"type":"string","enum":["Current","Power"],"title":"Mode","description":"Control mode the drive-cycle values are interpreted as. ``Current`` (default) treats the second data column as current in amps; ``Power`` treats it as power in watts.","default":"Current"},"note":{"type":"string","title":"Note","description":"An optional note for the step.","default":""},"duration":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Duration","description":"Maximum duration in seconds (drive cycle may end earlier)"},"ends":{"items":{"anyOf":[{"$ref":"#/components/schemas/CustomEnd"},{"$ref":"#/components/schemas/DurationEnd"},{"$ref":"#/components/schemas/CapacityEnd"},{"$ref":"#/components/schemas/LoopNumberEnd"},{"$ref":"#/components/schemas/VariableEnd"},{"$ref":"#/components/schemas/AndEnd"},{"$ref":"#/components/schemas/OrEnd"}]},"type":"array","title":"Ends","description":"End conditions that can terminate the drive cycle early"},"set_variable":{"items":{"$ref":"#/components/schemas/SetVariable"},"type":"array","title":"Set Variable","description":"Variables to set based on this step"},"resolution":{"anyOf":[{"$ref":"#/components/schemas/ResolutionConfig"},{"type":"null"}],"description":"Resolution for saving data for this step."}},"additionalProperties":false,"type":"object","required":["name"],"title":"DriveCycleStep","description":"A placeholder step for drive cycles parsed from cycler\nprotocols.\n\nDriveCycleStep is a parsing artifact that gets converted to a\nStandardStep with Direction.DRIVE before simulation. The `name`\nfield references the drive cycle data key passed to\n`simulate_protocol()`.\n\nThis step type should not reach the simulation - it's converted\nduring protocol loading in `create_experiment_from_protocol()`."},"DurationEnd":{"properties":{"type":{"type":"string","const":"Duration","title":"Type","description":"Type of end condition","default":"Duration"},"value":{"type":"string","title":"Value","description":"Duration value"},"goto":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Goto","description":"Step to transition to after end is reached"}},"additionalProperties":false,"type":"object","required":["value"],"title":"DurationEnd","description":"A duration end condition."},"EISStep":{"properties":{"kind":{"type":"string","const":"eis","title":"Kind","description":"The type of this step","default":"eis"},"lower_frequency":{"type":"string","title":"Lower Frequency","description":"Lower frequency [Hz]"},"upper_frequency":{"type":"string","title":"Upper Frequency","description":"Upper frequency [Hz]"},"note":{"type":"string","title":"Note","description":"An optional note for the step.","default":""}},"additionalProperties":false,"type":"object","required":["lower_frequency","upper_frequency"],"title":"EISStep","description":"An EIS (Electrochemical Impedance Spectroscopy) step."},"Electrode":{"type":"string","enum":["negative","positive"],"title":"Electrode"},"ElementSubtype":{"type":"string","enum":["Half Cell OCP","Full Cell OCV","Current Driven"],"title":"ElementSubtype"},"ElementType":{"type":"string","enum":["Direct Entry","Data Fit","Array Data Fit","Calculation","Validation"],"title":"ElementType"},"EntryConfig":{"properties":{"values":{"additionalProperties":true,"type":"object","title":"Values"}},"type":"object","required":["values"],"title":"EntryConfig"},"EntryResponse":{"properties":{"parameter_values":{"additionalProperties":true,"type":"object","title":"Parameter Values"}},"type":"object","required":["parameter_values"],"title":"EntryResponse"},"EstimateDurationRequest":{"properties":{"buffer_pct":{"anyOf":[{"type":"number","maximum":100.0,"minimum":0.0},{"type":"null"}],"title":"Buffer Pct"}},"type":"object","title":"EstimateDurationRequest","description":"Options for a planned test's duration estimate.\n\nThe body is optional on the endpoint; omitting it takes the default margin."},"EstimationStatus":{"type":"string","enum":["estimating","ready","failed"],"title":"EstimationStatus","description":"Lifecycle of a duration estimate computed by a background simulation.\n\nUsed by both estimates: a planned test's total duration\n(``planned_measurements.estimated_duration_*``) and a running test's\nremaining duration (``cell_measurements.estimated_end_time_*``). One enum\nbecause the lifecycle is identical -- only what is being estimated differs.\n\n``estimating`` while the job is in flight, ``ready`` once a value came from\nit, ``failed`` with the reason in the accompanying note. ``None`` means no\nestimate was ever requested."},"EvaluateExpressionRequest":{"properties":{"json_value":{"additionalProperties":true,"type":"object","title":"Json Value"},"parameters":{"additionalProperties":true,"type":"object","title":"Parameters"}},"type":"object","required":["json_value","parameters"],"title":"EvaluateExpressionRequest","description":"Request body for evaluating an expression with current parameters."},"EvaluateExpressionResponse":{"properties":{"value":{"type":"number","title":"Value"}},"type":"object","required":["value"],"title":"EvaluateExpressionResponse","description":"Response body with the evaluated numeric value."},"EvaluateVariablesRequest":{"properties":{"variables":{"items":{"type":"string"},"type":"array","title":"Variables","description":"List of variable names to evaluate from the simulation"}},"type":"object","required":["variables"],"title":"EvaluateVariablesRequest","description":"Request body for evaluating specific variables from a simulation."},"ExistingProtocolMatchResponse":{"properties":{"template_ids":{"items":{"type":"string"},"type":"array","title":"Template Ids"},"note":{"type":"string","title":"Note","default":""}},"type":"object","required":["template_ids"],"title":"ExistingProtocolMatchResponse","description":"A saved protocol that already does what was asked for."},"ExperimentBackendPreviewRequest":{"properties":{"experiment":{"type":"string","title":"Experiment","description":"UCP protocol YAML string"}},"type":"object","required":["experiment"],"title":"ExperimentBackendPreviewRequest","description":"Request body for previewing simulation backend compatibility."},"ExperimentBackendPreviewResponse":{"properties":{"pybamm_compatible":{"type":"boolean","title":"Pybamm Compatible"},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error"}},"type":"object","required":["pybamm_compatible"],"title":"ExperimentBackendPreviewResponse","description":"Compatibility report for a UCP protocol against the PyBaMM backend.\n\nThe PyBaMM backend converts UCP protocols to ``pybamm.Experiment`` objects.\nSome UCP features (loops, conditionals, EIS, expression-driven values) are\nnot representable in a PyBaMM experiment, in which case the user must run\non the UCP backend instead."},"ExperimentTemplate":{"properties":{"id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Id","description":"Unique identifier for the template"},"name":{"type":"string","title":"Name","description":"Name of the template"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"Description of the template"},"description_template":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description Template","description":"Template string for generating user-facing descriptions with {{param}} placeholders"},"protocol_config":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Protocol Config","description":"Protocol configuration (UCP format). Omitted from list responses by default; opt in via ``?include=protocol_config``."},"parameters_schema":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Parameters Schema","description":"Parameters schema defining what parameters this template accepts. Omitted from list responses by default; opt in via ``?include=parameters_schema``."},"organization_id":{"type":"string","title":"Organization Id","description":"ID of the organization that owns this template"},"created_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At","description":"When the template was created"},"updated_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated At","description":"When the template was last updated"},"plot_options":{"additionalProperties":true,"type":"object","title":"Plot Options","description":"Plot configuration options organized by plot type (time_series, metrics)"},"time_series_spec":{"additionalProperties":true,"type":"object","title":"Time Series Spec","description":"Specification mapping time-series keys to calculation rules."},"metrics_spec":{"additionalProperties":true,"type":"object","title":"Metrics Spec","description":"Specification mapping metric names to calculation rules."},"source_protocol":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Protocol","description":"Original protocol text as entered by the user"},"created_by":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created By","description":"User ID of the user who created this template"},"created_by_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created By Email","description":"Email of the user who created this template"},"project_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Id","description":"ID of the project that owns this protocol. Every protocol reachable through the API is project-scoped; None only on unmigrated rows."},"protocol_group_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Protocol Group Id","description":"ID of the protocol group this protocol belongs to. Protocols sharing a group are related. None means ungrouped. The group is always in the same project as the protocol."}},"type":"object","required":["name","organization_id"],"title":"ExperimentTemplate","description":"Pydantic model for experiment template database entity."},"ExperimentTemplateListResponse":{"properties":{"items":{"items":{"$ref":"#/components/schemas/ExperimentTemplate"},"type":"array","title":"Items"},"count":{"type":"integer","title":"Count"},"total":{"type":"integer","title":"Total"}},"type":"object","required":["items","count","total"],"title":"ExperimentTemplateListResponse","description":"Paginated list of experiment templates."},"ExpressionToJsonRequest":{"properties":{"expression":{"type":"string","title":"Expression"}},"type":"object","required":["expression"],"title":"ExpressionToJsonRequest","description":"Request body for converting PyBaMM expression string to JSON."},"ExpressionToJsonResponse":{"properties":{"value":{"additionalProperties":true,"type":"object","title":"Value"}},"type":"object","required":["value"],"title":"ExpressionToJsonResponse","description":"Response body with JSON-serialized PyBaMM symbol."},"FindInputReferencesRequest":{"properties":{"protocol":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"string"},{"items":{},"type":"array"}],"title":"Protocol","description":"Protocol as a dictionary (JSON), list, or string. Can be a protocol dict, list of steps, YAML string, or Protocol object serialized."}},"type":"object","required":["protocol"],"title":"FindInputReferencesRequest","description":"Request body for finding input references in a protocol."},"FitECMOptions":{"properties":{"num_rcs":{"type":"integer","maximum":5.0,"minimum":0.0,"title":"Num Rcs","description":"Number of RC pairs.","default":2},"fit_ocv":{"type":"boolean","title":"Fit Ocv","description":"Whether to fit OCV or use provided.","default":true},"capacity":{"anyOf":[{"type":"number","exclusiveMinimum":0.0},{"type":"null"}],"title":"Capacity","description":"Known cell capacity in Ah. Estimated if not provided."},"regularization":{"type":"number","minimum":0.0,"title":"Regularization","description":"Smoothness-prior strength on the R0 / RC parameter curves (never OCV). Maps to scale = 5 / regularization; 0 disables the prior. Defaults to 0 (off).","default":0.0},"ocv_soc_curve":{"anyOf":[{"$ref":"#/components/schemas/OcvSocCurve"},{"type":"null"}],"description":"Open-circuit voltage curve as (soc, ocv) arrays. When provided, OCV-fitting is skipped and OCV is interpolated from the curve. Mutually exclusive with measurement Open-circuit voltage [V] columns."},"bounds_capacity":{"anyOf":[{"$ref":"#/components/schemas/CapacityBounds"},{"type":"null"}],"description":"Search bounds (Ah) for capacity fitting. Providing this (with ocv_soc_curve and no capacity) opts in to fitting capacity; without it capacity is coulomb-count estimated."},"num_knots":{"anyOf":[{"type":"integer","maximum":64.0,"minimum":1.0},{"type":"null"}],"title":"Num Knots","description":"Number of SOC knots for RC alpha + default beta resolution. Service default applies when None."},"num_knots_r0":{"anyOf":[{"type":"integer","maximum":64.0,"minimum":1.0},{"type":"null"}],"title":"Num Knots R0","description":"Number of SOC knots for R0(SoC). Service default applies when None."},"knot_schedule":{"anyOf":[{"items":{"type":"integer"},"type":"array"},{"type":"null"}],"title":"Knot Schedule","description":"Multi-resolution beta knot schedule (strictly increasing positive ints ending at num_knots). Auto-derived when None."},"clamp_boundary_knots":{"type":"boolean","title":"Clamp Boundary Knots","description":"When True (default), clamp boundary R0/alpha/beta knot values to within ``clamp_max_ratio`` of their interior neighbour. Set False if you build R_rc(soc)=alpha(soc)/beta(soc) symbolically downstream — the ratio is well behaved even at unobserved boundary knots and clamping costs fit quality.","default":true},"clamp_max_ratio":{"type":"number","exclusiveMinimum":1.0,"title":"Clamp Max Ratio","description":"Cap boundary knot values at ``clamp_max_ratio`` × their interior neighbour (only when ``clamp_boundary_knots`` is True). Larger values preserve more SoC variation; smaller values are stricter against R_rc=alpha/beta blow-ups that destabilise pybamm forward simulations. Default 10.","default":10.0}},"type":"object","title":"FitECMOptions","description":"ECM fitting hyperparameters shared across all measurements."},"FitFromMeasurementsRequest":{"properties":{"measurements":{"items":{"$ref":"#/components/schemas/FitMeasurementRequest"},"type":"array","minItems":1,"title":"Measurements","description":"One or more measurements to fit jointly."},"ecm_options":{"$ref":"#/components/schemas/FitECMOptions"}},"type":"object","required":["measurements"],"title":"FitFromMeasurementsRequest","description":"Request body for fitting ECM from database measurements."},"FitMeasurementRequest":{"properties":{"id":{"type":"string","title":"Id","description":"Measurement ID."},"start_step":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Start Step","description":"Optional inclusive start step for filtering."},"end_step":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"End Step","description":"Optional inclusive end step for filtering."},"initial_soc":{"anyOf":[{"type":"number","maximum":1.0,"minimum":0.0},{"type":"null"}],"title":"Initial Soc","description":"Known initial SOC (0–1) at the start of this measurement. When None and an ``ocv_soc_curve`` is provided in ``ecm_options``, soc0 is auto-seeded by inverting V[s] = OCV(soc0) − I[s]·R0(soc0) after a warm-up fit. Falls back to coulomb-count for single-measurement runs without an OCV curve."},"capacity":{"anyOf":[{"type":"number","exclusiveMinimum":0.0},{"type":"null"}],"title":"Capacity","description":"Known cell capacity in Ah for this measurement. When provided for every measurement, the per-measurement values are used; otherwise the shared ``ecm_options.capacity`` (or an estimate) applies. Per-measurement capacity is all-or-none across measurements."}},"type":"object","required":["id"],"title":"FitMeasurementRequest","description":"One measurement to include in an ECM fit."},"FitResultsData":{"properties":{"soc":{"items":{"type":"number"},"type":"array","title":"Soc"},"ocv":{"items":{"type":"number"},"type":"array","title":"Ocv"},"r0":{"items":{"type":"number"},"type":"array","title":"R0"},"rc_pairs":{"items":{"$ref":"#/components/schemas/RcPairFitData"},"type":"array","title":"Rc Pairs"},"capacity_Ah":{"anyOf":[{"items":{"type":"number"},"type":"array"},{"type":"null"}],"title":"Capacity Ah","description":"Cell capacity used to integrate SOC, one entry per measurement segment. An estimated or fitted capacity is a single cell-wide value repeated across segments (a separate capacity is not estimated per trace); entries differ only when a per-measurement ``capacity`` is supplied. Required for validation — it is the SOC reference the curves were fitted against and is never re-estimated from the held-out trace. Save/validate use one capacity per model/trace, so the per-segment values must agree."}},"type":"object","required":["soc","ocv","r0"],"title":"FitResultsData","description":"Fit results needed for saving (and re-simulating for validation)."},"FixOption":{"properties":{"id":{"type":"string","enum":["accept","reject","change_cell"],"title":"Id","description":"Value to send back as the resolution."},"label":{"type":"string","title":"Label","description":"Plain-English button label."},"detail":{"type":"string","title":"Detail","description":"What choosing this will do.","default":""},"recommended":{"type":"boolean","title":"Recommended","description":"Whether this is the engine's suggested choice.","default":false}},"type":"object","required":["id","label"],"title":"FixOption","description":"One choice a reviewer can make about a finding.\n\nOptions are computed from the issue's ``code`` rather than stored, so a\nclient renders the choices without hardcoding what each code supports."},"FormatExpressionRequest":{"properties":{"expression":{"type":"string","title":"Expression"}},"type":"object","required":["expression"],"title":"FormatExpressionRequest","description":"Request body for formatting a PyBaMM expression with black."},"FormatExpressionResponse":{"properties":{"expression":{"type":"string","title":"Expression"}},"type":"object","required":["expression"],"title":"FormatExpressionResponse","description":"Response body with the black-formatted expression string."},"FromOptimizationRequest":{"properties":{"optimization_id":{"type":"string","title":"Optimization Id"},"name":{"type":"string","title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"}},"type":"object","required":["optimization_id","name"],"title":"FromOptimizationRequest","description":"Request body for creating a template from an existing optimization."},"FunctionParametersConversionBody":{"properties":{"parameters":{"additionalProperties":true,"type":"object","title":"Parameters"}},"type":"object","required":["parameters"],"title":"FunctionParametersConversionBody"},"GenerateFilterRequest":{"properties":{"prompt":{"type":"string","title":"Prompt"},"measurement_id":{"type":"string","title":"Measurement Id"},"current_sql":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Current Sql"}},"type":"object","required":["prompt","measurement_id"],"title":"GenerateFilterRequest","description":"Request body for AI-powered SQL filter generation."},"GenerateFilterResponse":{"properties":{"sql_where_clause":{"type":"string","title":"Sql Where Clause"},"match_mode":{"type":"string","title":"Match Mode"},"explanation":{"type":"string","title":"Explanation"}},"type":"object","required":["sql_where_clause","match_mode","explanation"],"title":"GenerateFilterResponse","description":"Response body for AI-powered SQL filter generation."},"GenerateProtocolRequest":{"properties":{"prompt":{"type":"string","maxLength":4000,"minLength":1,"title":"Prompt","description":"Plain-English description of the test to run, e.g. '1C/1C cycling for 200 cycles between 4.2 V and 2.5 V with 10-minute rests'."},"current_protocol":{"anyOf":[{"type":"string","maxLength":100000},{"type":"null"}],"title":"Current Protocol","description":"Optional existing protocol as UCP YAML. When supplied the prompt is treated as an edit to it rather than a fresh protocol."},"clarifications":{"items":{"$ref":"#/components/schemas/ClarificationAnswer"},"type":"array","maxItems":20,"title":"Clarifications","description":"Answers to questions a previous call returned, oldest first. Send the full history each time — the exchange is stateless."},"cell_specification_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cell Specification Id","description":"Cell the test will run on. Its voltage limits, capacity and rate limits are given to the generator as facts, so it stops guessing (or asking) about them."},"skip_existing":{"type":"boolean","title":"Skip Existing","description":"Skip the saved-protocol search and write a new protocol. Set when the user rejects the suggested matches.","default":false}},"type":"object","required":["prompt"],"title":"GenerateProtocolRequest","description":"Request body for generating a protocol from natural language."},"GenerateProtocolResponse":{"properties":{"protocol_yaml":{"type":"string","title":"Protocol Yaml","default":""},"name":{"type":"string","title":"Name","default":""},"explanation":{"type":"string","title":"Explanation","default":""},"assumptions":{"items":{"type":"string"},"type":"array","title":"Assumptions"},"questions":{"items":{"$ref":"#/components/schemas/ClarifyingQuestionResponse"},"type":"array","title":"Questions"},"matches":{"anyOf":[{"$ref":"#/components/schemas/ExistingProtocolMatchResponse"},{"type":"null"}]}},"type":"object","title":"GenerateProtocolResponse","description":"A protocol, the questions needed to write one, or an existing match.\n\nExactly one branch is populated. Callers should check ``questions`` and\n``matches`` before reading ``protocol_yaml`` — both leave it empty."},"GeneratedApiKey":{"properties":{"api_key":{"type":"string","title":"Api Key"},"key_prefix":{"type":"string","title":"Key Prefix"}},"type":"object","required":["api_key","key_prefix"],"title":"GeneratedApiKey","description":"A freshly minted key. The only response that ever contains the secret."},"GlobalConfig":{"properties":{"initial_temperature":{"type":"string","title":"Initial Temperature","description":"Global initial temperature for the experiment [°C], defaults to 25°C","default":"25"},"initial_state_type":{"type":"string","enum":["soc_percentage","voltage"],"title":"Initial State Type","description":"Whether to initialize using SOC percentage or voltage","default":"soc_percentage"},"initial_state_value":{"type":"string","title":"Initial State Value","description":"Global initial SOC [%] or voltage [V]","default":"100"},"resolution":{"$ref":"#/components/schemas/ResolutionConfig"}},"additionalProperties":false,"type":"object","title":"GlobalConfig","description":"Global configuration settings for the protocol."},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"HighlightsSection":{"properties":{"window_days":{"type":"integer","title":"Window Days","description":"Length of the trend window in days"},"daily_utilization":{"items":{"$ref":"#/components/schemas/DailyUtilizationPoint"},"type":"array","title":"Daily Utilization","description":"One point per day, oldest first"},"best_day":{"anyOf":[{"$ref":"#/components/schemas/DailyUtilizationPoint"},{"type":"null"}],"description":"The highest-utilization point in the window"},"tests_completed":{"type":"integer","title":"Tests Completed","description":"Tests that finished within the window","default":0},"tests_started":{"type":"integer","title":"Tests Started","description":"Tests that started within the window","default":0},"channel_hours_used":{"type":"number","title":"Channel Hours Used","description":"Total channel-hours of testing delivered inside the window — the lab's actual output, independent of how many channels it has.","default":0.0},"channel_hours_delta":{"anyOf":[{"$ref":"#/components/schemas/PeriodDelta"},{"type":"null"}],"description":"Channel-hours delivered against the previous window"},"tests_started_delta":{"anyOf":[{"$ref":"#/components/schemas/PeriodDelta"},{"type":"null"}],"description":"Tests started against the previous window"},"tests_completed_delta":{"anyOf":[{"$ref":"#/components/schemas/PeriodDelta"},{"type":"null"}],"description":"Tests completed against the previous window"},"delta_window":{"anyOf":[{"$ref":"#/components/schemas/ComparisonWindow"},{"type":"null"}],"description":"Which two windows every delta above compares"}},"type":"object","required":["window_days"],"title":"HighlightsSection","description":"Momentum: what the lab produced over the trend window, and how hard it ran.\n\nTwo subjects only — **output** (channel-hours, tests started and finished)\nand the **utilization trend** — both reconstructed by replaying measurement\nintervals. Equipment service lives in :class:`MaintenanceSection` instead,\nbeside the channels currently down: repairs are a different subject from\noutput, and the multi-period repair ladder reaches further back than this\nsection's window, so presenting it under a \"last N days\" heading was a\ncontradiction.\n\nEvery point divides by today's channel count, because ``channels`` itself\nkeeps no history: a channel added last week is in the denominator of samples\nfrom before it existed. That makes the *shape* of the series trustworthy and\nits absolute values approximate whenever equipment moved inside the window —\nand is why the trend window is capped."},"IdleChannelRow":{"properties":{"channel":{"$ref":"#/components/schemas/ChannelRef","description":"The idle channel"},"last_used_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Used At","description":"When this channel's most recent test finished. Null when no finished test was found within the service's lookback."},"idle_for_days":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Idle For Days","description":"Days since last_used_at; null when never used"},"max_amps":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max Amps","description":"Maximum rated current (A)"},"min_volts":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Volts","description":"Minimum rated voltage (V)"},"max_volts":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max Volts","description":"Maximum rated voltage (V)"}},"type":"object","required":["channel"],"title":"IdleChannelRow","description":"A healthy, free channel that has not run anything for a long time."},"IdleChannelsSection":{"properties":{"tiers":{"items":{"$ref":"#/components/schemas/IdleTierCount"},"type":"array","title":"Tiers","description":"Counts per threshold, ascending"},"channels":{"items":{"$ref":"#/components/schemas/IdleChannelRow"},"type":"array","title":"Channels","description":"Idle channels, longest-idle first"}},"type":"object","title":"IdleChannelsSection","description":"Idle healthy channels, plus a count at each requested threshold.\n\nRows are every channel past the *lowest* threshold, longest-idle first; the\ntier counts then say how many also cross the higher ones (the classic\n\"N idle over 2 days, of which M over 3\" phrasing) without listing a channel\nmore than once."},"IdleTierCount":{"properties":{"threshold_days":{"type":"integer","title":"Threshold Days","description":"Idle threshold in days"},"channel_count":{"type":"integer","title":"Channel Count","description":"Channels idle for at least this many days"}},"type":"object","required":["threshold_days","channel_count"],"title":"IdleTierCount","description":"How many idle channels cross one reporting threshold."},"IncidentCategory":{"type":"string","enum":["hardware_failure","maintenance","calibration","decommissioned","other"],"title":"IncidentCategory","description":"Why a channel is out of service.\n\nMirrors the ``channel_incidents_shape_check`` CHECK constraint. The database\nstores this as CHECK-constrained text rather than a Postgres enum so the\nallowed set can be widened by swapping a constraint — ``ALTER TYPE ... ADD\nVALUE`` does not compose with the additive-migration rule.\n\n``decommissioned`` is a retirement, not a repair: a channel in this state is\nnever expected back, so its incident stays open forever. The report layer must\nexclude it both from mean-time-to-repair (there is no repair to time) and from\n\"channels currently down\" (it is not awaiting anyone's attention). The\nfrontend already encodes that rule; the report-side constant lands with the\nreport that consumes it."},"InitiateLogoUploadRequest":{"properties":{"content_type":{"type":"string","title":"Content Type","description":"MIME type of the image (image/png, image/jpeg, image/webp, or image/svg+xml). Determines the stored object's extension, and must match the Content-Type sent on the PUT."}},"type":"object","required":["content_type"],"title":"InitiateLogoUploadRequest","description":"Ask for a signed URL to upload an organization logo to."},"InitiateLogoUploadResponse":{"properties":{"path":{"type":"string","title":"Path","description":"Storage path the logo will occupy. Informational: the confirm endpoint recomputes it server-side rather than trusting it back."},"signed_url":{"type":"string","title":"Signed Url","description":"PUT the image bytes here with the same Content-Type, then call the confirm endpoint. Storage rejects an object over 2 MiB (413) or of an unlisted type (415)."},"token":{"type":"string","title":"Token","description":"Upload token embedded in the signed URL."}},"type":"object","required":["path","signed_url","token"],"title":"InitiateLogoUploadResponse","description":"A signed URL to PUT an organization logo to."},"InitiateRawDataUploadRequest":{"properties":{"project_id":{"type":"string","title":"Project Id","description":"Owning project ID (required)."},"name":{"type":"string","title":"Name","description":"User-provided label for the raw file."},"source":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source","description":"Free-text provenance: where this raw file came from (a URL, DOI, S3 URI, vendor/cycler export description, etc.)."},"metadata":{"additionalProperties":true,"type":"object","title":"Metadata","description":"Loose free-form metadata."},"filename":{"type":"string","title":"Filename","description":"Original filename to upload."},"content_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Content Type","description":"MIME type, if known."}},"type":"object","required":["project_id","name","filename"],"title":"InitiateRawDataUploadRequest","description":"Body for POST /raw_data/initiate-upload.\n\nCarries the record metadata (project_id, name, source, metadata from\nRawDataBase) plus the original filename and optional content type needed\nto build the storage path and signed URL. No DB row is created."},"InitiateRawDataUploadResponse":{"properties":{"raw_data_id":{"type":"string","title":"Raw Data Id","description":"Pre-generated raw-data record ID."},"uploads":{"items":{"$ref":"#/components/schemas/RawDataUploadInfo"},"type":"array","title":"Uploads","description":"Signed-URL targets (always a single-element list)."}},"type":"object","required":["raw_data_id","uploads"],"title":"InitiateRawDataUploadResponse","description":"Response from POST /raw_data/initiate-upload."},"InitiateUploadRequest":{"properties":{"measurement":{"additionalProperties":true,"type":"object","title":"Measurement","description":"Measurement data with custom fields"},"measurement_type":{"$ref":"#/components/schemas/MeasurementType","description":"Type of measurement. Use 'file' for file uploads.","default":"time_series"},"filenames":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Filenames","description":"List of filenames to upload (required for file type)."}},"type":"object","required":["measurement"],"title":"InitiateUploadRequest","description":"Request model for initiating a signed URL upload for measurement data."},"InitiateUploadResponse":{"properties":{"measurement_id":{"type":"string","title":"Measurement Id","description":"Pre-generated measurement UUID"},"uploads":{"items":{"$ref":"#/components/schemas/UploadInfo"},"type":"array","title":"Uploads","description":"Signed URL info for each upload target"}},"type":"object","required":["measurement_id","uploads"],"title":"InitiateUploadResponse","description":"Response model after initiating a signed URL upload."},"JobAccessLevelEnum":{"type":"string","enum":["project","organization"],"title":"JobAccessLevelEnum","description":"Possible access levels for a job"},"JobErrorCode":{"type":"string","enum":["CONFIGURATION_ERROR","MODEL_ERROR","SOLVER_ERROR","EXECUTION_TIMEOUT","SUBMISSION_FAILED","INTERNAL_ERROR"],"title":"JobErrorCode","description":"Machine-readable error codes for jobs."},"JobErrorDetail":{"properties":{"exception_type":{"type":"string","title":"Exception Type","description":"Python exception class name."},"exception_message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Exception Message","description":"Raw exception message for internal debugging. Never shown to end users; stored in the DB error_detail JSON column only. Populated for INTERNAL_ERROR failures where error_short is intentionally sanitised."},"log_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Log Url","description":"Deep-link to a Sentry event."}},"type":"object","required":["exception_type"],"title":"JobErrorDetail","description":"Structured diagnostic context stored alongside a failed job's error_code."},"JobListResponse":{"properties":{"jobs":{"items":{"$ref":"#/components/schemas/JobResponse"},"type":"array","title":"Jobs"},"count":{"type":"integer","title":"Count"},"total":{"type":"integer","title":"Total"}},"type":"object","required":["jobs","count","total"],"title":"JobListResponse","description":"Schema for listing jobs with pagination"},"JobResponse":{"properties":{"job_id":{"type":"string","title":"Job Id"},"job_type":{"$ref":"#/components/schemas/JobType"},"status":{"$ref":"#/components/schemas/JobStatus"},"priority":{"type":"integer","title":"Priority"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"started_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Started At"},"completed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Completed At"},"compute_time":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Compute Time"},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error"},"error_code":{"anyOf":[{"$ref":"#/components/schemas/JobErrorCode"},{"type":"null"}]},"error_detail":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}]},"result":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Result"},"callback_url":{"anyOf":[{"type":"string","maxLength":2083,"minLength":1,"format":"uri"},{"type":"null"}],"title":"Callback Url"},"parent_job_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Parent Job Id"},"user_id":{"type":"string","title":"User Id"},"organization_id":{"type":"string","title":"Organization Id"},"project_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Id"},"access_level":{"anyOf":[{"$ref":"#/components/schemas/JobAccessLevelEnum"},{"type":"null"}],"default":"organization"},"params_path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Params Path"},"metadata_path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Metadata Path"},"anyscale_job_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Anyscale Job Id"},"submission_info":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Submission Info"},"is_terminal":{"type":"boolean","title":"Is Terminal","description":"Whether the job has reached a terminal state and will not transition further.\n\nDerived from :attr:`JobStatus.TERMINAL_STATUSES`, so adding a new\nterminal status to the enum automatically updates the wire field —\nclients that read ``is_terminal`` never need to know the status\ntaxonomy or be re-released when it changes.","readOnly":true},"is_failed":{"type":"boolean","title":"Is Failed","description":"Whether the job terminated unsuccessfully (failed or canceled, not completed).\n\nDerived from :attr:`is_terminal` minus the success case, so any new\nnon-success terminal status added to :class:`JobStatus` is\nautomatically classified as a failure without touching this method.","readOnly":true},"anyscale_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Anyscale Url","description":"Deep-link to this job's Anyscale console dashboard, or None.\n\nBuilt server-side (mirroring the Sentry ``log_url`` pattern) from the\ncaptured ``anyscale_job_id`` and the environment's console cloud/project\nids. Returns None when the job never ran on Anyscale (local/serve) or\nthe environment has no console ids configured, so the UI simply omits\nthe link in those cases.","readOnly":true}},"type":"object","required":["job_id","job_type","status","priority","created_at","updated_at","user_id","organization_id","is_terminal","is_failed","anyscale_url"],"title":"JobResponse","description":"Schema for job information response"},"JobStatus":{"type":"string","enum":["pending","processing","waiting","completed","failed","canceled"],"title":"JobStatus","description":"Possible statuses for a job"},"JobStatusesRequest":{"properties":{"simulation_ids":{"items":{"type":"string"},"type":"array","title":"Simulation Ids","default":[]},"limit":{"type":"integer","maximum":1000.0,"minimum":1.0,"title":"Limit","default":100},"offset":{"type":"integer","minimum":0.0,"title":"Offset","default":0}},"type":"object","title":"JobStatusesRequest"},"JobType":{"type":"string","enum":["dummy","datafit","array_datafit","validation","simulate","evaluate_variables","optimize","ecm_fit","simple_pipeline"],"title":"JobType","description":"Possible types for a job"},"JsonToExpressionRequest":{"properties":{"value":{"additionalProperties":true,"type":"object","title":"Value"}},"type":"object","required":["value"],"title":"JsonToExpressionRequest","description":"Request body for converting JSON-serialized PyBaMM symbol to string."},"JsonToExpressionResponse":{"properties":{"expression":{"type":"string","title":"Expression"}},"type":"object","required":["expression"],"title":"JsonToExpressionResponse","description":"Response body with PyBaMM expression string."},"LabChannel":{"properties":{"id":{"type":"string","title":"Id","description":"Channel ID"},"name":{"type":"string","title":"Name","description":"Channel name"},"state":{"$ref":"#/components/schemas/ChannelState","description":"Derived occupancy state"},"measurement":{"anyOf":[{"$ref":"#/components/schemas/LabMeasurementSummary"},{"type":"null"}],"description":"The measurement driving the state (occupied/stale). Null when free."},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes","description":"Free-text notes on the channel"},"out_of_commission":{"type":"boolean","title":"Out Of Commission","description":"Whether the channel is out of service","default":false},"max_amps":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max Amps","description":"Maximum rated current (A)"},"min_volts":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Volts","description":"Minimum rated voltage (V)"},"max_volts":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max Volts","description":"Maximum rated voltage (V)"}},"type":"object","required":["id","name","state"],"title":"LabChannel","description":"A channel with its derived occupancy state for the Lab wall."},"LabCycler":{"properties":{"id":{"type":"string","title":"Id","description":"Cycler ID"},"name":{"type":"string","title":"Name","description":"Cycler name"},"manufacturer":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Manufacturer","description":"Cycler manufacturer (make)"},"model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model","description":"Cycler model (type)"},"serial_number":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Serial Number","description":"Manufacturer serial number"},"last_calibrated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Calibrated At","description":"When the cycler was last calibrated"},"calibration_interval_days":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Calibration Interval Days","description":"Configured calibration cadence, carried so the record-calibration dialog can prefill it without a second fetch."},"calibration_due_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Calibration Due At","description":"When calibration next falls due. Null when the cycler is not on a calibration schedule or has never been calibrated."},"channel_count":{"type":"integer","title":"Channel Count","description":"Total number of channels"},"occupied":{"type":"integer","title":"Occupied","description":"Channels in the occupied state"},"stale":{"type":"integer","title":"Stale","description":"Channels in the stale state"},"free":{"type":"integer","title":"Free","description":"Channels in the free state"},"out_of_commission":{"type":"integer","title":"Out Of Commission","description":"Channels that are out of commission","default":0},"channels":{"items":{"$ref":"#/components/schemas/LabChannel"},"type":"array","title":"Channels","description":"Channels on this cycler"}},"type":"object","required":["id","name","channel_count","occupied","stale","free"],"title":"LabCycler","description":"A cycler with its channels and occupancy counts for the Lab wall."},"LabMeasurementSummary":{"properties":{"id":{"type":"string","title":"Id","description":"Measurement ID"},"name":{"type":"string","title":"Name","description":"Measurement name"},"start_time":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Start Time","description":"When the test started, if known"},"estimated_end_time":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Estimated End Time","description":"Forecast finish time, if an estimate has been computed"},"updated_at":{"type":"string","format":"date-time","title":"Updated At","description":"When the measurement was last updated (drives recency)"},"cell_instance_id":{"type":"string","title":"Cell Instance Id","description":"ID of the cell instance on test"},"cell_instance_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cell Instance Name","description":"Name of the cell instance on test"},"cell_specification_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cell Specification Name","description":"Name of the cell instance's cell specification"},"protocol_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Protocol Name","description":"Protocol name from the measurement's protocol dict"},"watched":{"type":"boolean","title":"Watched","description":"Whether the requesting user is watching this measurement. Drives the Lab 'My Channels' filter (a watch on the live measurement reads as watching its channel).","default":false},"requested_by_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Requested By Email","description":"Email of the planned-measurement requester, when this run is linked to a plan."},"program_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Program Name","description":"Catalog program name when the measurement (or its linked plan) has a program."}},"type":"object","required":["id","name","updated_at","cell_instance_id"],"title":"LabMeasurementSummary","description":"Slim view of the measurement occupying a channel, for the Lab wall.\n\nCarries only what a channel tile needs; the full measurement is fetched\nseparately on the channel detail page."},"LabReport":{"properties":{"project_id":{"type":"string","title":"Project Id","description":"Project the report covers"},"project_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Name","description":"Project name"},"organization_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Organization Name","description":"Organization the project belongs to"},"prepared_for_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Prepared For Email","description":"Email of the user the report was generated for"},"generated_at":{"type":"string","format":"date-time","title":"Generated At","description":"Server time the report was generated (UTC)"},"parameters":{"$ref":"#/components/schemas/LabReportParameters","description":"The parameters this report was built with"},"highlights":{"anyOf":[{"$ref":"#/components/schemas/HighlightsSection"},{"type":"null"}]},"utilization":{"anyOf":[{"$ref":"#/components/schemas/UtilizationSection"},{"type":"null"}]},"recently_stopped":{"anyOf":[{"$ref":"#/components/schemas/RecentlyStoppedSection"},{"type":"null"}]},"stopping_soon":{"anyOf":[{"$ref":"#/components/schemas/StoppingSoonSection"},{"type":"null"}]},"past_due":{"anyOf":[{"$ref":"#/components/schemas/PastDueSection"},{"type":"null"}]},"queue":{"anyOf":[{"$ref":"#/components/schemas/QueueSection"},{"type":"null"}]},"unscheduled_requests":{"anyOf":[{"$ref":"#/components/schemas/UnscheduledRequestsSection"},{"type":"null"}]},"maintenance":{"anyOf":[{"$ref":"#/components/schemas/MaintenanceSection"},{"type":"null"}]},"idle_channels":{"anyOf":[{"$ref":"#/components/schemas/IdleChannelsSection"},{"type":"null"}]},"markdown":{"type":"string","title":"Markdown","description":"The full report rendered as Markdown"}},"type":"object","required":["project_id","generated_at","parameters","markdown"],"title":"LabReport","description":"A rendered lab operations report plus the data behind it.\n\n``markdown`` is the whole report as a document (the intended payload for\nPDF conversion or messaging); the structured sections are the same content\nunformatted, for consumers that want to re-render or post-process it.\nSections not requested are ``None``."},"LabReportParameters":{"properties":{"sections":{"items":{"$ref":"#/components/schemas/LabReportSection"},"type":"array","title":"Sections","description":"Sections included in this report"},"recently_stopped_hours":{"type":"integer","title":"Recently Stopped Hours","description":"Lookback window for the recently-stopped section"},"stopping_soon_hours":{"type":"integer","title":"Stopping Soon Hours","description":"Forecast window for the stopping-soon section"},"idle_thresholds_days":{"items":{"type":"integer"},"type":"array","title":"Idle Thresholds Days","description":"Idle thresholds reported, in days, ascending"},"queue_limit":{"type":"integer","title":"Queue Limit","description":"Maximum queued measurements listed"},"queue_horizon_days":{"type":"integer","title":"Queue Horizon Days","description":"How far ahead the queue section looks"},"service_horizon_days":{"type":"integer","title":"Service Horizon Days","description":"How far ahead booked service visits were reported","default":30},"trend_window_days":{"type":"integer","title":"Trend Window Days","description":"Length of the highlights trend window"}},"type":"object","required":["sections","recently_stopped_hours","stopping_soon_hours","idle_thresholds_days","queue_limit","queue_horizon_days","trend_window_days"],"title":"LabReportParameters","description":"The knobs the report was built with, echoed back for reproducibility."},"LabReportSection":{"type":"string","enum":["highlights","utilization","recently_stopped","stopping_soon","past_due","queue","unscheduled_requests","maintenance","idle_channels"],"title":"LabReportSection","description":"The selectable sections of a lab report.\n\nUsed both as the ``sections`` query parameter on the report endpoint and as\nthe key for the corresponding field on :class:`LabReport`."},"LabSite":{"properties":{"id":{"type":"string","title":"Id","description":"Site ID"},"name":{"type":"string","title":"Name","description":"Site name"},"cyclers":{"items":{"$ref":"#/components/schemas/LabCycler"},"type":"array","title":"Cyclers","description":"Cyclers at this site owned by the project"}},"type":"object","required":["id","name"],"title":"LabSite","description":"A site grouping its cyclers for the Lab wall."},"LabStatus":{"properties":{"sites":{"items":{"$ref":"#/components/schemas/LabSite"},"type":"array","title":"Sites","description":"Sites with this project's cyclers"},"occupied":{"type":"integer","title":"Occupied","description":"Total occupied channels across the project","default":0},"stale":{"type":"integer","title":"Stale","description":"Total stale channels across the project","default":0},"free":{"type":"integer","title":"Free","description":"Total free channels across the project","default":0},"out_of_commission":{"type":"integer","title":"Out Of Commission","description":"Total out-of-commission channels across the project","default":0}},"type":"object","title":"LabStatus","description":"The full Lab-view tree for a project: sites -> cyclers -> channels.\n\nReturned by ``GET /projects/{project_id}/lab/status`` in a single call so\nthe wall can render without N per-channel round-trips."},"ListSimulationsResponse":{"properties":{"simulations":{"items":{"$ref":"#/components/schemas/SimulationSummary"},"type":"array","title":"Simulations","description":"List of simulation summaries without full parameters"},"model_scalar_parameters":{"additionalProperties":{"additionalProperties":true,"type":"object"},"type":"object","title":"Model Scalar Parameters","description":"Map of parameterized_model_id to scalar-only parameters. Used as fallback when design.design_parameters doesn't have a value."},"total":{"type":"integer","title":"Total","description":"Total number of matching simulations.","default":0}},"type":"object","required":["simulations"],"title":"ListSimulationsResponse","description":"Response for study simulations with deduplicated model parameters.\n\nInstead of including full parameters on each simulation (which can be\nmassive expression trees), this response includes simulations without\nparameters and a separate map of model_id -> scalar parameters.\nThe frontend can merge: design.design_parameters over model base params."},"LogoVariant":{"type":"string","enum":["light","dark"],"title":"LogoVariant","description":"Which of an organization's two marks an operation addresses.\n\nBoth are optional and each falls back to the other when rendering, so the\nvariant selects a slot rather than asserting one exists. A ``StrEnum`` so\nthe value doubles as the ``?variant=`` query-param string."},"LoopNumberEnd":{"properties":{"type":{"type":"string","const":"LoopNumber","title":"Type","description":"Type of end condition","default":"LoopNumber"},"operator":{"type":"string","enum":[">",">=","="],"title":"Operator","description":"Operator for the condition (>, >=, =). '=' fires on one specific iteration only; the inequalities fire on that iteration and every one after it."},"value":{"type":"integer","title":"Value","description":"Loop number value"},"goto":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Goto","description":"Step to transition to after end is reached"}},"additionalProperties":false,"type":"object","required":["operator","value"],"title":"LoopNumberEnd","description":"A loop number end condition."},"MaintenanceChannelRow":{"properties":{"channel":{"$ref":"#/components/schemas/ChannelRef","description":"The out-of-service channel"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes","description":"Why the channel is down: the incident's notes, falling back to the channel's own notes when there is no open incident."},"down_since":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Down Since","description":"When the outage began. Null when no open incident was found (see class docs)."},"down_for_days":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Down For Days","description":"Days elapsed since ``down_since``, to one decimal"},"category":{"anyOf":[{"$ref":"#/components/schemas/IncidentCategory"},{"type":"null"}],"description":"Cause of the outage, from the open incident"},"due_back":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Due Back","description":"When the outage's planned service was booked to end. Only planned visits carry one — an unplanned fault has no promised return, which is a different thing from a return that is merely unknown."},"overdue_days":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Overdue Days","description":"Days past ``due_back``, to one decimal, for a channel still down after its booked return. Null when inside the window or when no return was booked, on the same reasoning as the cycler-level row: zero would assert the channel is exactly on time."},"is_estimated":{"type":"boolean","title":"Is Estimated","description":"``down_since`` was reconstructed by the backfill from the channel's last-modified time rather than recorded when it happened.","default":false}},"type":"object","required":["channel"],"title":"MaintenanceChannelRow","description":"A channel currently marked out of commission.\n\n``down_since`` is the open incident's ``started_at`` — a real outage start,\nnot the channel row's update timestamp this once used as a proxy.\n\nA channel can be out of service with no open incident: it was flipped\nbefore ``channel_incidents`` existed and the backfill has not run in this\nenvironment yet. The outage fields are then all null, and the row still\nappears — a down channel must never disappear from the report because its\nhistory is missing."},"MaintenanceSection":{"properties":{"channels":{"items":{"$ref":"#/components/schemas/MaintenanceChannelRow"},"type":"array","title":"Channels","description":"Channel-local faults awaiting repair, longest outage first. Channels down as part of an instrument-level visit are reported once in ``serviced_cyclers`` instead of once per channel here."},"serviced_cyclers":{"items":{"$ref":"#/components/schemas/ServicedCyclerRow"},"type":"array","title":"Serviced Cyclers","description":"Whole cyclers out under one service event, longest first"},"calibration":{"items":{"$ref":"#/components/schemas/CalibrationRow"},"type":"array","title":"Calibration","description":"Cyclers on a calibration schedule that are overdue or due soon, most urgent first. Empty when everything on a schedule is current."},"scheduled_service":{"items":{"$ref":"#/components/schemas/ScheduledServiceRow"},"type":"array","title":"Scheduled Service","description":"Booked visits inside the horizon, soonest first"},"retired_count":{"type":"integer","title":"Retired Count","description":"Out-of-service channels excluded as retirements — not awaiting anyone's attention, so listed nowhere above, but counted by the Lab wall's out-of-service total.","default":0},"recovery":{"anyOf":[{"$ref":"#/components/schemas/ChannelRecovery"},{"type":"null"}],"description":"Outages closed and opened during the report's window"},"recovered_delta":{"anyOf":[{"$ref":"#/components/schemas/PeriodDelta"},{"type":"null"}],"description":"Outages closed this window against the previous one. A fall is not automatically bad — a lab with nothing broken repairs nothing — so read it alongside ``recovery.taken_out``."},"delta_window":{"anyOf":[{"$ref":"#/components/schemas/ComparisonWindow"},{"type":"null"}],"description":"Which two windows ``recovered_delta`` compares"},"service_changes":{"items":{"$ref":"#/components/schemas/ServiceChangePeriod"},"type":"array","title":"Service Changes","description":"Repairs and removals over each lookback, shortest first. The incident lookback is derived from the same set of periods, so every entry here is backed by fetched history rather than defaulting to zero."}},"type":"object","title":"MaintenanceSection","description":"Equipment service: what is down, what is due, and what is booked.\n\nCarries the outage list, the repair counts, the calibration schedule, and\nupcoming visits, because they answer one question together — \"are we on top\nof the equipment?\" — and none is much use alone. Six down channels reads\nvery differently next to \"eight repaired this week\" than next to \"none\", and\na lab that is current on repairs can still be three months overdue on\ncalibration.\n\nOutages are reported at the level the work happens at: a channel-local fault\nis a channel row, an instrument-level visit is one cycler row carrying its\nchannel count. Without that split, one calibration on a 40-channel cycler\nwould bury every genuine channel fault in the project.\n\n``retired_count`` exists so the section can never silently disagree with the\nLab wall: the wall counts every out-of-commission channel, this section lists\nonly the ones a repair could return, and without the count the difference\nwould read as a missing row."},"Material":{"properties":{"name":{"type":"string","title":"Name","description":"Name of the material"},"definition":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Definition","description":"Material definition (formula, type, constituents)"},"manufacturer":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Manufacturer","description":"Manufacturer of the material"},"product_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Product Id","description":"Supplier product ID"},"id":{"type":"string","title":"Id","description":"Unique identifier for the material"},"organization_id":{"type":"string","title":"Organization Id","description":"Organization ID of the material"},"project_id":{"type":"string","title":"Project Id","description":"Project the material is scoped to, derived from the cell specification(s) that reference it."},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"Timestamp when the material was created"},"updated_at":{"type":"string","format":"date-time","title":"Updated At","description":"Timestamp when the material was last updated"},"created_by":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created By","description":"User ID of the creator."},"property_count":{"type":"integer","title":"Property Count","description":"Number of property datasets attached to this material","default":0}},"type":"object","required":["name","id","organization_id","project_id","created_at","updated_at"],"title":"Material","description":"Model representing a material as returned by the API."},"MaterialPropertyDataset":{"properties":{"material_id":{"type":"string","title":"Material Id","description":"ID of the parent material"},"project_id":{"type":"string","title":"Project Id","description":"ID of the project this property is scoped to"},"name":{"type":"string","title":"Name","description":"User-provided dataset name, e.g. 'Electrolyte transport'"},"columns":{"items":{"$ref":"#/components/schemas/ColumnSpec"},"type":"array","title":"Columns","description":"All columns in the dataset with their units."},"id":{"type":"string","title":"Id","description":"Unique identifier"},"organization_id":{"type":"string","title":"Organization Id","description":"Organization that owns this record"},"storage_path":{"type":"string","title":"Storage Path","description":"Path to the processed parquet file in the material-property-datasets bucket."},"original_path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Original Path","description":"Path to the raw original file in the material-property-datasets bucket. NULL only for records created before this field was introduced."},"data_version":{"type":"integer","title":"Data Version","description":"Increments on every data-changing operation (file replacement or column re-processing). Downstream code can store this alongside computed results and compare against the current value to detect staleness."},"nan_counts":{"anyOf":[{"additionalProperties":{"type":"integer"},"type":"object"},{"type":"null"}],"title":"Nan Counts","description":"Number of NaN/null values per column, keyed by display name. Computed at upload time. ``None`` for records uploaded before this field was introduced."},"no_header":{"type":"boolean","title":"No Header","description":"True when the uploaded CSV had no header row. Column positions are mapped via ``source_column_index`` on each column spec.","default":false},"created_by":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created By","description":"User ID of the uploader"},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"Upload timestamp"},"updated_at":{"type":"string","format":"date-time","title":"Updated At","description":"Last update timestamp"},"source_pipeline_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Pipeline Id","description":"FK to the pipeline this dataset was computed from."},"source_simple_pipeline_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Simple Pipeline Id","description":"FK to the simple pipeline this dataset was computed from."},"source_analysis_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Analysis Id","description":"FK to the analysis this dataset was computed from."},"source_label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Label","description":"Free-text provenance note."}},"type":"object","required":["material_id","project_id","name","columns","id","organization_id","storage_path","data_version","created_at","updated_at"],"title":"MaterialPropertyDataset","description":"Material property dataset record as returned by the API."},"MeasurementExportRequest":{"properties":{"measurement_ids":{"items":{"type":"string"},"type":"array","title":"Measurement Ids"}},"type":"object","required":["measurement_ids"],"title":"MeasurementExportRequest","description":"Body for the measurement data export endpoint."},"MeasurementProcessingStatus":{"type":"string","enum":["pending","running","ready","failed","awaiting_extend","extending"],"title":"MeasurementProcessingStatus","description":"Lifecycle of a measurement's step processing, shared with extend.\n\n- ``pending`` — confirm-upload task enqueued.\n- ``running`` — worker parsing the upload or calculating steps.\n- ``ready`` — terminal success; default for ``file``/``properties``.\n- ``failed`` — permanent; see ``processing_error``.\n- ``awaiting_extend`` — claim held, signed URL out, no task queued.\n- ``extending`` — delta staged, stitch queued or running.\n\nOnly ``ready`` may start an extend, so it cannot overlap step processing\n(both write ``steps.parquet``). A failed extend returns to ``ready``."},"MeasurementType":{"type":"string","enum":["time_series","file","properties"],"title":"MeasurementType","description":"Shape of the data stored in a cell measurement.\n\n- ``time_series`` — cycling / diagnostic data uploaded as columnar\n  time series (and optional step summaries). Default for new\n  measurements.\n- ``file`` — an opaque file upload (raw cycler export, image, other\n  binary). Metadata about the file is captured in\n  ``file_metadata``; the file content lives in object storage.\n- ``properties`` — a flat key/value set of measured properties\n  (thickness, mass, DCIR, initial capacity, …) with no time-series\n  data. Numeric values use the Quantity format."},"Mode":{"type":"string","enum":["Current","C-rate","Power","Voltage"],"title":"Mode","description":"Control mode for the step."},"Model":{"properties":{"name":{"type":"string","title":"Name","description":"The name of the model."},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"An optional description for the model."},"pybamm_version":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Pybamm Version","description":"PyBaMM version used for this model. If not provided, will be read from pybamm.__version__."},"chemistry":{"type":"string","enum":["lithium_ion","lithium_sulfur","ecm","generic"],"title":"Chemistry","description":"Model chemistry kind: 'lithium_ion' (default — assumes pybamm lithium-ion conventions), 'lithium_sulfur', 'ecm', or 'generic' (no chemistry-specific enrichment).","default":"lithium_ion"},"simulation_settings":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Simulation Settings","description":"Optional persistent simulation kwargs (var_pts / submesh_types / spatial_methods / geometry / solver) in the flat canonical form, re-applied at simulation time. None uses the model defaults."},"id":{"type":"string","title":"Id","description":"The unique identifier for the model."},"user_id":{"type":"string","title":"User Id","description":"The ID of the user who created the model."},"organization_id":{"type":"string","title":"Organization Id","description":"The ID of the organization this model belongs to."},"created_by_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created By Email","description":"Email of the user who created the model."},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"Timestamp of when the model was created."},"updated_at":{"type":"string","format":"date-time","title":"Updated At","description":"Timestamp of when the model was last updated."},"is_custom_model":{"type":"boolean","title":"Is Custom Model","description":"Check if this is a custom model (has compressed model data).","readOnly":true}},"type":"object","required":["name","id","user_id","organization_id","created_at","updated_at","is_custom_model"],"title":"Model","description":"Model representing a model as returned by the API (without config)."},"ModelConfigBody":{"properties":{"config":{"additionalProperties":true,"type":"object","title":"Config"}},"type":"object","required":["config"],"title":"ModelConfigBody","description":"Request body for config-based metadata."},"ModelWithConfig":{"properties":{"name":{"type":"string","title":"Name","description":"The name of the model."},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"An optional description for the model."},"pybamm_version":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Pybamm Version","description":"PyBaMM version used for this model. If not provided, will be read from pybamm.__version__."},"chemistry":{"type":"string","enum":["lithium_ion","lithium_sulfur","ecm","generic"],"title":"Chemistry","description":"Model chemistry kind: 'lithium_ion' (default — assumes pybamm lithium-ion conventions), 'lithium_sulfur', 'ecm', or 'generic' (no chemistry-specific enrichment).","default":"lithium_ion"},"simulation_settings":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Simulation Settings","description":"Optional persistent simulation kwargs (var_pts / submesh_types / spatial_methods / geometry / solver) in the flat canonical form, re-applied at simulation time. None uses the model defaults."},"id":{"type":"string","title":"Id","description":"The unique identifier for the model."},"user_id":{"type":"string","title":"User Id","description":"The ID of the user who created the model."},"organization_id":{"type":"string","title":"Organization Id","description":"The ID of the organization this model belongs to."},"created_by_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created By Email","description":"Email of the user who created the model."},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"Timestamp of when the model was created."},"updated_at":{"type":"string","format":"date-time","title":"Updated At","description":"Timestamp of when the model was last updated."},"config":{"additionalProperties":true,"type":"object","title":"Config","description":"Model configuration stored as JSON."},"is_custom_model":{"type":"boolean","title":"Is Custom Model","description":"Check if this is a custom model (has compressed model data).","readOnly":true}},"type":"object","required":["name","id","user_id","organization_id","created_at","updated_at","config","is_custom_model"],"title":"ModelWithConfig","description":"Model with config loaded from database."},"MultipartUploadInfo":{"properties":{"endpoint":{"type":"string","title":"Endpoint","description":"S3-compatible endpoint URL."},"region":{"type":"string","title":"Region","description":"S3 region name."},"bucket":{"type":"string","title":"Bucket","description":"Target storage bucket."},"object_path":{"type":"string","title":"Object Path","description":"Object key within the bucket."},"access_key_id":{"type":"string","title":"Access Key Id","description":"S3 access key id."},"secret_access_key":{"type":"string","title":"Secret Access Key","description":"S3 secret access key."},"session_token":{"type":"string","title":"Session Token","description":"S3 session token (caller's JWT)."},"expires_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Expires At","description":"ISO timestamp after which the credentials stop working."}},"type":"object","required":["endpoint","region","bucket","object_path","access_key_id","secret_access_key","session_token"],"title":"MultipartUploadInfo","description":"S3-multipart credentials and target for a large direct-to-storage upload.\n\nMirrors the SDK-side model. The session token is the caller's own JWT, so\nSupabase Storage RLS applies to the S3 operations -- the service key must\nnever appear in this block."},"NameMismatchResponse":{"properties":{"aspect":{"type":"string","title":"Aspect","description":"Which claim is contradicted: 'c_rate', 'cycle_count', 'test_type', 'voltage', 'temperature', 'duration' or 'other'."},"claim":{"type":"string","title":"Claim","description":"What the name says."},"actual":{"type":"string","title":"Actual","description":"What the protocol actually does."}},"type":"object","required":["aspect","claim","actual"],"title":"NameMismatchResponse","description":"One specific way the name contradicts the protocol."},"NestedComponentInput":{"properties":{"properties":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Properties","description":"Application properties using Quantity format for numerics. Example: {'diameter': {'value': 14, 'unit': 'mm'}, 'binder': 'PVDF'}"},"material":{"$ref":"#/components/schemas/NestedMaterialInput","description":"Material for this component"}},"type":"object","required":["material"],"title":"NestedComponentInput","description":"Component data for nested cell spec creation. Used for upsert."},"NestedMaterialInput":{"properties":{"name":{"type":"string","title":"Name","description":"Name of the material"},"definition":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Definition","description":"Material definition (formula)"},"manufacturer":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Manufacturer","description":"Manufacturer of the material"},"product_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Product Id","description":"Supplier product ID"}},"type":"object","required":["name"],"title":"NestedMaterialInput","description":"Material data for nested cell spec creation. Used for upsert."},"NormalParam":{"properties":{"type":{"type":"string","const":"normal","title":"Type","default":"normal"},"name":{"type":"string","title":"Name"},"mean":{"type":"number","title":"Mean"},"std":{"type":"number","title":"Std"},"count":{"anyOf":[{"type":"integer","minimum":1.0},{"type":"null"}],"title":"Count"}},"type":"object","required":["name","mean","std"],"title":"NormalParam","description":"Normal parameter configuration.\n\nParameters\n----------\nname\n    Parameter name.\nmean\n    Mean of the distribution.\nstd\n    Standard deviation of the distribution.\ncount\n    Optional grid sample count for this parameter. Required for\n    ``grid`` sampling; ignored for non-grid methods."},"OcvSocCurve":{"properties":{"soc":{"items":{"type":"number"},"type":"array","minItems":2,"title":"Soc","description":"Strictly increasing SOC knot values in [0, 1]."},"ocv":{"items":{"type":"number"},"type":"array","minItems":2,"title":"Ocv","description":"OCV values in volts at each SOC knot."}},"type":"object","required":["soc","ocv"],"title":"OcvSocCurve","description":"Open-circuit voltage as a function of state of charge."},"Optimization":{"properties":{"id":{"type":"string","title":"Id"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"job_id":{"type":"string","title":"Job Id"},"project_id":{"type":"string","title":"Project Id"},"user_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"User Id"},"cell_spec_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cell Spec Id"},"parameterized_model_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Parameterized Model Id"},"optimization_template_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Optimization Template Id"},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At"},"created_by_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created By Email"},"parameterized_model_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Parameterized Model Name"},"cell_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cell Name"},"organization_id":{"type":"string","title":"Organization Id","description":"Organization this optimization belongs to."}},"type":"object","required":["id","job_id","project_id","organization_id"],"title":"Optimization","description":"Pydantic model for the ``optimizations`` table."},"OptimizationListResponse":{"properties":{"jobs":{"items":{"$ref":"#/components/schemas/JobResponse"},"type":"array","title":"Jobs"},"optimizations":{"items":{"$ref":"#/components/schemas/Optimization"},"type":"array","title":"Optimizations"},"total":{"type":"integer","title":"Total"}},"type":"object","required":["jobs","optimizations","total"],"title":"OptimizationListResponse","description":"List of optimization jobs and their optimization records."},"OptimizationResource":{"properties":{"id":{"type":"string","title":"Id","description":"Canonical optimization identifier."},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"project_id":{"type":"string","title":"Project Id"},"organization_id":{"type":"string","title":"Organization Id"},"status":{"anyOf":[{"$ref":"#/components/schemas/DomainStatus"},{"type":"null"}],"description":"Lifecycle status derived from the optimization run."},"kind":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Kind","description":"Optimization kind discriminator (e.g. 'optimize', 'datafit'); determines how the config is interpreted."},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At"},"created_by_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created By Email"},"cell_spec_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cell Spec Id"},"parameterized_model_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Parameterized Model Id"},"parameterized_model_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Parameterized Model Name","description":"Display name of the parameterized model."},"cell_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cell Name","description":"Display name of the cell specification."},"optimization_template_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Optimization Template Id"},"metrics":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Metrics","description":"Result metrics of the optimization, when complete."},"objectives":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Objectives","description":"Objectives/constraints from the config, for list display. Populated on list responses only."},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error","description":"Error message if the run failed."},"error_code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error Code","description":"Machine-readable error code."},"run_count":{"type":"integer","title":"Run Count","description":"Number of multistart runs.","default":0}},"type":"object","required":["id","project_id","organization_id"],"title":"OptimizationResource","description":"Frontend-facing view of an optimization.\n\nReplaces the job-centric ``{optimization, job}`` payload: the linked\njob is collapsed into a flat ``status`` plus result ``metrics`` and\nerror fields, so clients never see the underlying job. Heavy config\nand metadata blobs are served by dedicated sub-resource endpoints\nrather than inlined here."},"OptimizationResourceListResponse":{"properties":{"optimizations":{"items":{"$ref":"#/components/schemas/OptimizationResource"},"type":"array","title":"Optimizations"},"total":{"type":"integer","title":"Total"}},"type":"object","required":["optimizations","total"],"title":"OptimizationResourceListResponse","description":"Paginated list of job-free optimization resources."},"OptimizationRun":{"properties":{"run_id":{"type":"string","title":"Run Id","description":"Opaque identifier for this optimization run."},"index":{"type":"integer","title":"Index","description":"Zero-based position of the run."},"status":{"$ref":"#/components/schemas/DomainStatus","description":"Lifecycle status of the run."},"intermediate_results":{"anyOf":[{"items":{"additionalProperties":true,"type":"object"},"type":"array"},{"type":"null"}],"title":"Intermediate Results","description":"Per-iteration convergence history for the run; its length is the current iteration count. Null until the run produces history."}},"type":"object","required":["run_id","index","status"],"title":"OptimizationRun","description":"A single multistart run within an optimization.\n\nRuns execute internally as child jobs; ``run_id`` is an opaque handle\nfor one run and must not be treated by clients as a job identifier or\npassed to job endpoints. A single ``GET .../runs`` call returns every\nrun with the convergence history needed to render per-run progress, so\nclients never read job storage blobs themselves."},"OptimizationStatusItem":{"properties":{"id":{"type":"string","title":"Id"},"status":{"anyOf":[{"$ref":"#/components/schemas/DomainStatus"},{"type":"null"}]}},"type":"object","required":["id"],"title":"OptimizationStatusItem","description":"Lightweight status for one optimization, for list polling."},"OptimizationTemplate":{"properties":{"name":{"type":"string","title":"Name","description":"The name of the optimization template."},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"An optional description for the template."},"initial_form_data":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Initial Form Data","description":"Initial form data values."},"id":{"type":"string","title":"Id","description":"The unique identifier for the template."},"organization_id":{"type":"string","title":"Organization Id","description":"The ID of the organization this template belongs to."},"project_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Id","description":"The ID of the owner project (None for system templates)."},"access_level":{"type":"string","title":"Access Level","description":"Template scope: 'system' for built-in, 'project' for user-created.","default":"project"},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"Timestamp of when the template was created."},"updated_at":{"type":"string","format":"date-time","title":"Updated At","description":"Timestamp of when the template was last updated."},"created_by":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created By","description":"User ID of the creator."}},"type":"object","required":["name","id","organization_id","created_at","updated_at"],"title":"OptimizationTemplate","description":"Model representing an optimization template as returned by the API."},"OptimizationWithJobResponse":{"properties":{"optimization":{"$ref":"#/components/schemas/Optimization"},"job":{"$ref":"#/components/schemas/JobResponse"}},"type":"object","required":["optimization","job"],"title":"OptimizationWithJobResponse","description":"Single optimization and its linked job (for get-one responses)."},"OrEnd":{"properties":{"type":{"type":"string","const":"Or","title":"Type","description":"Type of end condition","default":"Or"},"conditions":{"items":{"anyOf":[{"$ref":"#/components/schemas/CustomEnd"},{"$ref":"#/components/schemas/DurationEnd"},{"$ref":"#/components/schemas/CapacityEnd"},{"$ref":"#/components/schemas/LoopNumberEnd"},{"$ref":"#/components/schemas/VariableEnd"},{"$ref":"#/components/schemas/AndEnd"},{"$ref":"#/components/schemas/OrEnd"}]},"type":"array","minItems":2,"title":"Conditions","description":"List of child conditions (any being true fires the event)"},"goto":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Goto","description":"Step to transition to when any condition is met"}},"additionalProperties":false,"type":"object","required":["conditions"],"title":"OrEnd","description":"Compound end condition where any child condition being true fires the event.\n\nThe first child condition to become true will trigger the end. For variable\nconditions that are true at step start, the step is skipped immediately."},"Organization":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"slug":{"type":"string","title":"Slug"},"usage_limit":{"anyOf":[{"additionalProperties":{"type":"integer"},"propertyNames":{"$ref":"#/components/schemas/UsageType"},"type":"object"},{"type":"string"},{"type":"null"}],"title":"Usage Limit","description":"Monthly usage limit"},"nav_config":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Nav Config","description":"Per-organization nav config: { '<key>': { 'show': bool, 'disabled': bool, 'badgeLabel': str | None, 'badgeTooltip': str | None } }"},"plotting_preferences":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Plotting Preferences","description":"Free-text markdown describing how this organization wants the battery agent to format plots; injected into the agent's system prompt each turn. None means not set (nothing is injected)."},"logo_path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Logo Path","description":"Storage object path of the light-mode organization logo, or None when unset. Not a URL: the bucket is private, so clients fetch the image from GET /organizations/{id}/logo, which returns a signed URL. Set via POST /organizations/{id}/logo, not via PATCH."},"logo_path_dark":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Logo Path Dark","description":"Storage object path of the dark-mode organization logo, or None when unset. Optional: dark mode falls back to `logo_path` when this is None, and light mode falls back to this when `logo_path` is None. Set via POST /organizations/{id}/logo?variant=dark."},"user_organization_roles":{"anyOf":[{"items":{"$ref":"#/components/schemas/UserOrganizationRole"},"type":"array"},{"type":"null"}],"title":"User Organization Roles","description":"List of user organization roles"},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At","description":"Timestamp of creation"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At","description":"Timestamp of last update"}},"type":"object","required":["id","name","slug"],"title":"Organization","description":"Pydantic model for an organization."},"OrganizationCreate":{"properties":{"name":{"type":"string","title":"Name"}},"type":"object","required":["name"],"title":"OrganizationCreate","description":"Pydantic model for creating an organization (request body)."},"OrganizationLogoUrl":{"properties":{"url":{"type":"string","title":"Url","description":"Signed storage URL for the logo. Load it directly (e.g. as an image source); it carries its own signature and needs no auth header. Treat it as short-lived and refetch rather than persist."},"expires_in":{"type":"integer","title":"Expires In","description":"Seconds until the URL expires, from when it was issued."}},"type":"object","required":["url","expires_in"],"title":"OrganizationLogoUrl","description":"A signed URL for reading an organization's logo."},"OrganizationRole":{"properties":{"name":{"type":"string","title":"Name"},"id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Id"},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At"},"organization_role_permissions":{"anyOf":[{"items":{"additionalProperties":{"$ref":"#/components/schemas/Permission"},"type":"object"},"type":"array"},{"type":"null"}],"title":"Organization Role Permissions","description":"The permissions for the organization role."}},"type":"object","required":["name"],"title":"OrganizationRole"},"OrganizationRoleWithPermissions":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At"},"permissions":{"items":{"$ref":"#/components/schemas/Permission"},"type":"array","title":"Permissions"}},"type":"object","required":["id","name"],"title":"OrganizationRoleWithPermissions","description":"Organization role with its permissions flattened into a list.\n\nRead model for the admin Roles page. Unlike :class:`OrganizationRole`, the\nnested ``organization_role_permissions`` join rows are flattened to a plain\n``permissions`` list so the frontend does not have to unwrap the join shape."},"OrganizationUsageResponse":{"properties":{"period_start":{"type":"string","format":"date-time","title":"Period Start"},"period_end":{"type":"string","format":"date-time","title":"Period End"},"simulation":{"$ref":"#/components/schemas/SimulationUsage"},"compute":{"$ref":"#/components/schemas/ComputeUsage"}},"type":"object","required":["period_start","period_end","simulation","compute"],"title":"OrganizationUsageResponse","description":"Org usage and limits for the current calendar-month billing period.\n\nUsage resets on the first of each month. All usage/limit values are in\nhours."},"PaginatedResponse_Analysis_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/Analysis"},"type":"array","title":"Items"},"count":{"type":"integer","title":"Count"},"total":{"type":"integer","title":"Total"}},"type":"object","required":["items","count","total"],"title":"PaginatedResponse[Analysis]"},"PaginatedResponse_MaterialPropertyDataset_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/MaterialPropertyDataset"},"type":"array","title":"Items"},"count":{"type":"integer","title":"Count"},"total":{"type":"integer","title":"Total"}},"type":"object","required":["items","count","total"],"title":"PaginatedResponse[MaterialPropertyDataset]"},"PaginatedResponse_Material_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/Material"},"type":"array","title":"Items"},"count":{"type":"integer","title":"Count"},"total":{"type":"integer","title":"Total"}},"type":"object","required":["items","count","total"],"title":"PaginatedResponse[Material]"},"PaginatedResponse_Model_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/Model"},"type":"array","title":"Items"},"count":{"type":"integer","title":"Count"},"total":{"type":"integer","title":"Total"}},"type":"object","required":["items","count","total"],"title":"PaginatedResponse[Model]"},"PaginatedResponse_ProjectWebhook_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/ProjectWebhook"},"type":"array","title":"Items"},"count":{"type":"integer","title":"Count"},"total":{"type":"integer","title":"Total"}},"type":"object","required":["items","count","total"],"title":"PaginatedResponse[ProjectWebhook]"},"PaginatedResponse_Project_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/Project"},"type":"array","title":"Items"},"count":{"type":"integer","title":"Count"},"total":{"type":"integer","title":"Total"}},"type":"object","required":["items","count","total"],"title":"PaginatedResponse[Project]"},"PaginatedResponse_RawDataIssue_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/RawDataIssue"},"type":"array","title":"Items"},"count":{"type":"integer","title":"Count"},"total":{"type":"integer","title":"Total"}},"type":"object","required":["items","count","total"],"title":"PaginatedResponse[RawDataIssue]"},"PaginatedResponse_RawData_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/RawData"},"type":"array","title":"Items"},"count":{"type":"integer","title":"Count"},"total":{"type":"integer","title":"Total"}},"type":"object","required":["items","count","total"],"title":"PaginatedResponse[RawData]"},"PaginatedResponse_WebhookDelivery_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/WebhookDelivery"},"type":"array","title":"Items"},"count":{"type":"integer","title":"Count"},"total":{"type":"integer","title":"Total"}},"type":"object","required":["items","count","total"],"title":"PaginatedResponse[WebhookDelivery]"},"PaginatedResponse_str_":{"properties":{"items":{"items":{"type":"string"},"type":"array","title":"Items"},"count":{"type":"integer","title":"Count"},"total":{"type":"integer","title":"Total"}},"type":"object","required":["items","count","total"],"title":"PaginatedResponse[str]"},"ParameterValidationResult":{"properties":{"value":{"type":"number","title":"Value","description":"Value computed from the current parameter set."},"reference":{"type":"number","title":"Reference","description":"Reference value to compare against."},"deviation":{"type":"number","title":"Deviation","description":"Absolute percentage deviation of value from reference."},"status":{"type":"string","enum":["success","warning","error"],"title":"Status","description":"Validation status: success (≤10% deviation), warning (≤50%), or error (>50%)."},"message":{"type":"string","title":"Message","description":"Human-readable description of the check."},"autofix":{"additionalProperties":true,"type":"object","title":"Autofix","description":"Parameter overrides that would bring `value` in line with `reference`. Empty when no autofix is available."}},"type":"object","required":["value","reference","deviation","status","message"],"title":"ParameterValidationResult","description":"Validation outcome for a single parameter against its reference value."},"ParseToTemplateRequest":{"properties":{"protocol_experiment":{"$ref":"#/components/schemas/ProtocolExperimentConfig"},"experiment_parameters":{"additionalProperties":true,"type":"object","title":"Experiment Parameters"},"project_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Id"}},"type":"object","required":["protocol_experiment"],"title":"ParseToTemplateRequest","description":"Request body for parsing a raw protocol and creating an experiment template."},"ParseToTemplateResponse":{"properties":{"template_id":{"type":"string","title":"Template Id"}},"type":"object","required":["template_id"],"title":"ParseToTemplateResponse","description":"Response from the parse-to-template endpoint."},"PastDueRow":{"properties":{"planned_measurement_id":{"type":"string","title":"Planned Measurement Id","description":"Planned measurement ID"},"name":{"type":"string","title":"Name","description":"Planned measurement name"},"status":{"type":"string","title":"Status","description":"``requested`` or ``scheduled``"},"program_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Program Name","description":"Program this test belongs to"},"cell_specification_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cell Specification Name","description":"Cell specification to be tested"},"cell_instance_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cell Instance Name","description":"Cell instance assigned, if any"},"protocol_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Protocol Name","description":"Protocol to run"},"channel":{"anyOf":[{"$ref":"#/components/schemas/ChannelRef"},{"type":"null"}],"description":"Reserved channel; null while the plan is unscheduled"},"planned_start_time":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Planned Start Time","description":"When the run is planned to start"},"planned_end_time":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Planned End Time","description":"When the run is planned to release the channel"},"estimated_duration_seconds":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Estimated Duration Seconds","description":"Expected run duration, for plans with no times yet"},"requested_by_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Requested By Email","description":"Who requested the test"},"overdue_days":{"type":"number","title":"Overdue Days","description":"Days since ``planned_start_time`` passed, to one decimal. Always positive: a row is only past due once its start time is behind us."}},"type":"object","required":["planned_measurement_id","name","status","overdue_days"],"title":"PastDueRow","description":"A plan whose start time has passed while it is still waiting to run.\n\nExtends the queue row rather than wrapping it: this is the same planned\nmeasurement, read with a different question in mind — not \"what is coming\nup\" but \"what should already have happened\". Inheriting keeps the field set\nflat, matching :class:`UnscheduledRequestRow`, which carries its own\n``waiting_days`` the same way."},"PastDueSection":{"properties":{"measurements":{"items":{"$ref":"#/components/schemas/PastDueRow"},"type":"array","title":"Measurements","description":"Overdue plans, most overdue first"},"total":{"type":"integer","title":"Total","description":"Every past-due plan, before the display limit. Greater than len(measurements) when the list was capped. Unlike the accumulated slip — which is just the sum of the rows' ``overdue_days`` and so is left to the reader — this cannot be derived from the listed rows."}},"type":"object","required":["total"],"title":"PastDueSection","description":"Plans that should have started and have not.\n\nSplit out of the queue rather than filtered into it. The queue answers \"what\nis coming up\", and a plan whose start time has passed is not upcoming work —\ncounting it there both inflates the horizon total and hides the more urgent\nfact that something slipped. These need a decision (start it, reschedule it,\ncancel it) rather than a slot."},"PeriodDelta":{"properties":{"current":{"type":"number","title":"Current","description":"Value over the current window"},"previous":{"type":"number","title":"Previous","description":"Value over the window immediately before it"},"change":{"type":"number","title":"Change","description":"current - previous"},"change_percent":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Change Percent","description":"Change as a percentage of previous; null when previous is 0"}},"type":"object","required":["current","previous","change"],"title":"PeriodDelta","description":"One output metric this period against the period immediately before it.\n\n``change_percent`` is null when the previous period was zero: a rise from\nnothing is not a percentage, and rendering it as +100% (or as an infinity)\nwould misstate it."},"Permission":{"properties":{"id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Id"},"action":{"type":"string","title":"Action"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At"}},"type":"object","required":["action"],"title":"Permission"},"PermissionWithRoles":{"properties":{"id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Id"},"action":{"type":"string","title":"Action"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At"},"organization_roles":{"items":{"$ref":"#/components/schemas/RoleRef"},"type":"array","title":"Organization Roles"},"project_roles":{"items":{"$ref":"#/components/schemas/RoleRef"},"type":"array","title":"Project Roles"}},"type":"object","required":["action"],"title":"PermissionWithRoles","description":"A permission together with the roles that grant it.\n\nRead model for the admin Permissions page: each permission alongside the\norganization and project roles that reference it."},"Pipeline":{"properties":{"id":{"type":"string","title":"Id"},"project_id":{"type":"string","title":"Project Id"},"user_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"User Id"},"name":{"type":"string","title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"options":{"$ref":"#/components/schemas/PipelineOptions"},"status":{"$ref":"#/components/schemas/PipelineStatus"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error"},"error_code":{"anyOf":[{"$ref":"#/components/schemas/JobErrorCode"},{"type":"null"}]},"created_by_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created By Email"},"organization_id":{"type":"string","title":"Organization Id","description":"Organization this pipeline belongs to."}},"type":"object","required":["id","project_id","name","status","created_at","updated_at","organization_id"],"title":"Pipeline","description":"Model for representing a pipeline in API list responses (without elements)."},"PipelineCalculationMetadataRequest":{"properties":{"subtype":{"anyOf":[{"$ref":"#/components/schemas/ElementSubtype"},{"type":"string"},{"type":"null"}],"title":"Subtype"},"electrode":{"anyOf":[{"$ref":"#/components/schemas/Electrode"},{"type":"null"}]},"method":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Method"},"voltage_limits":{"anyOf":[{"items":{"type":"number"},"type":"array"},{"type":"null"}],"title":"Voltage Limits"},"options":{"anyOf":[{"additionalProperties":{"type":"string"},"type":"object"},{"type":"null"}],"title":"Options"},"soc":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Soc"}},"type":"object","title":"PipelineCalculationMetadataRequest"},"PipelineCalculationMetadataResponse":{"properties":{"input_parameters":{"items":{"type":"string"},"type":"array","title":"Input Parameters"},"required_parameters":{"items":{"type":"string"},"type":"array","title":"Required Parameters"},"allowed_parameters":{"items":{"type":"string"},"type":"array","title":"Allowed Parameters"},"required_variables":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Required Variables"}},"type":"object","required":["input_parameters","required_parameters","allowed_parameters"],"title":"PipelineCalculationMetadataResponse"},"PipelineConfig":{"properties":{"project_id":{"type":"string","title":"Project Id"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"options":{"$ref":"#/components/schemas/PipelineOptions"},"elements":{"additionalProperties":true,"type":"object","title":"Elements"}},"type":"object","required":["project_id","elements"],"title":"PipelineConfig"},"PipelineDetail":{"properties":{"id":{"type":"string","title":"Id"},"project_id":{"type":"string","title":"Project Id"},"user_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"User Id"},"name":{"type":"string","title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"options":{"$ref":"#/components/schemas/PipelineOptions"},"status":{"$ref":"#/components/schemas/PipelineStatus"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error"},"error_code":{"anyOf":[{"$ref":"#/components/schemas/JobErrorCode"},{"type":"null"}]},"created_by_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created By Email"},"organization_id":{"type":"string","title":"Organization Id","description":"Organization this pipeline belongs to."},"elements":{"items":{"$ref":"#/components/schemas/PipelineElement"},"type":"array","title":"Elements","default":[]}},"type":"object","required":["id","project_id","name","status","created_at","updated_at","organization_id"],"title":"PipelineDetail","description":"Model for representing a pipeline with its elements in detail responses."},"PipelineElement":{"properties":{"id":{"type":"string","title":"Id"},"pipeline_id":{"type":"string","title":"Pipeline Id"},"name":{"type":"string","title":"Name"},"element_order":{"type":"integer","exclusiveMinimum":0.0,"title":"Element Order","description":"Order of execution within the pipeline (1-based)"},"element_type":{"$ref":"#/components/schemas/ElementType","description":"Type of job for this step"},"job_config":{"additionalProperties":true,"type":"object","title":"Job Config","description":"Configuration parameters for the job"},"job_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Job Id"},"result":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Result"},"status":{"$ref":"#/components/schemas/PipelineElementStatus"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error"},"error_code":{"anyOf":[{"$ref":"#/components/schemas/JobErrorCode"},{"type":"null"}]},"error_detail":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}]},"job_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Job Status","description":"Job status via job_id (from jobs.status)."},"organization_id":{"type":"string","title":"Organization Id","description":"Organization this pipeline element belongs to."}},"type":"object","required":["id","pipeline_id","name","element_order","element_type","job_config","status","created_at","updated_at","organization_id"],"title":"PipelineElement","description":"Model for representing a pipeline element in API responses."},"PipelineElementStatus":{"type":"string","enum":["pending","running","completed","failed","skipped","canceled"],"title":"PipelineElementStatus"},"PipelineElementStatusInfo":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"element_order":{"type":"integer","exclusiveMinimum":0.0,"title":"Element Order"},"element_type":{"$ref":"#/components/schemas/ElementType"},"status":{"$ref":"#/components/schemas/PipelineElementStatus"},"job_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Job Id"},"job_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Job Status","description":"Job status via job_id (from jobs.status)."},"anyscale_job_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Anyscale Job Id","description":"Anyscale prodjob id via job_id (from jobs.anyscale_job_id)."},"anyscale_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Anyscale Url","description":"Deep-link to this element's job on the Anyscale console, or None.","readOnly":true}},"type":"object","required":["id","name","element_order","element_type","status","anyscale_url"],"title":"PipelineElementStatusInfo","description":"Minimal element fields for pipeline list status display (element + job status)."},"PipelineListResponse":{"properties":{"pipelines":{"items":{"$ref":"#/components/schemas/PipelineWithElementStatus"},"type":"array","title":"Pipelines"},"total":{"type":"integer","title":"Total"}},"type":"object","required":["pipelines","total"],"title":"PipelineListResponse","description":"Schema for listing pipelines with pagination"},"PipelineOptions":{"properties":{"live_progress_updates":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Live Progress Updates","description":"If True, save checkpoint progress to database during job execution. If None, the worker picks a default based on job type."}},"type":"object","title":"PipelineOptions","description":"Options for pipeline execution behavior."},"PipelineResult":{"properties":{"element_results":{"additionalProperties":true,"type":"object","title":"Element Results"},"result":{"additionalProperties":true,"type":"object","title":"Result"}},"type":"object","required":["element_results","result"],"title":"PipelineResult","description":"Model for representing a pipeline result."},"PipelineStatus":{"type":"string","enum":["pending","running","completed","failed","canceled"],"title":"PipelineStatus"},"PipelineUpdateRequest":{"properties":{"name":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}],"title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"}},"type":"object","title":"PipelineUpdateRequest"},"PipelineWithElementStatus":{"properties":{"id":{"type":"string","title":"Id"},"project_id":{"type":"string","title":"Project Id"},"user_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"User Id"},"name":{"type":"string","title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"options":{"$ref":"#/components/schemas/PipelineOptions"},"status":{"$ref":"#/components/schemas/PipelineStatus"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error"},"error_code":{"anyOf":[{"$ref":"#/components/schemas/JobErrorCode"},{"type":"null"}]},"created_by_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created By Email"},"organization_id":{"type":"string","title":"Organization Id","description":"Organization this pipeline belongs to."},"elements":{"items":{"$ref":"#/components/schemas/PipelineElementStatusInfo"},"type":"array","title":"Elements","default":[]}},"type":"object","required":["id","project_id","name","status","created_at","updated_at","organization_id"],"title":"PipelineWithElementStatus","description":"Pipeline with element and job status for list/detailed status display."},"PlannedMeasurement":{"properties":{"name":{"type":"string","maxLength":255,"minLength":1,"title":"Name"},"cell_specification_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cell Specification Id","description":"Cell specification the requester wants tested (set at request time)."},"cell_instance_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cell Instance Id","description":"Cell instance this future measurement will run on."},"channel_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Channel Id","description":"Channel reserved for this measurement, once scheduled."},"set_temperature_c":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Set Temperature C","description":"Temperature this test must run at, in degrees Celsius, held fixed for the whole test. None means ambient: the test runs outside a thermal chamber."},"thermal_chamber_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Thermal Chamber Id","description":"Chamber this test's channel sits in for the reservation. Recorded per reservation rather than per channel, because channels move between chambers."},"protocol_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Protocol Id","description":"Named protocol (experiment_template) this measurement will run. Required on create; a planned measurement must name a protocol."},"program_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Program Id","description":"Optional catalog program (Formation, Cycling, …) for this test request."},"test_setup":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Test Setup","description":"Planned physical setup."},"planned_start_time":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Planned Start Time","description":"When setup/run is planned to start."},"planned_end_time":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Planned End Time","description":"When this planned measurement is expected to release the channel."},"estimated_duration_seconds":{"anyOf":[{"type":"integer","minimum":1.0},{"type":"null"}],"title":"Estimated Duration Seconds","description":"Expected run duration before scheduled times exist."},"setup_duration_seconds":{"type":"integer","minimum":0.0,"title":"Setup Duration Seconds","description":"Operator setup duration before the test starts.","default":0},"teardown_duration_seconds":{"type":"integer","minimum":0.0,"title":"Teardown Duration Seconds","description":"Operator teardown duration after the test finishes.","default":0},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes","description":"Free-text planning notes."},"id":{"type":"string","title":"Id"},"organization_id":{"type":"string","title":"Organization Id"},"project_id":{"type":"string","title":"Project Id"},"status":{"$ref":"#/components/schemas/PlannedMeasurementStatus"},"requested_by":{"type":"string","title":"Requested By"},"scheduled_by":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Scheduled By"},"scheduled_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Scheduled At"},"started_measurement_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Started Measurement Id"},"cancelled_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Cancelled At"},"completed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Completed At"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"requested_by_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Requested By Email"},"scheduled_by_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Scheduled By Email"},"channel_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Channel Name"},"cycler_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cycler Id"},"cycler_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cycler Name"},"program_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Program Name"},"estimated_duration_status":{"anyOf":[{"$ref":"#/components/schemas/EstimationStatus"},{"type":"null"}]},"estimated_duration_job_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Estimated Duration Job Id"},"estimated_duration_simulation_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Estimated Duration Simulation Id"},"simulated_duration_seconds":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Simulated Duration Seconds"},"estimated_duration_is_exact":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Estimated Duration Is Exact"},"estimated_duration_margin_pct":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Estimated Duration Margin Pct"},"actual_duration_seconds":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Actual Duration Seconds"},"estimated_duration_note":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Estimated Duration Note"},"estimated_duration_calculated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Estimated Duration Calculated At"}},"type":"object","required":["name","id","organization_id","project_id","status","requested_by","created_at","updated_at"],"title":"PlannedMeasurement","description":"A planned measurement row returned by the API."},"PlannedMeasurementStatus":{"type":"string","enum":["requested","scheduled","in_progress","completed","cancelled"],"title":"PlannedMeasurementStatus","description":"Lifecycle state for a planned measurement."},"Program":{"properties":{"name":{"type":"string","maxLength":255,"minLength":1,"title":"Name","description":"Display name of the program."},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"Free-text description of the program."},"id":{"type":"string","title":"Id","description":"Unique identifier for the program"},"organization_id":{"type":"string","title":"Organization Id","description":"Organization this program belongs to."},"created_by":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created By","description":"User ID of the user who created this program"},"created_by_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created By Email","description":"Email of the user who created this program"},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"Timestamp when the program was created"},"updated_at":{"type":"string","format":"date-time","title":"Updated At","description":"Timestamp when the program was last updated"}},"type":"object","required":["name","id","organization_id","created_at","updated_at"],"title":"Program","description":"Model representing a program as returned by the API."},"ProgramUtilizationRow":{"properties":{"program_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Program Name","description":"Program name; null for tests with no program assigned"},"channels_in_use":{"type":"integer","title":"Channels In Use","description":"Occupied or stale channels running this program"},"percent_of_lab":{"type":"number","title":"Percent Of Lab","description":"channels_in_use over all channels, as a percentage"},"percent_of_in_use":{"type":"number","title":"Percent Of In Use","description":"channels_in_use over all occupied+stale channels, as a percentage"}},"type":"object","required":["channels_in_use","percent_of_lab","percent_of_in_use"],"title":"ProgramUtilizationRow","description":"How much of the lab one test program is occupying right now.\n\nA program does not own channels, so there is no meaningful \"total\" to\ndivide by; a program's footprint is expressed as a share of the lab and a\nshare of the work currently in flight."},"Project":{"properties":{"name":{"type":"string","title":"Name","description":"The name of the project."},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"An optional description for the project."},"id":{"type":"string","title":"Id","description":"The unique identifier for the project."},"organization_id":{"type":"string","title":"Organization Id","description":"The ID of the organization this project belongs to."},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"Timestamp of when the project was created."},"updated_at":{"type":"string","format":"date-time","title":"Updated At","description":"Timestamp of when the project was last updated."},"created_by":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created By","description":"User ID of the creator."},"user_project_roles":{"anyOf":[{"items":{"$ref":"#/components/schemas/UserProjectRole"},"type":"array"},{"type":"null"}],"title":"User Project Roles","description":"The user project roles in the project."}},"type":"object","required":["name","id","organization_id","created_at","updated_at"],"title":"Project"},"ProjectRole":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"project_role_permissions":{"anyOf":[{"items":{"additionalProperties":{"$ref":"#/components/schemas/Permission"},"type":"object"},"type":"array"},{"type":"null"}],"title":"Project Role Permissions","description":"The permissions for the project role."}},"type":"object","required":["id","name","created_at","updated_at"],"title":"ProjectRole"},"ProjectRoleWithPermissions":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At"},"permissions":{"items":{"$ref":"#/components/schemas/Permission"},"type":"array","title":"Permissions"}},"type":"object","required":["id","name"],"title":"ProjectRoleWithPermissions","description":"Project role with its permissions flattened into a list.\n\nRead model counterpart to :class:`OrganizationRoleWithPermissions` for\nproject roles (carries the extra ``description`` column)."},"ProjectUpdate":{"properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"The name of the project."},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"An optional description for the project."}},"type":"object","title":"ProjectUpdate"},"ProjectWebhook":{"properties":{"id":{"type":"string","title":"Id"},"project_id":{"type":"string","title":"Project Id"},"organization_id":{"type":"string","title":"Organization Id"},"url":{"type":"string","title":"Url"},"events":{"items":{"type":"string"},"type":"array","title":"Events"},"enabled":{"type":"boolean","title":"Enabled"},"consecutive_failures":{"type":"integer","title":"Consecutive Failures","default":0},"disabled_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Disabled Reason"},"created_by":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created By"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","project_id","organization_id","url","events","enabled","created_at","updated_at"],"title":"ProjectWebhook","description":"A project webhook as returned by list/get (secret omitted)."},"ProjectWebhookCreated":{"properties":{"id":{"type":"string","title":"Id"},"project_id":{"type":"string","title":"Project Id"},"organization_id":{"type":"string","title":"Organization Id"},"url":{"type":"string","title":"Url"},"events":{"items":{"type":"string"},"type":"array","title":"Events"},"enabled":{"type":"boolean","title":"Enabled"},"consecutive_failures":{"type":"integer","title":"Consecutive Failures","default":0},"disabled_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Disabled Reason"},"created_by":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created By"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"secret":{"type":"string","title":"Secret","description":"HMAC signing secret; shown only in the create response."}},"type":"object","required":["id","project_id","organization_id","url","events","enabled","created_at","updated_at","secret"],"title":"ProjectWebhookCreated","description":"Create response that includes the signing secret once."},"Protocol":{"properties":{"header":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Header","description":"Original cycler header metadata."},"safety_limits":{"anyOf":[{"$ref":"#/components/schemas/SafetyLimits"},{"type":"null"}]},"steps":{"items":{"anyOf":[{"$ref":"#/components/schemas/StandardStep"},{"$ref":"#/components/schemas/RestStep"},{"$ref":"#/components/schemas/AmbientTemperatureStep"},{"$ref":"#/components/schemas/ControlStep"},{"$ref":"#/components/schemas/AuxiliaryStep"},{"$ref":"#/components/schemas/EISStep"},{"$ref":"#/components/schemas/SubroutineStep"},{"$ref":"#/components/schemas/DriveCycleStep"},{"$ref":"#/components/schemas/StepBlock"}]},"type":"array","title":"Steps","description":"List of steps or step blocks"},"global":{"$ref":"#/components/schemas/GlobalConfig","description":"Global settings for the protocol"}},"additionalProperties":false,"type":"object","required":["steps"],"title":"Protocol","description":"Complete protocol definition."},"ProtocolDifference":{"properties":{"location":{"type":"string","title":"Location","description":"Where the difference is, e.g. 'Discharge [#2]'."},"kind":{"type":"string","title":"Kind","description":"Machine-readable category, e.g. 'loop_repeat', 'end_condition', 'setpoint', 'goto_target', 'step_count', 'safety_limits', 'cumulative_block_end'."},"severity":{"type":"string","title":"Severity","description":"'behavioural' changes what the cycler does; 'expected' is a re-encoding a target format forces; 'unknown' is a real difference no tolerance explains."},"detail":{"type":"string","title":"Detail","description":"What changed, in cycler terms, e.g. 'control setpoint changed: Discharge at 1.0 (C-rate) -> Discharge at 2.0 (C-rate)'."},"reason":{"type":"string","title":"Reason","description":"Why it matters -- the consequence on hardware, so a caller can judge severity without reading the protocols.","default":""},"left":{"title":"Left","description":"Value on the left protocol."},"right":{"title":"Right","description":"Value on the right protocol."}},"type":"object","required":["location","kind","severity","detail"],"title":"ProtocolDifference","description":"One semantic difference between the two protocols."},"ProtocolExperimentConfig":{"properties":{"protocol":{"anyOf":[{"type":"string"},{"$ref":"#/components/schemas/Protocol"}],"title":"Protocol","description":"Protocol content as string or Protocol object"},"name":{"type":"string","title":"Name","description":"Required protocol name for template naming"},"additional_content_files":{"anyOf":[{"additionalProperties":{"type":"string","contentMediaType":"application/octet-stream"},"type":"object"},{"type":"null"}],"title":"Additional Content Files","description":"Additional content files for protocol parsing"},"parameters_schema":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Parameters Schema","description":"JSON Schema for input parameters detected in the protocol"}},"type":"object","required":["protocol","name"],"title":"ProtocolExperimentConfig","description":"Experiment configuration using protocol string or Protocol object."},"ProtocolGroup":{"properties":{"id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Id","description":"Unique identifier for the group"},"name":{"type":"string","title":"Name","description":"Name of the group, unique within the project"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"Optional note on what relates the protocols in this group"},"organization_id":{"type":"string","title":"Organization Id","description":"ID of the organization that owns this group"},"project_id":{"type":"string","title":"Project Id","description":"ID of the project that owns this group"},"created_by":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created By","description":"User ID of the user who created this group"},"created_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At","description":"When the group was created"},"updated_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated At","description":"When the group was last updated"},"protocol_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Protocol Count","description":"Number of protocols in this group. Present on list responses, None when the group is fetched on its own."},"created_by_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created By Email","description":"Email of the user who created this group"}},"type":"object","required":["name","organization_id","project_id"],"title":"ProtocolGroup","description":"Database entity for a protocol group."},"ProtocolGroupListResponse":{"properties":{"items":{"items":{"$ref":"#/components/schemas/ProtocolGroup"},"type":"array","title":"Items"},"count":{"type":"integer","title":"Count"},"total":{"type":"integer","title":"Total"}},"type":"object","required":["items","count","total"],"title":"ProtocolGroupListResponse","description":"Paginated list of protocol groups."},"Quantity":{"properties":{"value":{"anyOf":[{"type":"number"},{"type":"integer"}],"title":"Value"},"unit":{"type":"string","title":"Unit","description":"Unit string in PyBaMM notation: '.'-separated atoms with signed integer exponents (e.g. 'A.h', 'mg.cm-2', 'W.h.kg-1'). Pint-style strings ('A*h', 'mg/cm**2') are also accepted and normalized to PyBaMM notation. Common units: V, A, A.h, W.h, degC, s, ohm."}},"type":"object","required":["value","unit"],"title":"Quantity","description":"A numeric value with its physical unit.\n\nAll numeric fields that carry physical meaning across the cell-data API\n(capacities, voltages, masses, temperatures, etc.) use this structured\nformat rather than bare floats. That keeps the units on the wire so the\nserver, clients, and downstream consumers cannot disagree about them.\n\nCanonical form:\n\n```json\n{\"value\": 1.1, \"unit\": \"A.h\"}\n```\n\nCommon units used across the platform: ``V``, ``A``, ``A.h``, ``W.h``,\n``degC``, ``s``, ``ohm``, ``mm``, ``g``, ``mg.cm-2``, ``C`` (C-rate).\n\nUnits are stored in PyBaMM notation: ``.``-separated atoms with signed\ninteger exponents and no ``*``/``/`` (``mg.cm-2``, ``A.h``,\n``W.h.kg-1``). Pint-style strings (``mg/cm**2``, ``A*h``, ``W*h/kg``) are\nstill accepted on input for backwards compatibility and are normalized to\nPyBaMM notation on construction. Either form parses correctly via\n:meth:`to_pint`."},"QueueSection":{"properties":{"horizon_days":{"type":"integer","title":"Horizon Days","description":"Only plans starting within this many days are listed"},"measurements":{"items":{"$ref":"#/components/schemas/QueuedMeasurementRow"},"type":"array","title":"Measurements","description":"Queued plans, earliest start first"},"total_in_horizon":{"type":"integer","title":"Total In Horizon","description":"Plans starting within the horizon, before the display limit is applied. Greater than len(measurements) when the list was capped."},"undated_count":{"type":"integer","title":"Undated Count","description":"Requested plans with no planned start time. Not listed (they have no queue position) but surfaced so the backlog is visible."}},"type":"object","required":["horizon_days","total_in_horizon","undated_count"],"title":"QueueSection","description":"The near-term queue, with enough context to trust what is missing.\n\nA queue is only meaningful if the reader knows what was left out, so the\nsection carries its own horizon and totals rather than silently truncating:\n``total_in_horizon`` is every plan starting inside the window (not just the\nlisted ones) and ``undated_count`` is the backlog of requests with no date\nyet, which have no place in a time-ordered queue but should not vanish.\n\nBounded on both sides: only plans starting between the report time and the\nhorizon. A plan whose start time has already passed is not upcoming work and\nbelongs in :class:`PastDueSection`."},"QueuedMeasurementRow":{"properties":{"planned_measurement_id":{"type":"string","title":"Planned Measurement Id","description":"Planned measurement ID"},"name":{"type":"string","title":"Name","description":"Planned measurement name"},"status":{"type":"string","title":"Status","description":"``requested`` or ``scheduled``"},"program_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Program Name","description":"Program this test belongs to"},"cell_specification_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cell Specification Name","description":"Cell specification to be tested"},"cell_instance_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cell Instance Name","description":"Cell instance assigned, if any"},"protocol_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Protocol Name","description":"Protocol to run"},"channel":{"anyOf":[{"$ref":"#/components/schemas/ChannelRef"},{"type":"null"}],"description":"Reserved channel; null while the plan is unscheduled"},"planned_start_time":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Planned Start Time","description":"When the run is planned to start"},"planned_end_time":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Planned End Time","description":"When the run is planned to release the channel"},"estimated_duration_seconds":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Estimated Duration Seconds","description":"Expected run duration, for plans with no times yet"},"requested_by_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Requested By Email","description":"Who requested the test"}},"type":"object","required":["planned_measurement_id","name","status"],"title":"QueuedMeasurementRow","description":"A planned measurement waiting to run, with its program and cell.\n\nShared by :class:`PastDueSection` and :class:`QueueSection`: both describe\nthe same entity, one selecting plans whose start time has passed and the\nother plans still ahead."},"RangeParam":{"properties":{"type":{"type":"string","const":"range","title":"Type","default":"range"},"name":{"type":"string","title":"Name"},"min":{"type":"number","title":"Min"},"max":{"type":"number","title":"Max"},"count":{"anyOf":[{"type":"integer","minimum":1.0},{"type":"null"}],"title":"Count"}},"type":"object","required":["name","min","max"],"title":"RangeParam","description":"Range parameter configuration.\n\nParameters\n----------\nname\n    Parameter name.\nmin\n    Minimum value (inclusive).\nmax\n    Maximum value (inclusive).\ncount\n    Optional grid sample count for this parameter. Required for\n    ``grid`` sampling; ignored for non-grid methods."},"Ratings":{"properties":{"capacity":{"$ref":"#/components/schemas/Quantity","description":"Rated capacity, e.g., {'value': 0.002, 'unit': 'A.h'}"},"voltage_min":{"$ref":"#/components/schemas/Quantity","description":"Minimum voltage, e.g., {'value': 2.5, 'unit': 'V'}"},"voltage_max":{"$ref":"#/components/schemas/Quantity","description":"Maximum voltage, e.g., {'value': 4.2, 'unit': 'V'}"},"nominal_voltage":{"anyOf":[{"$ref":"#/components/schemas/Quantity"},{"type":"null"}],"description":"Nominal voltage, e.g., {'value': 3.6, 'unit': 'V'}"},"energy":{"anyOf":[{"$ref":"#/components/schemas/Quantity"},{"type":"null"}],"description":"Rated energy, e.g., {'value': 7.2, 'unit': 'mW.h'}"},"energy_density_gravimetric":{"anyOf":[{"$ref":"#/components/schemas/Quantity"},{"type":"null"}],"description":"Gravimetric energy density, e.g., {value: 250, unit: 'W.h.kg-1'}"},"energy_density_volumetric":{"anyOf":[{"$ref":"#/components/schemas/Quantity"},{"type":"null"}],"description":"Volumetric energy density, e.g., {'value': 650, 'unit': 'W.h.L-1'}"},"max_discharge_rate":{"anyOf":[{"$ref":"#/components/schemas/Quantity"},{"type":"null"}],"description":"Max discharge C-rate, e.g., {'value': 2, 'unit': 'C'}"},"max_charge_rate":{"anyOf":[{"$ref":"#/components/schemas/Quantity"},{"type":"null"}],"description":"Max charge C-rate, e.g., {'value': 1, 'unit': 'C'}"}},"type":"object","required":["capacity","voltage_min","voltage_max"],"title":"Ratings","description":"Electrical ratings from spec sheet / design targets."},"RawData":{"properties":{"project_id":{"type":"string","title":"Project Id","description":"Owning project ID (required)."},"name":{"type":"string","title":"Name","description":"User-provided label for the raw file."},"source":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source","description":"Free-text provenance: where this raw file came from (a URL, DOI, S3 URI, vendor/cycler export description, etc.)."},"metadata":{"additionalProperties":true,"type":"object","title":"Metadata","description":"Loose free-form metadata."},"id":{"type":"string","title":"Id","description":"Unique identifier."},"organization_id":{"type":"string","title":"Organization Id","description":"Owning organization."},"filename":{"type":"string","title":"Filename","description":"Original uploaded filename."},"content_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Content Type","description":"MIME type, if known."},"size_bytes":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Size Bytes","description":"File size in bytes."},"storage_path":{"type":"string","title":"Storage Path","description":"Path within the raw-data bucket."},"processing_status":{"type":"string","enum":["pending","queued","processing","needs_review","awaiting_cell","done","failed"],"title":"Processing Status","description":"Ingestion lifecycle: pending | queued | processing | needs_review | awaiting_cell | done | failed. See src.pydantic_models.raw_data_ingestion for what each means.","default":"pending"},"processing_error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Processing Error","description":"Terminal ingestion failure message, if any."},"processed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Processed At","description":"When ingestion last reached a terminal state."},"reader":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reader","description":"Cycler format detected on parse (arbin, maccor, ...)."},"created_by":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created By","description":"User ID of the uploader."},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"Creation timestamp."},"updated_at":{"type":"string","format":"date-time","title":"Updated At","description":"Last update timestamp."}},"type":"object","required":["project_id","name","id","organization_id","filename","storage_path","created_at","updated_at"],"title":"RawData","description":"A raw-data record as returned by the API."},"RawDataIssue":{"properties":{"id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Id","description":"Row id once persisted; None for freshly parsed issues."},"code":{"type":"string","title":"Code","description":"Stable machine-readable code — an ionworks IssueCode value or an engine-specific code. Branch on this, never on title/detail."},"severity":{"type":"string","enum":["auto_fixed","warning","needs_input","blocking"],"title":"Severity","description":"Whether this blocks ingestion and how it is displayed."},"title":{"type":"string","title":"Title","description":"Plain-English title, no error codes."},"detail":{"type":"string","title":"Detail","description":"One-paragraph explanation.","default":""},"payload":{"additionalProperties":true,"type":"object","title":"Payload","description":"Structured details: columns, observed values, row ranges."},"fix_summary":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Fix Summary","description":"For auto_fixed issues: short description of what changed."},"resolution":{"anyOf":[{"type":"string","enum":["accept","reject","change_cell"]},{"type":"null"}],"title":"Resolution","description":"Reviewer decision; None while unresolved."},"resolved_by":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Resolved By","description":"User who resolved it."},"resolved_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Resolved At","description":"Resolution timestamp."},"options":{"items":{"$ref":"#/components/schemas/FixOption"},"type":"array","title":"Options","description":"Choices available for this finding.\n\nDerived from ``code`` and ``severity`` rather than stored, so the\ncatalogue can grow without a migration and can never drift from what\n:meth:`resolve` actually accepts.","readOnly":true}},"type":"object","required":["code","severity","title","options"],"title":"RawDataIssue","description":"A single validation finding for a raw-data file.\n\nEmitted by the parse engine (with no id/timestamps) and persisted to\n``raw_data_issues``, where it gains identity and resolution fields."},"RawDataUploadInfo":{"properties":{"filename":{"type":"string","title":"Filename","description":"Filename this signed URL targets."},"signed_url":{"type":"string","title":"Signed Url","description":"Pre-signed URL to PUT the file to."},"token":{"type":"string","title":"Token","description":"Upload token from storage."},"path":{"type":"string","title":"Path","description":"Storage path within the raw-data bucket."},"multipart":{"anyOf":[{"$ref":"#/components/schemas/MultipartUploadInfo"},{"type":"null"}],"description":"Optional S3-multipart target for large files. Clients that do not understand this field fall back to PUTting the signed URL."}},"type":"object","required":["filename","signed_url","token","path"],"title":"RawDataUploadInfo","description":"Signed-URL info for the single raw-data upload target."},"RcPairFitData":{"properties":{"r":{"items":{"type":"number"},"type":"array","title":"R"},"c":{"items":{"type":"number"},"type":"array","title":"C"},"tau":{"items":{"type":"number"},"type":"array","title":"Tau"}},"type":"object","required":["r","c","tau"],"title":"RcPairFitData","description":"RC pair fit result arrays."},"RecentlyStoppedSection":{"properties":{"rows":{"items":{"$ref":"#/components/schemas/StoppedMeasurementRow"},"type":"array","title":"Rows","description":"Finished runs, most recently ended first"},"beyond_cap":{"type":"integer","title":"Beyond Cap","description":"Runs the display cap excluded, exactly: the query counts the whole window server-side, so this is how many more finished, not merely that more did. Adding it to the row count gives the window's true total. Non-zero means the list is the most recent slice, not the full window.","default":0}},"type":"object","title":"RecentlyStoppedSection","description":"Tests that finished in the lookback window, and what the list left out.\n\nA list rather than a bare count because the useful question is which\nchannels came free and what was on them. It is capped for the same reason\nthe other list sections are: ``recently_stopped_hours`` reaches back up to\n90 days, and a large lab on short protocols finishes thousands of runs in\nthat time — too many to fetch, hold, or render as one table."},"ReferencedParameter":{"properties":{"name":{"type":"string","title":"Name"},"exists":{"type":"boolean","title":"Exists"},"similar_existing":{"items":{"type":"string"},"type":"array","title":"Similar Existing","default":[]}},"type":"object","required":["name","exists"],"title":"ReferencedParameter","description":"A Parameter node found in the expression."},"ReferencedVariable":{"properties":{"name":{"type":"string","title":"Name"},"exists":{"type":"boolean","title":"Exists"},"source":{"type":"string","title":"Source"}},"type":"object","required":["name","exists","source"],"title":"ReferencedVariable","description":"A model or custom variable referenced by a CoupledVariable node."},"ResolutionConfig":{"properties":{"time":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Time","description":"Interval at which to save data (in seconds). Defaults to the adaptive time stepping if not specified. Supports input expressions like 'input[\"C-rate\"]' or math like '10 / input[\"C-rate\"]'."},"voltage":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Voltage","description":"Interval at which to save data (in volts). Ignored if not specified. Supports input expressions like 'input[\"Upper voltage cut-off [V]\"]' or math like 'input[\"Upper voltage cut-off [V]\"]' / 1000."},"current":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Current","description":"Interval at which to save data (in amps). Ignored if not specified. Supports input expressions like 'input[\"C-rate\"]' or math like '10 / input[\"C-rate\"]'."}},"additionalProperties":false,"type":"object","title":"ResolutionConfig","description":"Resolution for saving data."},"ResolveIssueRequest":{"properties":{"resolution":{"type":"string","enum":["accept","reject","change_cell"],"title":"Resolution","description":"The chosen option's id."}},"type":"object","required":["resolution"],"title":"ResolveIssueRequest","description":"Body for resolving a single validation issue.\n\nThe valid values for a given finding are exactly the ``id``s of the\n``options`` that finding reports; sending anything else is rejected with\nthe allowed set listed."},"ResolveIssuesRequest":{"properties":{"resolutions":{"additionalProperties":{"type":"string","enum":["accept","reject","change_cell"]},"type":"object","minProperties":1,"title":"Resolutions","description":"Chosen option id, keyed by issue id."}},"type":"object","required":["resolutions"],"title":"ResolveIssuesRequest","description":"Body for resolving several findings on one file in a single call.\n\nA reviewer usually faces several findings at once, and resolving them one\nrequest at a time makes the UI's \"save my answers\" button non-atomic."},"ResolveIssuesResponse":{"properties":{"resolved":{"type":"integer","title":"Resolved","description":"Findings updated."},"issues":{"items":{"$ref":"#/components/schemas/RawDataIssue"},"type":"array","title":"Issues","description":"Every finding on the file, post-update."},"ready_to_retry":{"type":"boolean","title":"Ready To Retry","description":"True when no finding still blocks ingestion, so the file can be retried immediately."}},"type":"object","required":["resolved","ready_to_retry"],"title":"ResolveIssuesResponse","description":"Result of a bulk resolve."},"RestStep":{"properties":{"ends":{"items":{"anyOf":[{"$ref":"#/components/schemas/CustomEnd"},{"$ref":"#/components/schemas/DurationEnd"},{"$ref":"#/components/schemas/CapacityEnd"},{"$ref":"#/components/schemas/LoopNumberEnd"},{"$ref":"#/components/schemas/VariableEnd"},{"$ref":"#/components/schemas/AndEnd"},{"$ref":"#/components/schemas/OrEnd"}]},"type":"array","title":"Ends","description":"List of duration or end conditions"},"kind":{"type":"string","const":"rest","title":"Kind","description":"The type of this step","default":"rest"},"set_variable":{"items":{"$ref":"#/components/schemas/SetVariable"},"type":"array","title":"Set Variable","description":"Variables to set based on this step"},"note":{"type":"string","title":"Note","description":"An optional note for the step.","default":""},"resolution":{"anyOf":[{"$ref":"#/components/schemas/ResolutionConfig"},{"type":"null"}],"description":"Resolution for saving data for this step."}},"additionalProperties":false,"type":"object","title":"RestStep","description":"A step that represents a rest period."},"RoleRef":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"}},"type":"object","required":["id","name"],"title":"RoleRef","description":"Minimal role reference (id + name) attached to a permission."},"SafetyLimit":{"properties":{"value":{"type":"number","title":"Value","description":"Limit value (units depend on the field)."},"goto":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Goto","description":"Step to jump to when this specific limit triggers (e.g. 'Step_13'). If None, falls back to ``SafetyLimits.goto``; if that is also None, the test ends."},"delay":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Delay","description":"Time in seconds the limit must be continuously violated before the safety triggers. Used as a debounce to avoid spurious trips at step start (e.g. Maccor ``VOLT>=4.5&STIME>3`` encodes a 3 s delay). ``None`` means the safety triggers immediately."}},"additionalProperties":false,"type":"object","required":["value"],"title":"SafetyLimit","description":"A single safety bound with an optional dedicated goto step.\n\nEach bound carries its own ``goto`` so that different fault conditions can\nroute to different recovery / pause steps (e.g. \"max capacity exceeded\"\nvs \"operating voltage exceeded\"). When ``goto`` is None the limit falls\nback to ``SafetyLimits.goto``; when both are None the test ends."},"SafetyLimits":{"properties":{"voltage_min":{"anyOf":[{"$ref":"#/components/schemas/SafetyLimit"},{"type":"null"}],"description":"Minimum voltage limit [V]"},"voltage_max":{"anyOf":[{"$ref":"#/components/schemas/SafetyLimit"},{"type":"null"}],"description":"Maximum voltage limit [V]"},"temperature_min":{"anyOf":[{"$ref":"#/components/schemas/SafetyLimit"},{"type":"null"}],"description":"Minimum temperature limit [°C]"},"temperature_max":{"anyOf":[{"$ref":"#/components/schemas/SafetyLimit"},{"type":"null"}],"description":"Maximum temperature limit [°C]"},"charge_current_max":{"anyOf":[{"$ref":"#/components/schemas/SafetyLimit"},{"type":"null"}],"description":"Maximum charge current limit [A]"},"discharge_current_max":{"anyOf":[{"$ref":"#/components/schemas/SafetyLimit"},{"type":"null"}],"description":"Maximum discharge current limit [A]"},"goto":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Goto","description":"Default step to jump to when a limit without its own ``goto`` triggers (e.g. 'Step_13'). If None and the triggering limit also has no ``goto``, the test ends."}},"additionalProperties":false,"type":"object","title":"SafetyLimits","description":"Safety limits for the protocol.\n\nEach limit may be specified as a bare number (legacy form) or as a\n:class:`SafetyLimit` object with its own ``goto``. Bare numbers use the\ntop-level ``goto`` as their fallback target. The schema accepts both\nforms on input so previously-saved protocols continue to validate\nunchanged; on output every limit is the structured ``SafetyLimit`` form."},"SaveToProjectRequest":{"properties":{"name":{"type":"string","minLength":1,"title":"Name","description":"Name for the model."},"description":{"type":"string","title":"Description","description":"Optional description.","default":""},"cell_spec_id":{"type":"string","title":"Cell Spec Id","description":"Cell specification ID."},"num_rcs":{"type":"integer","maximum":5.0,"minimum":0.0,"title":"Num Rcs","description":"Number of RC pairs."},"fit_results":{"$ref":"#/components/schemas/FitResultsData"}},"type":"object","required":["name","cell_spec_id","num_rcs","fit_results"],"title":"SaveToProjectRequest","description":"Request body for saving ECM fit results as a Parameterized Model."},"SaveToProjectResponse":{"properties":{"model_id":{"type":"string","title":"Model Id"},"parameterized_model_id":{"type":"string","title":"Parameterized Model Id"}},"type":"object","required":["model_id","parameterized_model_id"],"title":"SaveToProjectResponse","description":"Response from save-to-project."},"ScanResponse":{"properties":{"scanned":{"type":"integer","title":"Scanned","description":"Pending records examined."},"queued":{"type":"integer","title":"Queued","description":"Records enqueued for ingestion."},"raw_data_ids":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Raw Data Ids","description":"The records that were enqueued."}},"type":"object","required":["scanned","queued"],"title":"ScanResponse","description":"Result of a scan sweep over a project's pending raw-data records."},"ScheduledServiceRow":{"properties":{"service_event_id":{"type":"string","title":"Service Event Id","description":"Service event ID"},"cycler_id":{"type":"string","title":"Cycler Id","description":"The cycler booked in"},"cycler_name":{"type":"string","title":"Cycler Name","description":"Cycler name"},"site_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Site Name","description":"Site the cycler sits at"},"event_type":{"$ref":"#/components/schemas/ServiceEventType","description":"What kind of work this is"},"scheduled_for":{"type":"string","format":"date-time","title":"Scheduled For","description":"When the visit is booked"},"scheduled_until":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Scheduled Until","description":"When the visit is booked to end. Null on an open-ended booking, which is a real state and not a gap to fill in: a visit whose end nobody estimated must not be reported as ending the moment it starts."},"days_until":{"type":"number","title":"Days Until","description":"Days from the report time to the visit, to one decimal"},"duration_days":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Duration Days","description":"Booked length of the visit in days, to one decimal. Null when the booking is open-ended. This is how long the channels below are expected to be gone, which is what decides whether a visit is a blip or a plan the queue has to route around."},"channels_affected":{"type":"integer","title":"Channels Affected","description":"Channels that will go offline. The capacity cost of the visit, and the reason a booking belongs in a report rather than only a diary."},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes","description":"Free-text detail about the service"}},"type":"object","required":["service_event_id","cycler_id","cycler_name","event_type","scheduled_for","days_until","channels_affected"],"title":"ScheduledServiceRow","description":"A booked service visit that will take a cycler offline."},"SearchResponse":{"properties":{"results":{"items":{"$ref":"#/components/schemas/SearchResult"},"type":"array","title":"Results"},"query":{"type":"string","title":"Query"},"total":{"type":"integer","title":"Total"},"limit":{"type":"integer","title":"Limit"},"offset":{"type":"integer","title":"Offset"}},"type":"object","required":["results","query","total","limit","offset"],"title":"SearchResponse","description":"Response from the global search endpoint."},"SearchResult":{"properties":{"id":{"type":"string","title":"Id"},"entity_type":{"type":"string","title":"Entity Type"},"name":{"type":"string","title":"Name"},"project_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Id"},"created_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At"},"parent_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Parent Id"}},"type":"object","required":["id","entity_type","name"],"title":"SearchResult","description":"A single search result from any searchable entity type."},"ServiceChangePeriod":{"properties":{"label":{"type":"string","title":"Label","description":"Human label for the lookback, e.g. '7 days'"},"hours_ago":{"type":"integer","title":"Hours Ago","description":"How far back this period reaches"},"recovered":{"type":"integer","title":"Recovered","description":"Outages closed within the period"},"taken_out":{"type":"integer","title":"Taken Out","description":"Outages opened within the period"},"net":{"type":"integer","title":"Net","description":"recovered - taken_out"},"mean_repair_hours":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Mean Repair Hours","description":"Mean repair time over the period's measurable repairs"}},"type":"object","required":["label","hours_ago","recovered","taken_out","net"],"title":"ServiceChangePeriod","description":"Repairs and removals over one lookback, for the multi-period ladder.\n\nThe trend window alone cannot separate a bad week from a bad quarter: three\nchannels repaired in the last 24 hours reads very differently against two in\nthe last 30 days than against forty. Uses the same lookbacks as\n:class:`UtilizationComparison` so the two ladders line up."},"ServiceEventType":{"type":"string","enum":["calibration","preventive_maintenance","firmware","repair","other"],"title":"ServiceEventType","description":"What kind of work took (or will take) a cycler out of service.\n\nMirrors the ``cycler_service_events_shape_check`` CHECK constraint. Stored\nas CHECK-constrained text rather than a Postgres enum so the allowed set can\nbe widened by swapping a constraint — ``ALTER TYPE ... ADD VALUE`` does not\ncompose with the additive-migration rule.\n\n``calibration`` is the one that feeds ``cyclers.last_calibrated_at``:\ncompleting an event of this type is what advances the calibration clock."},"ServicedCyclerRow":{"properties":{"cycler_id":{"type":"string","title":"Cycler Id","description":"The cycler being serviced"},"cycler_name":{"type":"string","title":"Cycler Name","description":"Cycler name"},"site_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Site Name","description":"Site the cycler sits at"},"event_type":{"$ref":"#/components/schemas/ServiceEventType","description":"What kind of work this is"},"channels_down":{"type":"integer","title":"Channels Down","description":"Channels this event has taken out of service"},"scheduled_for":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Scheduled For","description":"When the visit was booked"},"scheduled_until":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Scheduled Until","description":"When the visit was booked to end, if an end was given"},"down_since":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Down Since","description":"When the earliest of its channel outages opened"},"down_for_days":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Down For Days","description":"Days elapsed since ``down_since``, to one decimal"},"overdue_days":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Overdue Days","description":"Days past ``scheduled_until``, to one decimal, for a visit still open after its booked return. Null when the visit is inside its window or open-ended — an absent booked end is not lateness, and reporting it as zero would claim the visit is exactly on time."},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes","description":"Free-text detail about the service"}},"type":"object","required":["cycler_id","cycler_name","event_type","channels_down"],"title":"ServicedCyclerRow","description":"A whole cycler out of service under one instrument-level event.\n\nCalibration and preventive maintenance are performed on the instrument, so\na 40-channel cycler going in for its annual calibration is one visit — not\nforty unrelated channel faults that happen to share a category. Reporting it\nonce, with the channel count, is what keeps a single calibration from\nburying every genuine channel-local fault under forty rows."},"SetVariable":{"properties":{"name":{"type":"string","title":"Name","description":"Name of the variable being set"},"eval":{"type":"string","title":"Eval","description":"Expression to evaluate for the variable"},"note":{"type":"string","title":"Note","description":"Optional note describing the variable","default":""}},"additionalProperties":false,"type":"object","required":["name","eval"],"title":"SetVariable","description":"Variable to set based on an expression."},"SimplePipeline":{"properties":{"id":{"type":"string","title":"Id"},"project_id":{"type":"string","title":"Project Id"},"organization_id":{"type":"string","title":"Organization Id"},"user_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"User Id"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"status":{"$ref":"#/components/schemas/PipelineStatus"},"job_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Job Id"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error"},"error_code":{"anyOf":[{"$ref":"#/components/schemas/JobErrorCode"},{"type":"null"}]},"created_by_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created By Email"},"config_path":{"type":"string","title":"Config Path"},"result":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Result"}},"type":"object","required":["id","project_id","organization_id","status","created_at","updated_at","config_path"],"title":"SimplePipeline","description":"Full model for detail responses and DB records."},"SimplePipelineListItem":{"properties":{"id":{"type":"string","title":"Id"},"project_id":{"type":"string","title":"Project Id"},"organization_id":{"type":"string","title":"Organization Id"},"user_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"User Id"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"status":{"$ref":"#/components/schemas/PipelineStatus"},"job_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Job Id"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error"},"error_code":{"anyOf":[{"$ref":"#/components/schemas/JobErrorCode"},{"type":"null"}]},"created_by_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created By Email"}},"type":"object","required":["id","project_id","organization_id","status","created_at","updated_at"],"title":"SimplePipelineListItem","description":"Lightweight model for list responses — excludes config_path and result."},"SimplePipelineListResponse":{"properties":{"items":{"items":{"$ref":"#/components/schemas/SimplePipelineListItem"},"type":"array","title":"Items"},"count":{"type":"integer","title":"Count","description":"Number of items in this page"},"total":{"type":"integer","title":"Total","description":"Total number of matching items"}},"type":"object","required":["items","count","total"],"title":"SimplePipelineListResponse","description":"Paginated list response for SimplePipelines."},"SimplePipelineUpdateRequest":{"properties":{"name":{"anyOf":[{"type":"string","maxLength":255,"minLength":1},{"type":"null"}],"title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"}},"type":"object","title":"SimplePipelineUpdateRequest","description":"Request body for partially updating a SimplePipeline (name/description)."},"SimulationBoard":{"properties":{"name":{"type":"string","title":"Name","description":"The name of the simulation board."},"template_id":{"type":"string","title":"Template Id","description":"The experiment template this board is bound to."},"project_id":{"type":"string","title":"Project Id","description":"The project this simulation board belongs to."},"study_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Study Id","description":"The study this simulation board belongs to, if any."},"organization_id":{"type":"string","title":"Organization Id","description":"Organization this simulation board belongs to."},"config":{"additionalProperties":true,"type":"object","title":"Config","description":"Visualization config (plots and grid layout)."},"table_filter":{"additionalProperties":true,"type":"object","title":"Table Filter","description":"Persisted MUI DataGrid filter model for this board."},"column_visibility":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Column Visibility","description":"Persisted MUI DataGrid column visibility model for this board."},"id":{"type":"string","title":"Id","description":"The unique identifier for the board."},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"Timestamp of when the board was created."}},"type":"object","required":["name","template_id","project_id","organization_id","id","created_at"],"title":"SimulationBoard"},"SimulationBoardCreatePayload":{"properties":{"name":{"type":"string","title":"Name","description":"The name of the simulation board."},"template_id":{"type":"string","title":"Template Id","description":"The experiment template this board is bound to."},"config":{"additionalProperties":true,"type":"object","title":"Config","description":"Visualization config (plots and grid layout)."},"table_filter":{"additionalProperties":true,"type":"object","title":"Table Filter","description":"Persisted MUI DataGrid filter model for this board."},"column_visibility":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Column Visibility","description":"Persisted MUI DataGrid column visibility model for this board."}},"type":"object","required":["name","template_id"],"title":"SimulationBoardCreatePayload"},"SimulationCreationResponse":{"properties":{"simulation_id":{"type":"string","title":"Simulation Id"},"job_id":{"type":"string","title":"Job Id"}},"type":"object","required":["simulation_id","job_id"],"title":"SimulationCreationResponse","description":"Response for simulation creation requests."},"SimulationStatusItem":{"properties":{"simulation_id":{"type":"string","title":"Simulation Id"},"status":{"$ref":"#/components/schemas/JobStatus"},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error"},"error_code":{"anyOf":[{"$ref":"#/components/schemas/JobErrorCode"},{"type":"null"}]},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["simulation_id","status","updated_at"],"title":"SimulationStatusItem","description":"Lightweight status payload for batch polling."},"SimulationSummary":{"properties":{"id":{"type":"string","title":"Id","description":"The unique identifier for the simulation."},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"Timestamp of when the simulation was created."},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At","description":"Timestamp of when the simulation was last updated."},"experiment_id":{"type":"string","title":"Experiment Id","description":"The ID of the experiment this simulation belongs to."},"parameterized_model_id":{"type":"string","title":"Parameterized Model Id","description":"The ID of the parameterized model used for this simulation."},"design_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Design Id","description":"The ID of the design for this simulation."},"job_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Job Id","description":"The ID of the job running this simulation."},"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status","description":"The current status of the job running this simulation."},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error","description":"Error message if the job failed."},"error_code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error Code","description":"Machine-readable error code."},"metrics":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Metrics","description":"Computed metrics from the simulation."},"storage_folder":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Storage Folder","description":"Folder path in storage containing simulation files (solution.parquet, time_series.parquet, steps.parquet)."},"organization_id":{"type":"string","title":"Organization Id","description":"Organization this simulation belongs to."},"experiment":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Experiment","description":"The experiment this simulation belongs to (id and template)."},"parameterized_model":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Parameterized Model","description":"The parameterized model (id and name only)."},"design":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Design","description":"The design used for this simulation."}},"type":"object","required":["id","created_at","experiment_id","parameterized_model_id","organization_id"],"title":"SimulationSummary","description":"Simulation summary model for study listings.\n\nUsed for listing simulations where full parameters and simulation_data\nare not needed. Optimized for table views with minimal payload."},"SimulationUsage":{"properties":{"usage":{"type":"number","title":"Usage","default":0},"limit":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Limit"}},"type":"object","title":"SimulationUsage","description":"Current simulation usage and its configured limit, in hours."},"Site":{"properties":{"name":{"type":"string","title":"Name","description":"Name of the site"},"location":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Location","description":"Physical location of the site (e.g. address or lab name)"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes","description":"Free-text notes about the site"},"id":{"type":"string","title":"Id","description":"Unique identifier for the site"},"organization_id":{"type":"string","title":"Organization Id","description":"Organization this site belongs to."},"created_by":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created By","description":"User ID of the user who created this site"},"created_by_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created By Email","description":"Email of the user who created this site"},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"Timestamp when the site was created"},"updated_at":{"type":"string","format":"date-time","title":"Updated At","description":"Timestamp when the site was last updated"},"cycler_ids":{"anyOf":[{"items":{"additionalProperties":true,"type":"object"},"type":"array"},{"type":"null"}],"title":"Cycler Ids","description":"List of cycler IDs belonging to this site"}},"type":"object","required":["name","id","organization_id","created_at","updated_at"],"title":"Site","description":"Model representing a site as returned by the API."},"SkillsBundleInfo":{"properties":{"version":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Version"}},"type":"object","title":"SkillsBundleInfo","description":"Metadata about the downloadable toolkit, for the download UI."},"SpatialProfile":{"properties":{"variable":{"type":"string","title":"Variable","description":"Evaluated PyBaMM variable name."},"coordinate_name":{"type":"string","title":"Coordinate Name","description":"Spatial coordinate used for the profile."},"coordinates":{"items":{"type":"number"},"type":"array","title":"Coordinates","description":"One-dimensional mesh coordinates in metres."},"times":{"items":{"type":"number"},"type":"array","title":"Times","description":"Stored simulation times in seconds."},"values":{"items":{"items":{"type":"number"},"type":"array"},"type":"array","title":"Values","description":"Field values indexed as values[time][position]."},"domains":{"items":{"type":"string"},"type":"array","title":"Domains","description":"Ordered PyBaMM domains along the coordinate."},"domain_boundaries":{"items":{"type":"number"},"type":"array","title":"Domain Boundaries","description":"Internal boundaries between adjacent domains in metres."}},"type":"object","required":["variable","coordinate_name","coordinates","times","values"],"title":"SpatialProfile","description":"A time-dependent scalar field on a one-dimensional PyBaMM mesh."},"StandardStep":{"properties":{"ends":{"items":{"anyOf":[{"$ref":"#/components/schemas/CustomEnd"},{"$ref":"#/components/schemas/DurationEnd"},{"$ref":"#/components/schemas/CapacityEnd"},{"$ref":"#/components/schemas/LoopNumberEnd"},{"$ref":"#/components/schemas/VariableEnd"},{"$ref":"#/components/schemas/AndEnd"},{"$ref":"#/components/schemas/OrEnd"}]},"type":"array","title":"Ends","description":"List of duration or end conditions"},"kind":{"type":"string","const":"standard","title":"Kind","description":"The type of this step","default":"standard"},"direction":{"anyOf":[{"type":"string","enum":["Charge","Discharge","Drive"]},{"type":"string"}],"title":"Direction","description":"The direction of this step"},"mode":{"$ref":"#/components/schemas/Mode","description":"The mode of this step"},"value":{"type":"string","title":"Value","description":"The value of this step"},"set_variable":{"items":{"$ref":"#/components/schemas/SetVariable"},"type":"array","title":"Set Variable","description":"Variables to set based on this step"},"note":{"type":"string","title":"Note","description":"An optional note for the step.","default":""},"resolution":{"anyOf":[{"$ref":"#/components/schemas/ResolutionConfig"},{"type":"null"}],"description":"Resolution for saving data for this step."}},"additionalProperties":false,"type":"object","required":["direction","mode","value"],"title":"StandardStep","description":"A step that represents a standard step."},"StepBlock":{"properties":{"ends":{"items":{"anyOf":[{"$ref":"#/components/schemas/CustomEnd"},{"$ref":"#/components/schemas/DurationEnd"},{"$ref":"#/components/schemas/CapacityEnd"},{"$ref":"#/components/schemas/LoopNumberEnd"},{"$ref":"#/components/schemas/VariableEnd"},{"$ref":"#/components/schemas/AndEnd"},{"$ref":"#/components/schemas/OrEnd"}]},"type":"array","title":"Ends","description":"A list of termination conditions that apply to all steps within the block. These are inherited by all child steps."},"kind":{"type":"string","const":"step_block","title":"Kind","description":"The type of this item","default":"step_block"},"name":{"type":"string","title":"Name","description":"Name of the block"},"steps":{"items":{"anyOf":[{"$ref":"#/components/schemas/StandardStep"},{"$ref":"#/components/schemas/RestStep"},{"$ref":"#/components/schemas/AmbientTemperatureStep"},{"$ref":"#/components/schemas/ControlStep"},{"$ref":"#/components/schemas/AuxiliaryStep"},{"$ref":"#/components/schemas/EISStep"},{"$ref":"#/components/schemas/SubroutineStep"},{"$ref":"#/components/schemas/DriveCycleStep"},{"$ref":"#/components/schemas/StepBlock"}]},"type":"array","title":"Steps","description":"List of steps or nested blocks"},"repeat":{"anyOf":[{"type":"integer"},{"type":"string"}],"title":"Repeat","description":"Number of times to repeat the block","default":1},"set_variable":{"items":{"$ref":"#/components/schemas/SetVariable"},"type":"array","title":"Set Variable","description":"Variables to set at the end of each block repetition."}},"additionalProperties":false,"type":"object","required":["name","steps"],"title":"StepBlock","description":"A named block of steps that can be repeated."},"StoppedMeasurementRow":{"properties":{"channel":{"$ref":"#/components/schemas/ChannelRef","description":"Channel the test ran on"},"measurement_id":{"type":"string","title":"Measurement Id","description":"Measurement ID"},"measurement_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Measurement Name","description":"Measurement name"},"cell_instance_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cell Instance Name","description":"Cell instance tested"},"cell_specification_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cell Specification Name","description":"Cell specification"},"protocol_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Protocol Name","description":"Protocol that was run"},"program_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Program Name","description":"Program the test belonged to"},"start_time":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Start Time","description":"When the test started"},"end_time":{"type":"string","format":"date-time","title":"End Time","description":"When the test finished"},"duration_hours":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Duration Hours","description":"Run duration in hours, when a start time is recorded"}},"type":"object","required":["channel","measurement_id","end_time"],"title":"StoppedMeasurementRow","description":"A measurement that finished within the report's lookback window."},"StoppingSoonSection":{"properties":{"channels":{"items":{"$ref":"#/components/schemas/UpcomingStopRow"},"type":"array","title":"Channels","description":"Expected releases, earliest first"},"planned_beyond_cap":{"type":"integer","title":"Planned Beyond Cap","description":"Scheduled releases in the window that the display cap excluded. Non-zero means the forecast is incomplete and the cap should rise.","default":0},"unassigned_count":{"type":"integer","title":"Unassigned Count","description":"Scheduled releases with no channel assigned yet, counted among the plans the query returned. Not listed because the forecast is per channel, but real work that will free a channel once assigned — so not a truncation.\n\nAlways 0 while the schema requires a channel on a scheduled plan; see the class docstring for why the field is kept.\n\nA lower bound when ``planned_beyond_cap`` is non-zero: plans past the cap were never inspected, so a channel-less one among them is counted there instead. Both figures stay individually true and both point at the same remedy — raise the cap — but do not read this as a window-wide total unless ``planned_beyond_cap`` is 0.","default":0}},"type":"object","title":"StoppingSoonSection","description":"Channels forecast to free up, and what the forecast could not place.\n\nA scheduled release can be missing from the list for two unrelated reasons,\ncounted separately because they need different responses and would be\nuninterpretable summed together: the list hit its cap\n(``planned_beyond_cap``), or the plan has no channel assigned yet\n(``unassigned_count``) and so cannot be attributed to one.\n\nRunning tests are bounded by the channel count and so are never capped.\n\n.. note::\n\n    ``unassigned_count`` is **always 0 under the current schema**.\n    ``planned_measurements_status_shape_check`` requires ``channel_id IS\n    NOT NULL`` for a ``scheduled`` plan, so the state it counts cannot be\n    stored. It is kept, rather than dropped as dead code, because the\n    constraint is the only thing preventing it: booking work before\n    assigning a channel is a coherent lab workflow, and were the status\n    shape relaxed to allow it the field would start reporting without any\n    other change. Read a non-zero value as a signal that the schema moved."},"Study":{"properties":{"name":{"type":"string","title":"Name","description":"The name of the study."},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"An optional description for the study."},"project_id":{"type":"string","title":"Project Id","description":"The ID of the project this study belongs to."},"organization_id":{"type":"string","title":"Organization Id","description":"Organization this study belongs to."},"created_by":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created By","description":"User ID of the creator."},"id":{"type":"string","title":"Id","description":"The unique identifier for the study."},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"Timestamp of when the study was created."},"updated_at":{"type":"string","format":"date-time","title":"Updated At","description":"Timestamp of when the study was last updated."}},"type":"object","required":["name","project_id","organization_id","id","created_at","updated_at"],"title":"Study"},"StudyCreatePayload":{"properties":{"name":{"type":"string","title":"Name","description":"The name of the study."},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"An optional description for the study."}},"type":"object","required":["name"],"title":"StudyCreatePayload"},"StudyMeasurementMapping":{"properties":{"study_id":{"type":"string","title":"Study Id","description":"ID of the study"},"measurement_id":{"type":"string","title":"Measurement Id","description":"ID of the measurement"},"organization_id":{"type":"string","title":"Organization Id","description":"Organization this mapping belongs to."},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"Timestamp of when the mapping was created"}},"type":"object","required":["study_id","measurement_id","organization_id","created_at"],"title":"StudyMeasurementMapping"},"StudySimulationMapping":{"properties":{"study_id":{"type":"string","title":"Study Id","description":"ID of the study"},"simulation_id":{"type":"string","title":"Simulation Id","description":"ID of the simulation"},"organization_id":{"type":"string","title":"Organization Id","description":"Organization this mapping belongs to."},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"Timestamp of when the mapping was created"}},"type":"object","required":["study_id","simulation_id","organization_id","created_at"],"title":"StudySimulationMapping"},"SubmitJobRequest":{"properties":{"job_type":{"$ref":"#/components/schemas/JobType","description":"Type of job to run"},"params":{"additionalProperties":true,"type":"object","title":"Params","description":"Parameters for the job"},"priority":{"type":"integer","maximum":10.0,"minimum":0.0,"title":"Priority","description":"Job priority (0-10)","default":0},"callback_url":{"anyOf":[{"type":"string","maxLength":2083,"minLength":1,"format":"uri"},{"type":"null"}],"title":"Callback Url","description":"Webhook URL for job completion notification"},"metadata":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Metadata"},"parent_job_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Parent Job Id","description":"Parent job ID for hierarchical job relationships"}},"type":"object","required":["job_type","params"],"title":"SubmitJobRequest","description":"Schema for submitting a new job"},"SubroutineStep":{"properties":{"kind":{"type":"string","const":"subroutine","title":"Kind","description":"The type of this step","default":"subroutine"},"name":{"type":"string","title":"Name","description":"Name of the subroutine to call"}},"additionalProperties":false,"type":"object","required":["name"],"title":"SubroutineStep","description":"A step that calls a reusable subroutine."},"ThermalChamber":{"properties":{"name":{"type":"string","title":"Name","description":"Name of the thermal chamber"},"manufacturer":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Manufacturer","description":"Manufacturer (make) of the chamber (e.g. Espec, Thermotron)"},"model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model","description":"Model (type) of the chamber (e.g. BTL-433)"},"serial_number":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Serial Number","description":"Manufacturer serial number of the chamber"},"min_temperature_c":{"type":"number","title":"Min Temperature C","description":"Lowest temperature the chamber is rated to hold, in degrees Celsius."},"max_temperature_c":{"type":"number","title":"Max Temperature C","description":"Highest temperature the chamber is rated to hold, in degrees Celsius."},"max_channels":{"anyOf":[{"type":"integer","exclusiveMinimum":0.0},{"type":"null"}],"title":"Max Channels","description":"How many channels fit in the chamber at once. None means capacity is not tracked and scheduling treats the chamber as unlimited."},"heating_rate_c_per_min":{"type":"number","exclusiveMinimum":0.0,"title":"Heating Rate C Per Min","description":"Rate the chamber raises temperature, in degrees Celsius per minute."},"cooling_rate_c_per_min":{"type":"number","exclusiveMinimum":0.0,"title":"Cooling Rate C Per Min","description":"Rate the chamber lowers temperature, in degrees Celsius per minute."},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes","description":"Free-text notes about the chamber"},"site_id":{"type":"string","title":"Site Id","description":"Foreign key to the parent site"},"project_id":{"type":"string","title":"Project Id","description":"Project that owns this thermal chamber"},"id":{"type":"string","title":"Id","description":"Unique identifier for the thermal chamber"},"organization_id":{"type":"string","title":"Organization Id","description":"Organization this thermal chamber belongs to."},"created_by":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created By","description":"User ID of the user who created this thermal chamber"},"created_by_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created By Email","description":"Email of the user who created this thermal chamber"},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"Timestamp when the thermal chamber was created"},"updated_at":{"type":"string","format":"date-time","title":"Updated At","description":"Timestamp when the thermal chamber was last updated"}},"type":"object","required":["name","min_temperature_c","max_temperature_c","heating_rate_c_per_min","cooling_rate_c_per_min","site_id","project_id","id","organization_id","created_at","updated_at"],"title":"ThermalChamber","description":"Model representing a thermal chamber as returned by the API."},"UnscheduledRequestRow":{"properties":{"planned_measurement_id":{"type":"string","title":"Planned Measurement Id","description":"Planned measurement ID"},"name":{"type":"string","title":"Name","description":"Planned measurement name"},"program_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Program Name","description":"Program this test belongs to"},"cell_specification_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cell Specification Name","description":"Cell specification to be tested"},"cell_instance_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cell Instance Name","description":"Cell instance assigned, if any"},"protocol_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Protocol Name","description":"Protocol to run"},"estimated_duration_seconds":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Estimated Duration Seconds","description":"Expected run duration, for capacity planning"},"requested_by_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Requested By Email","description":"Who asked for the test"},"requested_at":{"type":"string","format":"date-time","title":"Requested At","description":"When the request was raised"},"waiting_days":{"type":"number","title":"Waiting Days","description":"Days the request has been waiting for a slot"}},"type":"object","required":["planned_measurement_id","name","requested_at","waiting_days"],"title":"UnscheduledRequestRow","description":"A test someone asked for that has not been given a slot yet.\n\nThese have no ``planned_start_time``, so they cannot appear in a\ntime-ordered queue — which is exactly why they need their own section. An\nunscheduled request is invisible on the Lab wall and absent from the queue,\nso without this it is work that only the requester remembers."},"UnscheduledRequestsSection":{"properties":{"requests":{"items":{"$ref":"#/components/schemas/UnscheduledRequestRow"},"type":"array","title":"Requests","description":"Unscheduled requests, longest-waiting first"},"total":{"type":"integer","title":"Total","description":"All unscheduled requests, before the display limit. Greater than len(requests) when the list was capped."},"total_estimated_hours":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Total Estimated Hours","description":"Combined estimated duration of the listed requests, in hours — the channel-time the backlog will need. Null when no request carries an estimate."}},"type":"object","required":["total"],"title":"UnscheduledRequestsSection","description":"Requested tests with no slot, longest-waiting first.\n\nSorted oldest-request-first rather than newest: the point of the section is\nto surface what has been forgotten, and the request that has waited longest\nis the one most likely to have been."},"UpcomingStopRow":{"properties":{"channel":{"$ref":"#/components/schemas/ChannelRef","description":"Channel expected to free up"},"source":{"$ref":"#/components/schemas/UpcomingStopSource","description":"Whether this is a running test or a scheduled reservation"},"reference_id":{"type":"string","title":"Reference Id","description":"Measurement ID (running) or planned measurement ID (planned)"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"Measurement or plan name"},"cell_instance_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cell Instance Name","description":"Cell instance on test"},"cell_specification_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cell Specification Name","description":"Cell specification"},"protocol_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Protocol Name","description":"Protocol being run"},"program_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Program Name","description":"Program the test belongs to"},"expected_end_time":{"type":"string","format":"date-time","title":"Expected End Time","description":"Forecast time the channel is released"},"hours_until_end":{"type":"number","title":"Hours Until End","description":"Hours from the report time to expected_end_time"}},"type":"object","required":["channel","source","reference_id","expected_end_time","hours_until_end"],"title":"UpcomingStopRow","description":"A channel expected to free up within the report's forecast window."},"UpcomingStopSource":{"type":"string","enum":["running","planned"],"title":"UpcomingStopSource","description":"Where an upcoming channel release was forecast from."},"UpdateActiveOrganizationBody":{"properties":{"organization_id":{"type":"string","title":"Organization Id","description":"ID of the organization to set as the current user's active org."}},"type":"object","required":["organization_id"],"title":"UpdateActiveOrganizationBody"},"UpdateAnalysis":{"properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"New analysis name."},"analysis_type":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}],"title":"Analysis Type","description":"New analysis type (non-empty)."},"columns":{"anyOf":[{"items":{"$ref":"#/components/schemas/AnalysisColumnSpec"},"type":"array"},{"type":"null"}],"title":"Columns","description":"Revised column specs."},"metadata":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Metadata","description":"Replacement metadata dict."},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes","description":"New free-text description of how the analysis was performed."},"source_pipeline_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Pipeline Id","description":"New source pipeline FK (null to clear)."},"source_simple_pipeline_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Simple Pipeline Id","description":"New source simple-pipeline FK (null to clear)."},"source_analysis_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Analysis Id","description":"New source analysis FK (null to clear)."},"source_label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Label","description":"New provenance note."}},"type":"object","title":"UpdateAnalysis","description":"Partial update for an analysis. Does not replace the parquet."},"UpdateCellComponent":{"properties":{"component_type":{"anyOf":[{"$ref":"#/components/schemas/ComponentType"},{"type":"null"}],"description":"New component type"},"material_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Material Id","description":"New material ID"},"properties":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Properties","description":"New properties"}},"type":"object","title":"UpdateCellComponent","description":"Model for updating an existing cell component. All fields are optional."},"UpdateCellMeasurement":{"properties":{"name":{"anyOf":[{"type":"string","maxLength":255,"minLength":1},{"type":"null"}],"title":"Name"},"protocol":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Protocol","description":"Protocol information as a dict with: name (str), ambient_temperature_degc (float), definition (dict | str - UCP or other protocol format)"},"test_setup":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Test Setup","description":"Test setup: cycler, operator, lab, etc."},"end_time":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"End Time","description":"When the test finished (ISO 8601 with timezone). Set this to mark the measurement complete; leave null while it is still running."},"estimated_end_time":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Estimated End Time","description":"Forecast of when a still-running test will finish (ISO 8601 with timezone). Distinct from end_time. Null when no estimate exists."},"estimated_end_time_note":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Estimated End Time Note","description":"Free-text explanation of how estimated_end_time was derived."},"estimated_end_time_calculated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Estimated End Time Calculated At","description":"When estimated_end_time was last computed (ISO 8601, tz)."},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"},"channel_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Channel Id","description":"Optional ID of the channel this measurement ran on."},"protocol_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Protocol Id","description":"Optional ID of the experiment template (protocol) this measurement was run against."},"program_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Program Id","description":"Optional catalog program for this measurement."},"properties":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Properties","description":"Key-value measurements using Quantity format for numerics. Only for measurement_type='properties'. Example: {'thickness': {'value': 0.52, 'unit': 'mm'}}"}},"type":"object","title":"UpdateCellMeasurement","description":"Model for updating an existing cell measurement. All fields optional."},"UpdateCellSpecificationNested":{"properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"New name of the cell specification"},"form_factor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Form Factor","description":"New form factor"},"manufacturer":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Manufacturer","description":"New manufacturer"},"ratings":{"anyOf":[{"$ref":"#/components/schemas/Ratings"},{"type":"null"}],"description":"New electrical ratings"},"properties":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Properties","description":"New cell-level properties"},"source":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Source","description":"New source/provenance info"},"default_parameterized_model_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Default Parameterized Model Id","description":"Set the default parameterized model for this specification. Must reference one of this specification's own parameterized models. Pass null to clear the default."},"anode":{"anyOf":[{"$ref":"#/components/schemas/NestedComponentInput"},{"type":"null"}],"description":"Anode component with material"},"cathode":{"anyOf":[{"$ref":"#/components/schemas/NestedComponentInput"},{"type":"null"}],"description":"Cathode component with material"},"electrolyte":{"anyOf":[{"$ref":"#/components/schemas/NestedComponentInput"},{"type":"null"}],"description":"Electrolyte component with material"},"separator":{"anyOf":[{"$ref":"#/components/schemas/NestedComponentInput"},{"type":"null"}],"description":"Separator component with material"},"case":{"anyOf":[{"$ref":"#/components/schemas/NestedComponentInput"},{"type":"null"}],"description":"Case component with material"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes","description":"Notes"}},"type":"object","title":"UpdateCellSpecificationNested","description":"Model for updating a cell specification with nested component/material data.\n\nComponents and materials are upserted based on uniqueness constraints.\nAll fields are optional for partial updates."},"UpdateExperimentTemplateBody":{"properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"protocol_config":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Protocol Config"},"parameters_schema":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Parameters Schema"},"time_series_spec":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Time Series Spec"},"metrics_spec":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Metrics Spec"},"protocol_group_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Protocol Group Id"}},"type":"object","title":"UpdateExperimentTemplateBody","description":"Request body for updating an experiment template.\n\n``protocol_group_id`` is three-valued: omitted leaves the current group\nalone, an id moves the protocol into that group, and an explicit ``null``\nungroups it. The other fields keep their existing omitted-or-set semantics."},"UpdateMaterial":{"properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"New name of the material"},"definition":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Definition","description":"New material definition"},"manufacturer":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Manufacturer","description":"New manufacturer"},"product_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Product Id","description":"New product ID"}},"type":"object","title":"UpdateMaterial","description":"Model for updating an existing material. All fields are optional."},"UpdateMaterialPropertyDataset":{"properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"New dataset name"},"columns":{"anyOf":[{"items":{"$ref":"#/components/schemas/ColumnSpec"},"type":"array"},{"type":"null"}],"title":"Columns","description":"Revised column specs. Must cover exactly the columns in the original uploaded file (minus any unnamed index columns)."},"source_pipeline_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Pipeline Id","description":"New source pipeline FK (null to clear)."},"source_simple_pipeline_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Simple Pipeline Id","description":"New source simple-pipeline FK (null to clear)."},"source_analysis_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Analysis Id","description":"New source analysis FK (null to clear)."},"source_label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Label","description":"New provenance note."}},"type":"object","title":"UpdateMaterialPropertyDataset","description":"Partial update for a material property dataset.\n\nIf ``columns`` is provided, the stored parquet is rebuilt from the\npreserved original file using the new column specs."},"UpdateModel":{"properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"The new name of the model."},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"The new optional description for the model."},"pybamm_version":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Pybamm Version","description":"Updated PyBaMM version used for this model."},"chemistry":{"anyOf":[{"type":"string","enum":["lithium_ion","lithium_sulfur","ecm","generic"]},{"type":"null"}],"title":"Chemistry","description":"Updated model chemistry kind."},"simulation_settings":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Simulation Settings","description":"Updated persistent simulation kwargs (mesh + solver)."}},"type":"object","title":"UpdateModel","description":"Model for updating an existing model."},"UpdateOptimizationBody":{"properties":{"name":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}],"title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"}},"type":"object","title":"UpdateOptimizationBody","description":"Request body for updating an optimization's name and/or description."},"UpdateOptimizationTemplate":{"properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"The new name of the template."},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"The new optional description for the template."},"initial_form_data":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Initial Form Data","description":"Updated initial form data values."}},"type":"object","title":"UpdateOptimizationTemplate","description":"Model for updating an existing optimization template.\n\nValidates initial_form_data against DesignOptimizationDataFitConfigSchema\nwhen updating to ensure updated templates conform to the current schema."},"UpdateOrganization":{"properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"New name of the organization"},"usage_limit":{"anyOf":[{"additionalProperties":{"type":"integer"},"propertyNames":{"$ref":"#/components/schemas/UsageType"},"type":"object"},{"type":"string"},{"type":"null"}],"title":"Usage Limit","description":"Monthly usage limit"},"nav_config":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Nav Config","description":"Per-organization nav config: { '<key>': { 'show': bool, 'disabled': bool, 'badgeLabel': str | None, 'badgeTooltip': str | None } }"},"plotting_preferences":{"anyOf":[{"type":"string","maxLength":20000},{"type":"null"}],"title":"Plotting Preferences","description":"Free-text markdown describing how the agent should format plots for this organization. Injected into the agent's system prompt."}},"type":"object","title":"UpdateOrganization","description":"Model for updating an existing organization. All fields are optional."},"UpdateParameterizedModelBody":{"properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"simulation_settings":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Simulation Settings"}},"type":"object","title":"UpdateParameterizedModelBody","description":"Request body for updating a parameterized model (partial update)."},"UpdatePlannedMeasurement":{"properties":{"name":{"anyOf":[{"type":"string","maxLength":255,"minLength":1},{"type":"null"}],"title":"Name"},"status":{"anyOf":[{"$ref":"#/components/schemas/PlannedMeasurementStatus"},{"type":"null"}]},"cell_specification_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cell Specification Id"},"cell_instance_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cell Instance Id"},"channel_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Channel Id"},"set_temperature_c":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Set Temperature C"},"thermal_chamber_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Thermal Chamber Id"},"protocol_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Protocol Id"},"program_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Program Id"},"test_setup":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Test Setup"},"planned_start_time":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Planned Start Time"},"planned_end_time":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Planned End Time"},"estimated_duration_seconds":{"anyOf":[{"type":"integer","minimum":1.0},{"type":"null"}],"title":"Estimated Duration Seconds"},"setup_duration_seconds":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Setup Duration Seconds"},"teardown_duration_seconds":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Teardown Duration Seconds"},"started_measurement_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Started Measurement Id"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"}},"type":"object","title":"UpdatePlannedMeasurement","description":"Request model for patching a planned measurement.\n\n``set_temperature_c`` and ``thermal_chamber_id`` must end up either both\nset or both unset, but this model cannot check that alone: a body sending\nonly one of them has nothing to compare against, and the other may already be\nstored. The service validates the *merged* result against the stored row, and\nthe database CHECK backstops it — the same split used for the thermal\nchamber's min/max envelope."},"UpdateProjectMemberBody":{"properties":{"project_role_id":{"type":"string","title":"Project Role Id","description":"ID of the project role to assign."}},"type":"object","required":["project_role_id"],"title":"UpdateProjectMemberBody"},"UpdateProjectWebhook":{"properties":{"url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Url","description":"HTTPS destination URL."},"events":{"anyOf":[{"items":{"$ref":"#/components/schemas/WebhookEvent"},"type":"array","minItems":1},{"type":"null"}],"title":"Events","description":"Events that should trigger delivery."},"enabled":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Enabled","description":"Whether the webhook is active."}},"type":"object","title":"UpdateProjectWebhook","description":"Partial update for a project webhook."},"UpdateProtocolGroupBody":{"properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"New name for the group"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"New description"}},"type":"object","title":"UpdateProtocolGroupBody","description":"Request body for updating a protocol group.\n\nAll fields are optional (PATCH semantics). ``description`` is deliberately\ndistinguishable from \"absent\": passing ``null`` clears it, while omitting it\nleaves the stored value alone."},"UpdateRawData":{"properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"New label."},"source":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source","description":"New free-text provenance (where the raw file came from)."},"metadata":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Metadata","description":"Replacement metadata dict."}},"type":"object","title":"UpdateRawData","description":"Partial update for a raw-data record. Does not replace the file."},"UpdateSessionRequest":{"properties":{"title":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}],"title":"Title"},"sdk_session_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sdk Session Id"}},"type":"object","title":"UpdateSessionRequest","description":"Body for updating a chat session (partial update).\n\nAll fields optional. ``title`` renames the session; ``sdk_session_id`` is\nwritten by the client after agent-service emits it, so the agent's\nmulti-turn memory persists across idle eviction and restarts."},"UpdateSimulationBoard":{"properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"The new name of the board."},"config":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Config","description":"Updated visualization config."},"table_filter":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Table Filter","description":"Updated DataGrid filter model."},"column_visibility":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Column Visibility","description":"Updated DataGrid column visibility model."}},"type":"object","title":"UpdateSimulationBoard"},"UpdateStudy":{"properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"The new name of the study."},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"The new optional description for the study."}},"type":"object","title":"UpdateStudy"},"UpdateUserActiveRequest":{"properties":{"is_active":{"type":"boolean","title":"Is Active","description":"True to reactivate the user's membership, False to deactivate it. Deactivating blocks the user's access to this organization while preserving their membership and role."}},"type":"object","required":["is_active"],"title":"UpdateUserActiveRequest","description":"Request model to activate or deactivate a user's organization membership."},"UpdateUserOrgRoleRequest":{"properties":{"role_name":{"type":"string","title":"Role Name"}},"type":"object","required":["role_name"],"title":"UpdateUserOrgRoleRequest","description":"Request model to update a user's organization role by role name."},"UploadInfo":{"properties":{"filename":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Filename","description":"Original filename"},"signed_url":{"type":"string","title":"Signed Url","description":"Pre-signed URL for uploading"},"token":{"type":"string","title":"Token","description":"Upload token"},"path":{"type":"string","title":"Path","description":"Storage path for the file"},"multipart":{"anyOf":[{"$ref":"#/components/schemas/MultipartUploadInfo"},{"type":"null"}],"description":"Optional S3-multipart target for large files. Clients that do not understand this field fall back to PUTting the signed URL."}},"type":"object","required":["signed_url","token","path"],"title":"UploadInfo","description":"Signed URL info for a single file upload."},"UpsertProjectMemberBody":{"properties":{"user_id":{"type":"string","title":"User Id","description":"ID of the user whose project role to set."},"project_role_id":{"type":"string","title":"Project Role Id","description":"ID of the project role to assign."}},"type":"object","required":["user_id","project_role_id"],"title":"UpsertProjectMemberBody"},"UsageType":{"type":"string","enum":["simulation","compute"],"title":"UsageType"},"UserOrganizationRole":{"properties":{"user_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"User Id"},"users":{"anyOf":[{"$ref":"#/components/schemas/UsersResponse"},{"type":"null"}]},"organization_id":{"type":"string","title":"Organization Id"},"organization_role_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Organization Role Id"},"organization_roles":{"anyOf":[{"$ref":"#/components/schemas/OrganizationRole"},{"type":"null"}]},"deactivated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Deactivated At"}},"type":"object","required":["organization_id"],"title":"UserOrganizationRole"},"UserProjectRole":{"properties":{"user_id":{"type":"string","title":"User Id","description":"The ID of the user."},"project_id":{"type":"string","title":"Project Id","description":"The ID of the project."},"project_role_id":{"type":"string","title":"Project Role Id","description":"The ID of the project role."},"project_roles":{"anyOf":[{"$ref":"#/components/schemas/ProjectRole"},{"type":"null"}],"description":"The project roles for the user in the project."},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"Timestamp of when the user project role was created."},"updated_at":{"type":"string","format":"date-time","title":"Updated At","description":"Timestamp of when the user project role was last updated."}},"type":"object","required":["user_id","project_id","project_role_id","created_at","updated_at"],"title":"UserProjectRole"},"UserProjectRoleRef":{"properties":{"project_id":{"type":"string","title":"Project Id"},"project_role_id":{"type":"string","title":"Project Role Id"}},"type":"object","required":["project_id","project_role_id"],"title":"UserProjectRoleRef","description":"Raw project-membership reference: which role a user holds in a project.\n\nThe frontend filters project membership by ``project_id`` (project names can\ncollide or change), so this id-keyed array is exposed alongside the\nname-keyed ``project_roles`` dict on :class:`UserWithRoles`."},"UserWithRoles":{"properties":{"id":{"type":"string","title":"Id"},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email"},"active_org_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Active Org Id"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"is_super_admin":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Super Admin"},"organization_role":{"$ref":"#/components/schemas/OrganizationRole"},"project_roles":{"anyOf":[{"additionalProperties":{"$ref":"#/components/schemas/ProjectRole"},"type":"object"},{"type":"null"}],"title":"Project Roles"},"user_project_roles":{"anyOf":[{"items":{"$ref":"#/components/schemas/UserProjectRoleRef"},"type":"array"},{"type":"null"}],"title":"User Project Roles"}},"type":"object","required":["id","created_at","organization_role"],"title":"UserWithRoles"},"UsersResponse":{"properties":{"id":{"type":"string","title":"Id"},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email"}},"type":"object","required":["id"],"title":"UsersResponse"},"UtilizationComparison":{"properties":{"label":{"type":"string","title":"Label","description":"Human label for the lookback, e.g. '7 days'"},"hours_ago":{"type":"integer","title":"Hours Ago","description":"How far back this comparison reaches"},"previous_utilization_percent":{"type":"number","title":"Previous Utilization Percent","description":"Lab utilization at that instant"},"change_points":{"type":"number","title":"Change Points","description":"Change in lab utilization since then, in percentage points. Positive means the lab is busier now."}},"type":"object","required":["label","hours_ago","previous_utilization_percent","change_points"],"title":"UtilizationComparison","description":"Headline utilization now against one point in the past.\n\nSeveral of these together separate a blip from a trend: a lab can be down\nagainst yesterday while still well up on last month, and acting on the\nfirst number alone would be a mistake."},"UtilizationRow":{"properties":{"label":{"type":"string","title":"Label","description":"Name of the group (lab, site, or cycler)"},"total_channels":{"type":"integer","title":"Total Channels","description":"Channels in this group"},"occupied":{"type":"integer","title":"Occupied","description":"Channels running a freshly-updated test"},"stale":{"type":"integer","title":"Stale","description":"Channels whose test has stopped updating"},"free":{"type":"integer","title":"Free","description":"Channels available for work"},"out_of_commission":{"type":"integer","title":"Out Of Commission","description":"Channels out of service"},"utilization_percent":{"type":"number","title":"Utilization Percent","description":"(occupied + stale) / total_channels, as a percentage"},"utilization_of_available_percent":{"type":"number","title":"Utilization Of Available Percent","description":"(occupied + stale) / (total_channels - out_of_commission), as a percentage. 0 when every channel is out of commission."}},"type":"object","required":["label","total_channels","occupied","stale","free","out_of_commission","utilization_percent","utilization_of_available_percent"],"title":"UtilizationRow","description":"Channel-state counts and utilization for one grouping of channels.\n\n``utilization_percent`` matches the Lab wall's headline figure: occupied\nplus stale over *all* channels. ``utilization_of_available_percent``\nexcludes out-of-commission channels from the denominator, answering the\ndifferent question \"how hard is the usable capacity being used?\" — the two\ndiverge exactly when equipment is out of service, which is when the\ndistinction matters most."},"UtilizationSection":{"properties":{"lab":{"$ref":"#/components/schemas/UtilizationRow","description":"The project's equipment as a whole"},"comparisons":{"items":{"$ref":"#/components/schemas/UtilizationComparison"},"type":"array","title":"Comparisons","description":"Headline utilization against several points in the past, shortest lookback first. Empty when it could not be reconstructed."},"by_site":{"items":{"$ref":"#/components/schemas/UtilizationRow"},"type":"array","title":"By Site","description":"One row per site, ordered by name"},"by_program":{"items":{"$ref":"#/components/schemas/ProgramUtilizationRow"},"type":"array","title":"By Program","description":"One row per program in use, busiest first"}},"type":"object","required":["lab"],"title":"UtilizationSection","description":"Utilization for the whole project, by site and by program, vs yesterday.\n\nThe day-over-day comparison is reconstructed rather than stored: there is no\nutilization history table, so yesterday's figure is derived by replaying the\nmeasurement intervals that were open 24 hours ago. Its denominator is\n*today's* channel count, because the equipment tables carry no history\neither — so a lab that added channels overnight will see a small artificial\ndip. Over a single day that error is negligible; over months it would not\nbe, which is why nothing here reaches further back than the trend window."},"ValidateECMRequest":{"properties":{"measurement_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Measurement Id","description":"Held-out cell measurement to validate against."},"example_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Example Id","description":"Built-in example dataset id to validate against."},"start_step":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Start Step","description":"Optional inclusive start step (measurement only)."},"end_step":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"End Step","description":"Optional inclusive end step (measurement only)."},"initial_soc":{"anyOf":[{"type":"number","maximum":1.0,"minimum":0.0},{"type":"null"}],"title":"Initial Soc","description":"Known SOC (0–1) at the start of the held-out trace. When omitted it is recovered from the trace's first voltage via the fitted OCV(SOC) curve (assumes the trace starts near rest)."},"capacity":{"anyOf":[{"type":"number","exclusiveMinimum":0.0},{"type":"null"}],"title":"Capacity","description":"Cell capacity [Ah] for the SOC integration. Defaults to the fit/model capacity (the SOC reference the curves were fitted against); it is never re-estimated from the held-out trace."},"fit_results":{"anyOf":[{"$ref":"#/components/schemas/FitResultsData"},{"type":"null"}],"description":"In-memory fit results to re-simulate."},"parameterized_model_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Parameterized Model Id","description":"Saved ECM parameterized model to re-simulate."}},"type":"object","title":"ValidateECMRequest","description":"Request body for validating a fitted ECM against a held-out trace.\n\nProvide exactly one held-out data source (``measurement_id`` or\n``example_id``) and exactly one model source (``fit_results`` or\n``parameterized_model_id``). The model is re-simulated forward on the\nheld-out current — no fit and no pipeline — and compared to the held-out\nvoltage."},"ValidateECMResponse":{"properties":{"rmse_mV":{"type":"number","title":"Rmse Mv","description":"Root-mean-square voltage error [mV]."},"mae_mV":{"type":"number","title":"Mae Mv","description":"Mean absolute voltage error [mV]."},"max_mV":{"type":"number","title":"Max Mv","description":"Maximum absolute voltage error [mV]."},"num_rcs":{"type":"integer","title":"Num Rcs","description":"RC-pair count of the validated model."},"capacity_Ah":{"items":{"type":"number"},"type":"array","title":"Capacity Ah","description":"Capacity used for SOC integration [Ah] (single-element list)."},"initial_soc":{"type":"number","title":"Initial Soc","description":"Initial SOC used for the held-out trace."},"model_source":{"type":"string","title":"Model Source","description":"Where the validated model came from."},"time":{"items":{"type":"number"},"type":"array","title":"Time","description":"Downsampled time grid [s]."},"data_voltage":{"items":{"type":"number"},"type":"array","title":"Data Voltage","description":"Held-out measured voltage [V]."},"model_voltage":{"items":{"type":"number"},"type":"array","title":"Model Voltage","description":"Re-simulated model voltage [V]."},"residual_mV":{"items":{"type":"number"},"type":"array","title":"Residual Mv","description":"Model − data voltage residual [mV]."}},"type":"object","required":["rmse_mV","mae_mV","max_mV","num_rcs","capacity_Ah","initial_soc","model_source","time","data_voltage","model_voltage","residual_mV"],"title":"ValidateECMResponse","description":"Held-out validation result: error metrics + downsampled overlay traces."},"ValidateExpressionRequest":{"properties":{"expression":{"type":"string","title":"Expression"},"model_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model Id"},"config":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Config"},"existing_custom_variables":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Existing Custom Variables"},"new_var_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"New Var Name"}},"type":"object","required":["expression"],"title":"ValidateExpressionRequest","description":"Request body for validating a custom variable expression."},"ValidateModelConfigBody":{"properties":{"config":{"additionalProperties":true,"type":"object","title":"Config"}},"type":"object","required":["config"],"title":"ValidateModelConfigBody"},"ValidateParametersBody":{"properties":{"parameters":{"additionalProperties":true,"type":"object","title":"Parameters"},"model_id":{"type":"string","title":"Model Id"}},"type":"object","required":["parameters","model_id"],"title":"ValidateParametersBody"},"ValidateParametersResponse":{"properties":{"results":{"additionalProperties":{"$ref":"#/components/schemas/ParameterValidationResult"},"type":"object","title":"Results","description":"Validation results keyed by parameter name (e.g. 'Capacity [Ah]')."}},"type":"object","title":"ValidateParametersResponse","description":"Per-parameter validation results keyed by parameter name."},"ValidateProtocolRequest":{"properties":{"protocol":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"string"}],"title":"Protocol","description":"Protocol as a YAML-format dictionary with 'steps' and optional 'global', 'safety_limits', or a YAML string."}},"type":"object","required":["protocol"],"title":"ValidateProtocolRequest","description":"Request body for validating a protocol."},"ValidateRequest":{"properties":{"measurement_ids":{"items":{"type":"string"},"type":"array","minItems":1,"title":"Measurement Ids","description":"IDs of measurements to validate"},"parameterized_model_id":{"type":"string","title":"Parameterized Model Id","description":"ID of the parameterized model to simulate"},"cell_specification_id":{"type":"string","title":"Cell Specification Id","description":"ID of the cell specification (for model ownership verification)"},"start_step":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Start Step","description":"First step index to include (inclusive)"},"end_step":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"End Step","description":"Last step index to include (inclusive)"},"initial_voltage":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Initial Voltage","description":"Custom initial voltage [V]. Overrides auto-detection."},"initial_soc":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Initial Soc","description":"Custom initial SOC (0-1). Overrides voltage-based init."}},"type":"object","required":["measurement_ids","parameterized_model_id","cell_specification_id"],"title":"ValidateRequest","description":"Payload for the POST validate endpoint."},"ValidateResponse":{"properties":{"validations":{"items":{"$ref":"#/components/schemas/src__routes__study_validation__ValidationResult"},"type":"array","title":"Validations"},"errors":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Errors"},"skipped":{"items":{"type":"string"},"type":"array","title":"Skipped","description":"Measurement IDs skipped because an identical validation already exists"}},"type":"object","title":"ValidateResponse","description":"Aggregated result of a batch validation request."},"ValidationConfig":{"properties":{"objectives":{"additionalProperties":true,"type":"object","title":"Objectives"},"summary_stats":{"items":{},"type":"array","title":"Summary Stats"},"existing_parameters":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Existing Parameters"}},"type":"object","required":["objectives","summary_stats"],"title":"ValidationConfig"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"ValidationPair":{"properties":{"simulation_id":{"type":"string","title":"Simulation Id"},"measurement_id":{"type":"string","title":"Measurement Id"},"measurement_name":{"type":"string","title":"Measurement Name"},"model_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model Name"},"experiment_description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Experiment Description"},"job_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Job Status"},"job_error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Job Error"}},"type":"object","required":["simulation_id","measurement_id","measurement_name"],"title":"ValidationPair","description":"A simulation-measurement pair used for the validation report tab."},"ValidationPairMetrics":{"properties":{"simulation_id":{"type":"string","title":"Simulation Id"},"measurement_id":{"type":"string","title":"Measurement Id"},"rmse":{"type":"number","title":"Rmse"},"mae":{"type":"number","title":"Mae"},"max":{"type":"number","title":"Max"}},"type":"object","required":["simulation_id","measurement_id","rmse","mae","max"],"title":"ValidationPairMetrics","description":"One row of the report's summary table."},"ValidationPlotDataResponse":{"properties":{"traces":{"items":{"$ref":"#/components/schemas/ValidationPlotTrace"},"type":"array","title":"Traces"},"x_full_min":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"X Full Min"},"x_full_max":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"X Full Max"},"layout":{"additionalProperties":true,"type":"object","title":"Layout"}},"type":"object","required":["traces","layout"],"title":"ValidationPlotDataResponse","description":"Response from GET /pipelines/{validations|datafits}/{job_id}/plot_data.\n\nContains decimated trace data for a single validation plot, filtered to\nthe requested x-range and downsampled to at most ``max_points`` per trace."},"ValidationPlotTrace":{"properties":{"name":{"type":"string","title":"Name"},"x":{"items":{"anyOf":[{"type":"number"},{"type":"null"}]},"type":"array","title":"X"},"y":{"items":{"anyOf":[{"type":"number"},{"type":"null"}]},"type":"array","title":"Y"}},"type":"object","required":["name","x","y"],"title":"ValidationPlotTrace","description":"Single decimated trace returned by the validation plot data endpoint."},"ValidationResponse":{"properties":{"validation_results":{"additionalProperties":true,"type":"object","title":"Validation Results"},"summary_stats":{"additionalProperties":{"items":{},"type":"array"},"type":"object","title":"Summary Stats"},"validation_warning":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Validation Warning"}},"type":"object","required":["validation_results","summary_stats"],"title":"ValidationResponse"},"VariableEnd":{"properties":{"type":{"type":"string","const":"Variable","title":"Type","description":"Type of end condition","default":"Variable"},"expression":{"type":"string","title":"Expression","description":"Boolean expression using protocol variables, e.g., 'var1 > var2' or 'cycle_count >= 10'"},"goto":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Goto","description":"Step to transition to if condition is true at start"}},"additionalProperties":false,"type":"object","required":["expression"],"title":"VariableEnd","description":"A condition based on protocol variables, evaluated at step start.\n\nThis end condition is evaluated once when the step begins, using the current\nvalues of protocol variables. If the expression evaluates to True, the step\nis skipped immediately. If False, this condition is ignored for the step."},"WatchedMeasurementIds":{"properties":{"measurement_ids":{"items":{"type":"string"},"type":"array","title":"Measurement Ids","description":"IDs of live measurements the user is watching"}},"type":"object","title":"WatchedMeasurementIds","description":"The set of measurement IDs the requesting user is currently watching.\n\nReturned as a flat list of IDs (not full rows) because callers only need to\ntest membership — e.g. to mark channels as watched on the Lab wall."},"WebhookDelivery":{"properties":{"id":{"type":"string","title":"Id"},"webhook_id":{"type":"string","title":"Webhook Id"},"delivery_key":{"type":"string","title":"Delivery Key"},"resource_type":{"type":"string","title":"Resource Type"},"resource_id":{"type":"string","title":"Resource Id"},"event":{"type":"string","title":"Event"},"status":{"$ref":"#/components/schemas/WebhookDeliveryStatus"},"attempt_count":{"type":"integer","title":"Attempt Count"},"response_status":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Response Status"},"last_error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Error"},"payload":{"additionalProperties":true,"type":"object","title":"Payload"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","webhook_id","delivery_key","resource_type","resource_id","event","status","attempt_count","created_at","updated_at"],"title":"WebhookDelivery","description":"One delivery attempt / idempotency row."},"WebhookDeliveryStatus":{"type":"string","enum":["pending","success","failed"],"title":"WebhookDeliveryStatus","description":"Lifecycle states for a webhook delivery row."},"WebhookEvent":{"type":"string","enum":["pipeline.completed","pipeline.failed","pipeline.canceled","simple_pipeline.completed","simple_pipeline.failed","simple_pipeline.canceled","cell_specification.created","cell_specification.updated","cell_specification.deleted","cell_instance.created","cell_instance.updated","cell_instance.deleted","cell_measurement.created","cell_measurement.updated","cell_measurement.deleted"],"title":"WebhookEvent","description":"Supported webhook events (namespaced by resource family).\n\nAdd new members as more resources gain webhook fire points. Validation\nlives in the API layer; the DB does not hard-code the allowed set."},"WebhookTestResponse":{"properties":{"task_id":{"type":"string","title":"Task Id"},"message":{"type":"string","title":"Message","default":"Test webhook delivery enqueued."}},"type":"object","required":["task_id"],"title":"WebhookTestResponse","description":"Response after enqueueing a test ping."},"_HasMeasurementsResponse":{"properties":{"has_measurements":{"type":"boolean","title":"Has Measurements"}},"type":"object","required":["has_measurements"],"title":"_HasMeasurementsResponse"},"_SerializeIonworksModelBody":{"properties":{"name":{"type":"string","title":"Name","description":"Ionworks model class name to build and serialize, e.g. 'ECM', 'LumpedSPMR', 'MSMRFullCellModel', 'GITTModel'. Must be one of the names returned under 'ionworks_models' by GET /discovery/pybamm_models."},"options":{"additionalProperties":true,"type":"object","title":"Options","description":"Options dict to pass to the model constructor."}},"type":"object","required":["name"],"title":"_SerializeIonworksModelBody","description":"Body for ``POST /discovery/ionworks_models/serialize``."},"_ValidatePybammModelBody":{"properties":{"pybamm_model":{"type":"string","title":"Pybamm Model","description":"Class name to instantiate, e.g. 'DFN', 'SPM', 'ECM'. Must be one of the names returned by GET /discovery/pybamm_models."},"module":{"type":"string","title":"Module","description":"PyBaMM submodule the class lives under ('lithium_ion' or 'lead_acid'). Ignored for ionworks-specific models.","default":"lithium_ion"},"options":{"additionalProperties":true,"type":"object","title":"Options","description":"Options dict to pass to the model constructor."}},"type":"object","required":["pybamm_model"],"title":"_ValidatePybammModelBody","description":"Body for ``POST /discovery/pybamm_models/validate``."},"src__routes__study_validation__ValidationResult":{"properties":{"measurement_id":{"type":"string","title":"Measurement Id"},"simulation_id":{"type":"string","title":"Simulation Id"},"job_id":{"type":"string","title":"Job Id"}},"type":"object","required":["measurement_id","simulation_id","job_id"],"title":"ValidationResult","description":"A single successful validation submission."},"src__services__variable_validation_service__ValidationResult":{"properties":{"valid":{"type":"boolean","title":"Valid"},"json_value":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Json Value"},"referenced_variables":{"items":{"$ref":"#/components/schemas/ReferencedVariable"},"type":"array","title":"Referenced Variables","default":[]},"parameters":{"items":{"$ref":"#/components/schemas/ReferencedParameter"},"type":"array","title":"Parameters","default":[]},"errors":{"items":{"type":"string"},"type":"array","title":"Errors","default":[]},"warnings":{"items":{"type":"string"},"type":"array","title":"Warnings","default":[]}},"type":"object","required":["valid"],"title":"ValidationResult","description":"Result of validating a custom variable expression."}}}}