{"openapi":"3.1.0","info":{"title":"Labric API","version":"1.0.0"},"paths":{"/api/v1/files":{"get":{"operationId":"files_list","summary":"List files","description":"List source data files available for parser development.\n\nReturns the org's uploaded files, newest first.\nFilter by instrument_id, comma-separated file extensions (e.g. \"csv,txt\"),\nor a substring of the file name. Use the file-content tool to inspect a\nfile's raw contents.\n\nRequires an API key with the `read` scope.","tags":["Files"],"parameters":[{"name":"instrument_id","in":"query","required":false,"schema":{"type":"string","default":""}},{"name":"extensions","in":"query","required":false,"schema":{"type":"string","default":""}},{"name":"query","in":"query","required":false,"schema":{"type":"string","default":""}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":50}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/FileInfoSchema"}}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"422":{"description":"Unprocessable Content","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationErrorSchema"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}}},"security":[{"ApiKeyAuth":[]}]},"post":{"operationId":"files_upload","summary":"Upload a small file in one request","description":"Upload a file in one multipart/form-data request.\n\nRequest bodies over 4.5 MB are rejected at the platform edge before they\nreach this route. For larger files, create an upload URL and PUT the bytes\nto it instead; the SDK's files.upload() does that for files of any size.\nThe [Upload files](https://docs.labric.co/upload-files) guide walks\nthrough both flows.\n\nAt least one of job_execution_id and instrument_id is required: pass a\njob_execution_id for an artifact of a job running in a sandbox, which also\nrecords provenance linking the file to that execution, and pass an\ninstrument_id for data captured off-platform by an instrument the Sync app\ncannot reach, which attaches the file to that instrument so instrument\ntriggers and parsers pick it up.\n\nRequires an API key with the `write` scope.","tags":["Files"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FileUploadSchema"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"422":{"description":"Unprocessable Content","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationErrorSchema"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}}},"requestBody":{"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary"},"job_execution_id":{"type":["string","null"],"format":"uuid"},"instrument_id":{"type":["string","null"],"format":"uuid"}},"required":["file"]}}}},"security":[{"ApiKeyAuth":[]}]}},"/api/v1/files/upload-url":{"post":{"operationId":"files_create_upload_url","summary":"Create an upload URL","description":"Start an upload that sends the file bytes straight to storage.\n\nCreates the file record and returns a signed URL that accepts the bytes as\nthe body of an HTTP PUT for the next 15 minutes. Send exactly the returned\nheaders on the PUT and no Authorization header, then confirm the upload to\nmake the file visible. The URL only creates the object, never replaces one,\nand refuses bodies over 500 MB. Asking again for an instrument path whose\nupload was never confirmed returns a fresh URL for the same file, so a\nfailed PUT can be retried. The SDK's files.upload() runs all three steps;\nthe [Upload files](https://docs.labric.co/upload-files) guide shows them\nwith curl.\n\nAt least one of job_execution_id and instrument_id is required: pass a\njob_execution_id for an artifact of a job running in a sandbox, which also\nrecords provenance linking the file to that execution, and pass an\ninstrument_id for data captured off-platform by an instrument the Sync app\ncannot reach, which attaches the file to that instrument so instrument\ntriggers and parsers pick it up.\n\nRequires an API key with the `write` scope.","tags":["Files"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FileUploadUrlSchema"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"422":{"description":"Unprocessable Content","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationErrorSchema"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FileUploadUrlRequestSchema"}}}},"security":[{"ApiKeyAuth":[]}]}},"/api/v1/files/{file_id}/confirm-upload":{"post":{"operationId":"files_confirm_upload","summary":"Confirm an upload","description":"Finish an upload after the PUT to its upload URL has succeeded.\n\nRecords the stored file's size and checksum, makes the file visible in\nlistings, and notifies triggers and parsers. Files over 500 MB and native\nexecutables are discarded with a 400, as the one-request upload rejects\nthem. Confirming a file that is already confirmed returns its record again\nwithout notifying anyone twice. The\n[Upload files](https://docs.labric.co/upload-files) guide shows the full\nsequence.\n\nRequires an API key with the `write` scope.","tags":["Files"],"parameters":[{"name":"file_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FileUploadSchema"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"422":{"description":"Unprocessable Content","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationErrorSchema"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}}},"security":[{"ApiKeyAuth":[]}]}},"/api/v1/files/{file_id}/content":{"get":{"operationId":"files_get_content","summary":"Get a file's content","description":"Fetch a source file's content for inspecting raw instrument output.\n\nReturns a presigned download URL plus a best-effort UTF-8 text preview of\nthe start of the file. Large files return a URL only (no inline preview);\nfetch the full bytes via the URL when needed.\n\nRequires an API key with the `read` scope.","tags":["Files"],"parameters":[{"name":"file_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FileContentSchema"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"422":{"description":"Unprocessable Content","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationErrorSchema"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}}},"security":[{"ApiKeyAuth":[]}]}},"/api/v1/agent/runs":{"post":{"operationId":"agent_run_stream","summary":"Run","description":"Run the Labric data-analysis agent and return its final answer\nalongside the tool calls it made. With stream=true the response is\ninstead a stream of server-sent AgentRunEvent events, closing after a\nterminal `result` event that carries the same summary, or an `error`\nevent if the run fails; prefer streaming for long analyses. Pass chat_id\nto continue a saved conversation, or save=true to save the run as a new\nchat visible in the web UI; if saving fails, the answer is still returned\nbut its chat_id is null. Tools that change data are available to the run\nonly when the API key holds the write scope.\n\nRequires an API key with the `read` scope.","tags":["Agent"],"responses":{"200":{"description":"","content":{"text/event-stream":{"schema":{"$ref":"#/components/schemas/AgentRunEvent"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"422":{"description":"Unprocessable Content","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationErrorSchema"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"502":{"description":"Bad Gateway","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}}},"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"prompt":{"type":"string"},"model":{"type":["string","null"]},"chat_id":{"type":["string","null"],"format":"uuid"},"save":{"type":"boolean","default":false},"stream":{"type":"boolean","enum":[true]}},"required":["prompt","stream"]}}}},"security":[{"ApiKeyAuth":[]}]}},"/api/v1/jobs":{"get":{"operationId":"jobs_list","summary":"List jobs","description":"List the organization's jobs, newest first.\n\nPass name to look up one job, since job names are unique within an\norganization; the list is then empty or holds that job. Archived jobs\nare left out unless archived is true.\n\nRequires an API key with the `read` scope.","tags":["Jobs"],"parameters":[{"name":"name","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"archived","in":"query","required":false,"schema":{"type":"boolean","default":false}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ToolsJobSchema"}}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"422":{"description":"Unprocessable Content","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationErrorSchema"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}}},"security":[{"ApiKeyAuth":[]}]},"post":{"operationId":"jobs_create","summary":"Create a job","description":"Create a job that runs a Python script on the platform.\n\nThe code becomes the job's script; declare its dependencies inline in a\nPEP 723 `# /// script` block. The job then appears on the platform, where\nit can be run and its executions reviewed. To change an existing job's\nname, description, or code, use update_job instead.\n\nRequires an API key with the `write` scope.","tags":["Jobs"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToolsJobSchema"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"422":{"description":"Unprocessable Content","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationErrorSchema"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToolsCreateJobSchema"}}}},"security":[{"ApiKeyAuth":[]}]}},"/api/v1/jobs/{job_id}":{"patch":{"operationId":"jobs_update","summary":"Update a job","description":"Change a job's name, description, code, trigger, or parameters, or\narchive it.\n\nOnly the fields passed are changed. To change part of the script, pass\nedits: exact replacements of text in the current script. Pass code only to\nreplace the whole script. New code is stored as a new version of the job's\nscript, so earlier executions keep the version they ran. To create a job,\nuse create_job instead.\n\nRequires an API key with the `write` scope.","tags":["Jobs"],"parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToolsJobSchema"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"422":{"description":"Unprocessable Content","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationErrorSchema"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToolsUpdateJobSchema"}}}},"security":[{"ApiKeyAuth":[]}]}},"/api/v1/job-executions":{"post":{"operationId":"jobs_start","summary":"Start a job execution","description":"Open a job execution for a script running outside the platform.\n\nPass the returned job_execution_id to the write and upload-file tools so\neverything one script run produces is attributed to a single execution and\ncan be inspected or reverted as a unit. Pass job_id to run under an\nexisting job, job_name to run under a job of that name (created if\nmissing), or neither to run under the default off-platform job.\n\nThe execution is marked running immediately. Close it as completed or\nfailed when the script finishes. Pass timeout_minutes to have the platform\nfail it after that long if the script has not closed it, so a crashed\nscript does not leave it running forever.\n\nRequires an API key with the `write` scope.","tags":["Jobs"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OffPlatformJobExecutionSchema"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"422":{"description":"Unprocessable Content","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationErrorSchema"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}}},"requestBody":{"content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/StartJobExecutionSchema"},{"type":"null"}]}}}},"security":[{"ApiKeyAuth":[]}]}},"/api/v1/job-executions/{execution_id}":{"patch":{"operationId":"jobs_close","summary":"Close a job execution","description":"Close a job execution as completed or failed.\n\nCall this when an off-platform script finishes. Either status is final:\nre-sending the same status is a no-op, and changing it is rejected. Only\nexecutions opened by the start tool are accepted; the platform records\nevery other execution's status itself.\n\nRequires an API key with the `write` scope.","tags":["Jobs"],"parameters":[{"name":"execution_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OffPlatformJobExecutionSchema"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"422":{"description":"Unprocessable Content","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationErrorSchema"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateJobExecutionStatusSchema"}}}},"security":[{"ApiKeyAuth":[]}]}},"/api/v1/job-executions/{execution_id}/revert":{"post":{"operationId":"jobs_revert","summary":"Revert a job execution","description":"Revert a job execution by deleting the rows it created.\n\nDeletes the execution's created objects and their linked raw rows in one\ntransaction, for undoing a test write that failed validation. Updates and\ndeletes cannot be reversed and are reported as warnings in the result.\n\nRequires an API key with the `write` scope.","tags":["Jobs"],"parameters":[{"name":"execution_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RevertResultSchema"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"422":{"description":"Unprocessable Content","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationErrorSchema"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}}},"security":[{"ApiKeyAuth":[]}]}},"/api/v1/tools/write":{"post":{"operationId":"tools_write","summary":"Write","description":"Write records to a table.\n\nDeprecated: use write_data (client.data.write), which writes several\ntables and raw series in one transaction.\n\nInserts or updates records in the specified target table. Supports batch\ninserts, upserts with match columns, default value functions (DATETIME_NOW,\nUUID4), and optional dry-run validation. A job execution is created\nautomatically if one is not provided.\n\nCore tables are writable only if they appear in the write allowlist. Tables\nthat describe the organization itself, such as organizationmember, are\nread-only and can only be reached through the read tool.\n\nRequires an API key with the `write` scope.","tags":["Tools"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","additionalProperties":{"description":"Any type"}}}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"422":{"description":"Unprocessable Content","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationErrorSchema"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}}},"deprecated":true,"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LabricWriteSchema"}}}},"security":[{"ApiKeyAuth":[]}]}},"/api/v1/tools/read":{"post":{"operationId":"tools_read","summary":"Read","description":"Read records from a table.\n\nReturns records from the specified table matching the given filters.\nUse 'single' mode to retrieve exactly one record, or 'multiple' mode\nto retrieve all matching records.\n\nRequires an API key with the `read` scope.","tags":["Tools"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","additionalProperties":{"description":"Any type"}}}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"422":{"description":"Unprocessable Content","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationErrorSchema"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LabricReadSchema"}}}},"security":[{"ApiKeyAuth":[]}]}},"/api/v1/tools/query":{"post":{"operationId":"tools_execute_sql","summary":"Execute Sql","description":"Execute a read-only SQL query.\n\nRuns the query against the organization's read replica, so it cannot\nmutate data. Only SELECT statements are accepted. Supports positional\nparameters: write %s placeholders in the query and pass the values in\norder in the params list. Named :param placeholders belong to saved\ndataset queries and are not accepted here. Use the schema tool to discover tables\nfirst, and reference each column by its sql_column_name — foreign keys\ncarry an _id suffix in SQL (e.g. a 'sample' reference is the 'sample_id'\ncolumn).\n\nRequires an API key with the `read` scope.","tags":["Tools"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QueryResult"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"422":{"description":"Unprocessable Content","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationErrorSchema"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"503":{"description":"Service Unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QueryBody"}}}},"security":[{"ApiKeyAuth":[]}]}},"/api/v1/tools/schema":{"get":{"operationId":"tools_get_schema","summary":"Get Schema","description":"Describe the organization's data schema.\n\nReturns every table the agent can target, including its semantic category\n(e.g. raw vs. curated), description, and full column definitions with types,\nnullability, uniqueness, and foreign-key targets. Each column carries two\nnames: 'name' is what the read and write tools accept, and 'sql_column_name'\nis the physical column for SQL queries (a column holding another row's key\ncarries an _id suffix).\nThe org's own tables are followed by the platform tables (core_experiment,\ncore_instrument, and similar) that SQL queries can join against, ending with\ncore_user, which holds the org's members; those have no id or semantic\ncategory. This is the map a parser writes into: use it to plan which tables\nto populate and how rows link.\n\nRequires an API key with the `read` scope.","tags":["Tools"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/QueryableTableSchema"}}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"422":{"description":"Unprocessable Content","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationErrorSchema"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}}},"security":[{"ApiKeyAuth":[]}]}},"/api/v1/tools/batch-write":{"post":{"operationId":"tools_batch_write","summary":"Batch Write","description":"Write records to multiple tables in a single transaction.\n\nDeprecated: use write_data (client.data.write), which also writes raw\nseries and supports update and delete.\n\nSupports:\n- Batch references: Use \"_ref\" to label records, \"@refname\" to reference them\n- Natural keys: Use human-readable values for foreign keys (e.g., recipe name)\n- Automatic FK ordering: Tables are inserted in dependency order\n- Upsert mode: Update existing records based on match columns\n- Dry run: Validate without committing changes\n\nCommitted writes are recorded against a job execution (created automatically\nif not supplied) and the job_execution_id is returned, so the write can be\nreverted as a unit.\n\nRequires an API key with the `write` scope.","tags":["Tools"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchWriteResponse"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"422":{"description":"Unprocessable Content","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationErrorSchema"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}}},"deprecated":true,"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchWriteRequest"}}}},"security":[{"ApiKeyAuth":[]}]}},"/api/v1/images/{file_id}/annotations":{"post":{"operationId":"images_annotate","summary":"Save annotations on an image","description":"Save masks on an image as annotations, one per entry.\n\nEach entry is a binary mask PNG (white-on-transparent, base64-encoded)\nfor a label; labels are created on first use. Saving is additive, so\na label can accumulate several masks on the same image. The annotations\na segmentation model returns from predict can be passed straight through;\neach names the file it was predicted for, and one for a different file\nrejects the request. Leave is_human_vetted false for automated saves:\nthe mask editor flags unvetted masks for review, and only vetted masks\nfeed training. The file must be a processed image. All-or-nothing: one\nbad entry rejects the whole request.\n\nRequires an API key with the `write` scope.","tags":["Images"],"parameters":[{"name":"file_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AnnotationSchema"}}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"422":{"description":"Unprocessable Content","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationErrorSchema"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"502":{"description":"Bad Gateway","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SaveAnnotationsSchema"}}}},"security":[{"ApiKeyAuth":[]}]}},"/api/v1/data/write":{"post":{"operationId":"data_write","summary":"Write data","description":"Insert, upsert, update, or delete rows across tables, and write raw\nseries, in a single transaction.\n\nTable writes target the organization's tables from get_schema or core\ntables such as experiment, operation, and carrier. They are applied in\nrequest order, so one request can create a sample and then the\nmeasurements that reference it: label a row with \"_ref\": \"s1\" and point at\nit with \"@s1\" from a foreign key column of any later row. A foreign key may\nalso be a lookup object such as {\"name\": \"S-001\"} that matches exactly one\nrow that existed before the request. Primary keys are generated when\nomitted where the table allows it, and are always returned in input\norder.\n\nA series holds the points of one parent row in a raw table as one list per\ncolumn. Writing a series replaces the parent's existing series in that\ntable, so repeating a write is safe. The server fills in the primary key,\nthe parent foreign key, and an integer order column.\n\nEvery row, series, and lookup is checked before anything is written, and\nall of those problems are reported together in errors. Each has a path\nnaming its place in the request, such as tables[1].rows[0].sample. Keys\nfor upsert, update, and delete are matched as each table write is\napplied, and any failure rolls back the whole request. The write is recorded under a job execution,\ncreated if none is given. Reverting that execution deletes the rows it\ncreated along with their series; updates, deletes, and series written to\nexisting parents are not undone.\n\nThe request body must be under 4.5 MB, which the row and series value\nlimits keep most requests within.\n\nA write that waits too long on rows other writes are changing fails with\n429 and changes nothing. Retry it after the Retry-After header's delay.\n\nRequires an API key with the `write` scope.","tags":["Data"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WriteDataResponse"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WriteDataErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"422":{"description":"Unprocessable Content","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationErrorSchema"}}}},"429":{"description":"Too Many Requests","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WriteDataRequest"}}}},"security":[{"ApiKeyAuth":[]}]}},"/api/v1/notifications":{"post":{"operationId":"notifications_send","summary":"Send a notification","description":"Send a message to your own inbox, and to your email if you have enabled\nemail for the Message category in your notification preferences. Sends are\ncapped per hour and per organization per day; a 429 response carries a\nRetry-After header. Messages sent with an API key are attributed to it, so\nthe recipient can tell where they came from.\n\nRequires an API key with the `write` scope.","tags":["Notifications"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentNotificationSchema"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"422":{"description":"Unprocessable Content","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationErrorSchema"}}}},"429":{"description":"Too Many Requests","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendNotificationSchema"}}}},"security":[{"ApiKeyAuth":[]}]}},"/api/v1/ml-models/predict":{"post":{"operationId":"models_predict","summary":"Run predictions","description":"Run predictions with a trained ML model.\n\nIdentify the model by ml_model_id, or by ml_model_name (the name of a\nnon-archived model). Each row in data maps the model's feature columns to\nvalues; list_ml_models shows the columns each model expects. Returns one\nprediction per input row, plus per-class probabilities for classifiers.\n\nRequires an API key with the `read` scope.","tags":["Models"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PredictResponseSchema"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"422":{"description":"Unprocessable Content","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationErrorSchema"}}}},"429":{"description":"Too Many Requests","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"502":{"description":"Bad Gateway","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToolsPredictRequestSchema"}}}},"security":[{"ApiKeyAuth":[]}]}},"/api/v1/ml-models/{ml_model_id}":{"get":{"operationId":"models_get","summary":"Get a model","description":"Get one ML model's training status and results.\n\nRequires an API key with the `read` scope.","tags":["Models"],"parameters":[{"name":"ml_model_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToolsMLModelDetailSchema"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"422":{"description":"Unprocessable Content","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationErrorSchema"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}}},"security":[{"ApiKeyAuth":[]}]}},"/api/v1/ml-models":{"get":{"operationId":"models_list","summary":"List models","description":"List the organization's ML models, newest first.\n\nReturns every non-archived model with its task type, target and feature\ncolumns, training status, and evaluation metrics. The status describes the\nnewest version. A model serves predictions only while currently_active is\ntrue; a retrain stops it serving until the new version is ready.\n\nRequires an API key with the `read` scope.","tags":["Models"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ToolsMLModelDetailSchema"}}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"422":{"description":"Unprocessable Content","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationErrorSchema"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}}},"security":[{"ApiKeyAuth":[]}]},"post":{"operationId":"models_train","summary":"Train a model","description":"Train a new ML model on a dataset, or retrain an existing one.\n\nTo train a new model, pass name and omit ml_model_id. To retrain, pass\nml_model_id and omit name; the model keeps its name and gains a new\nversion. dataset_id and target_column are always required, and every\ncolumn must exist in the dataset. Training runs in the background;\ncheck its progress with get_ml_model.\n\nRequires an API key with the `write` scope.","tags":["Models"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToolsMLModelDetailSchema"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"422":{"description":"Unprocessable Content","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationErrorSchema"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"503":{"description":"Service Unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TrainMLModelSchema"}}}},"security":[{"ApiKeyAuth":[]}]}},"/api/v1/ml-models/{ml_model_id}/cancel-training":{"post":{"operationId":"models_cancel_training","summary":"Cancel training","description":"Cancel the model's in-flight training runs.\n\nOverlapping retrains can leave several versions pending or training at\nonce, so the cancel is model-wide: every in-flight version is marked\n'cancelled' and its cloud training jobs are stopped. Fails when no\ntraining is pending or running.\n\nRequires an API key with the `write` scope.","tags":["Models"],"parameters":[{"name":"ml_model_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToolsMLModelDetailSchema"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}},"422":{"description":"Unprocessable Content","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationErrorSchema"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSchema"}}}}},"security":[{"ApiKeyAuth":[]}]}}},"tags":[{"name":"Files"},{"name":"Agent"},{"name":"Jobs"},{"name":"Tools"},{"name":"Images"},{"name":"Data"},{"name":"Notifications"},{"name":"Models"}],"servers":[{"url":"https://platform.labric.co","description":"https://platform.labric.co"}],"components":{"schemas":{"FileInfoSchema":{"type":"object","properties":{"file_id":{"type":"string","description":"The file's ID, for use with the file-content tool."},"original_path":{"type":["string","null"],"description":"Original file name / path."},"source_type":{"type":["string","null"],"description":"Where the file came from (e.g. instrument sync, manual upload)."},"source_instrument_id":{"type":["string","null"],"description":"ID of the instrument that produced the file, if any."},"size_kilobytes":{"type":["integer","null"],"description":"File size in kilobytes."},"crc32c_hash":{"type":["string","null"],"description":"Content hash, useful as an idempotency key for parsed rows."},"file_created_at":{"type":["string","null"],"format":"date-time","description":"When the source file was created, if known."}},"required":["file_id","original_path","source_type","source_instrument_id","size_kilobytes","crc32c_hash","file_created_at"],"description":"A source data file available for parser development.","title":"FileInfoSchema"},"ErrorSchema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"],"title":"ErrorSchema"},"ValidationErrorSchema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","additionalProperties":{"description":"Any type"}}}},"required":["detail"],"description":"Shape of Ninja's built-in 422 request-validation error response.","title":"ValidationErrorSchema"},"FileUploadSchema":{"type":"object","properties":{"file_id":{"type":"string","description":"The ID of the uploaded file."},"file_name":{"type":"string","description":"The original file name."},"size_kilobytes":{"type":["integer","null"],"description":"File size in kilobytes."}},"required":["file_id","file_name","size_kilobytes"],"title":"FileUploadSchema"},"FileUploadUrlRequestSchema":{"type":"object","properties":{"file_name":{"type":"string","description":"The file name to record, e.g. results.csv."},"content_type":{"type":["string","null"],"description":"MIME type of the file. Defaults to application/octet-stream, which is also substituted for types a browser could render as a page."},"job_execution_id":{"type":["string","null"],"format":"uuid","description":"The job execution producing the file, for a job artifact."},"instrument_id":{"type":["string","null"],"format":"uuid","description":"The instrument that captured the file, for off-platform data."}},"required":["file_name"],"title":"FileUploadUrlRequestSchema"},"FileUploadUrlSchema":{"type":"object","properties":{"file_id":{"type":"string","description":"The ID of the file record awaiting its bytes."},"upload_url":{"type":"string","description":"Signed Google Cloud Storage URL. Send the file bytes as the body of an HTTP PUT to this URL with no Authorization header."},"headers":{"type":"object","additionalProperties":{"type":"string"},"description":"Headers the PUT must carry exactly as given; the URL is signed for them. They set the Content-Type, let the object be created but not replaced, and cap the body at the platform's file size limit."},"expires_at":{"type":"string","description":"When the upload URL stops working, as an ISO 8601 timestamp."}},"required":["file_id","upload_url","headers","expires_at"],"title":"FileUploadUrlSchema"},"FileContentSchema":{"type":"object","properties":{"file_id":{"type":"string"},"file_name":{"type":["string","null"]},"size_kilobytes":{"type":["integer","null"]},"download_url":{"type":"string","description":"Presigned URL to fetch the full file (e.g. via the SDK)."},"text_preview":{"type":["string","null"],"description":"Best-effort UTF-8 decode of the start of the file, or null if skipped."},"preview_truncated":{"type":"boolean","description":"True if the file is longer than the inlined preview."},"preview_skipped_reason":{"type":["string","null"],"description":"Why an inline preview was not returned (e.g. file too large)."}},"required":["file_id","file_name","size_kilobytes","download_url","text_preview","preview_truncated","preview_skipped_reason"],"description":"The content of a source data file, for inspecting raw instrument output.","title":"FileContentSchema"},"AgentToolCall":{"type":"object","properties":{"tool_call_id":{"type":"string"},"tool_name":{"type":"string"},"input":{"description":"Any type"},"output":{"description":"Any type"}},"required":["tool_call_id","tool_name"],"title":"AgentToolCall"},"AgentRunUsage":{"type":"object","properties":{"input_tokens":{"type":["integer","null"]},"output_tokens":{"type":["integer","null"]},"total_tokens":{"type":["integer","null"]}},"title":"AgentRunUsage"},"AgentRunResponse":{"type":"object","properties":{"output":{"type":"string"},"model":{"type":"string"},"tool_calls":{"type":"array","items":{"$ref":"#/components/schemas/AgentToolCall"}},"usage":{"$ref":"#/components/schemas/AgentRunUsage"},"chat_id":{"type":["string","null"],"format":"uuid"}},"required":["output","model","tool_calls","usage"],"description":"Final result of an agent run: the assistant's answer, the tool calls it\nmade, token usage, and the chat id when the run was persisted.","title":"AgentRunResponse"},"AgentRunEvent":{"type":"object","properties":{"type":{"type":"string"},"delta":{"type":["string","null"]},"tool_call_id":{"type":["string","null"]},"tool_name":{"type":["string","null"]},"input":{"description":"Any type"},"output":{"description":"Any type"},"result":{"oneOf":[{"$ref":"#/components/schemas/AgentRunResponse"},{"type":"null"}]},"error":{"type":["string","null"]}},"required":["type"],"description":"One streamed agent run event, discriminated by `type`:\n\n- `text_delta` / `reasoning_delta`: incremental assistant text in `delta`\n- `tool_call`: the agent invoked a tool (`tool_call_id`, `tool_name`, `input`)\n- `tool_result`: a tool finished (`tool_call_id`, `tool_name`, `output`)\n- `result`: terminal event carrying the full run summary in `result`\n- `error`: the run or its persistence failed; details in `error`","title":"AgentRunEvent"},"JobTriggerSchema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"category":{"type":"string"},"instrument_id":{"type":["string","null"],"format":"uuid"},"conditions":{"type":["object","null"],"additionalProperties":{"description":"Any type"}}},"required":["id","category"],"title":"JobTriggerSchema"},"ParameterDefinitionSchemaWidgetType":{"type":"string","enum":["combobox","date","slider","text","region"],"title":"ParameterDefinitionSchemaWidgetType"},"ParameterDefinitionSchema":{"type":"object","properties":{"widget_type":{"$ref":"#/components/schemas/ParameterDefinitionSchemaWidgetType"},"parameter_name":{"type":"string"},"label":{"type":["string","null"]},"model_source":{"type":["string","null"]},"min":{"type":["number","null"],"format":"double"},"max":{"type":["number","null"],"format":"double"},"step":{"type":["number","null"],"format":"double"},"file_id":{"type":["string","null"]},"file_id_parameter":{"type":["string","null"]},"required":{"type":"boolean","default":true,"description":"True requires a value on manual runs. A default satisfies the requirement."}},"required":["widget_type","parameter_name"],"title":"ParameterDefinitionSchema"},"ToolsJobSchema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Pass this as job_id to the job execution tools."},"name":{"type":"string"},"description":{"type":["string","null"]},"archived":{"type":"boolean"},"trigger":{"oneOf":[{"$ref":"#/components/schemas/JobTriggerSchema"},{"type":"null"}]},"parameter_definitions":{"type":["array","null"],"items":{"$ref":"#/components/schemas/ParameterDefinitionSchema"}}},"required":["id","name","archived"],"description":"A job that runs a script on the platform.","title":"ToolsJobSchema"},"JobTriggerCategory":{"type":"string","enum":["file_uploaded","job_completed","schedule"],"title":"JobTriggerCategory"},"ToolsCreateJobSchema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200,"description":"Name of the job. Unique within the organization."},"description":{"type":["string","null"],"description":"What the job does."},"code":{"type":"string","description":"Python source of the script the job runs. Declare dependencies inline in a PEP 723 `# /// script` block."},"trigger_enabled":{"type":"boolean","default":false,"description":"True runs the job automatically when its trigger fires."},"trigger_category":{"oneOf":[{"$ref":"#/components/schemas/JobTriggerCategory"},{"type":"null"}],"description":"What runs the job automatically: file_uploaded runs it on each uploaded file that matches the conditions; job_completed runs it on the output files of another job's executions; schedule configures a recurring cron schedule. Required when trigger_enabled is true."},"trigger_instrument_id":{"type":["string","null"],"format":"uuid","description":"Restricts a file_uploaded trigger to files from this instrument."},"trigger_conditions":{"type":["object","null"],"additionalProperties":{"description":"Any type"},"description":"Filters on the triggering event. For file_uploaded, any of file_name_pattern, file_extensions (list of strings starting with '.'; files with no extension always pass), source_type, min_size_kb, and max_size_kb (both inclusive). file_name_pattern is a case-sensitive glob in which * matches any characters, including folder separators, ? matches one character, and '/' and '\\' each match either separator. It must match the file's whole path or the part after any separator, so '*.csv' and 'run_*.csv' match files in any folder. For job_completed, source_job_id (required) and statuses (list drawn from completed and failed; defaults to completed). For schedule, cron (required five-field expression: minute, hour, day of month, month, day of week) and timezone (required IANA timezone, e.g. America/Los_Angeles). Cron supports numbers, month and weekday names, *, ranges, lists, and steps."},"parameter_definitions":{"type":["array","null"],"items":{"$ref":"#/components/schemas/ParameterDefinitionSchema"},"description":"Inputs the script reads at run time. Each is rendered as a form control when the job is run on the platform."}},"required":["name","code"],"description":"A job to create from a Python script.","title":"ToolsCreateJobSchema"},"ScriptEditSchema":{"type":"object","properties":{"old_string":{"type":"string","minLength":1,"description":"Text to replace. Must match the script exactly once, including whitespace and indentation; include surrounding lines to make it unique."},"new_string":{"type":"string","description":"Replacement text. An empty string deletes the match."}},"required":["old_string","new_string"],"description":"One exact text replacement in a job's script.","title":"ScriptEditSchema"},"ToolsUpdateJobSchema":{"type":"object","properties":{"name":{"type":["string","null"],"minLength":1,"maxLength":200,"description":"New name for the job."},"description":{"type":["string","null"],"description":"New description for the job. Pass an empty string to clear it."},"code":{"type":["string","null"],"description":"Complete new Python source for the job's script, stored as a new script version. Declare dependencies inline in a PEP 723 `# /// script` block. For a change to part of the script, pass edits instead."},"edits":{"type":["array","null"],"items":{"$ref":"#/components/schemas/ScriptEditSchema"},"description":"Replacements applied in order to the job's current script, stored as a new script version. Each old_string is matched against the script as left by the edits before it. If any edit fails to match, no change is saved. Cannot be combined with code."},"archived":{"type":["boolean","null"],"description":"True archives the job, hiding it from the active job list; false restores it."},"trigger_enabled":{"type":["boolean","null"],"description":"True creates or replaces the job's trigger from the trigger fields; false removes it."},"trigger_category":{"oneOf":[{"$ref":"#/components/schemas/JobTriggerCategory"},{"type":"null"}],"description":"What runs the job automatically: file_uploaded runs it on each uploaded file that matches the conditions; job_completed runs it on the output files of another job's executions; schedule configures a recurring cron schedule. Required when trigger_enabled is true."},"trigger_instrument_id":{"type":["string","null"],"format":"uuid","description":"Restricts a file_uploaded trigger to files from this instrument."},"trigger_conditions":{"type":["object","null"],"additionalProperties":{"description":"Any type"},"description":"Filters on the triggering event. For file_uploaded, any of file_name_pattern, file_extensions (list of strings starting with '.'; files with no extension always pass), source_type, min_size_kb, and max_size_kb (both inclusive). file_name_pattern is a case-sensitive glob in which * matches any characters, including folder separators, ? matches one character, and '/' and '\\' each match either separator. It must match the file's whole path or the part after any separator, so '*.csv' and 'run_*.csv' match files in any folder. For job_completed, source_job_id (required) and statuses (list drawn from completed and failed; defaults to completed). For schedule, cron (required five-field expression: minute, hour, day of month, month, day of week) and timezone (required IANA timezone, e.g. America/Los_Angeles). Cron supports numbers, month and weekday names, *, ranges, lists, and steps."},"parameter_definitions":{"type":["array","null"],"items":{"$ref":"#/components/schemas/ParameterDefinitionSchema"},"description":"Inputs the script reads at run time. Each is rendered as a form control when the job is run on the platform."}},"description":"Changes to apply to a job. Fields left unset keep their current value.","title":"ToolsUpdateJobSchema"},"StartJobExecutionSchema":{"type":"object","properties":{"job_id":{"type":["string","null"],"format":"uuid","description":"ID of an existing job to run under. Omit to use job_name instead."},"job_name":{"type":["string","null"],"description":"Name of the job to run under, created if it does not exist yet. Ignored when job_id is given. Defaults to 'Off-Platform Manual Job'."},"timeout_minutes":{"type":["integer","null"],"minimum":1,"maximum":43200,"description":"Fail the execution if the script has not closed it within this many minutes (at most 43200, i.e. 30 days), so a crashed script does not leave it running forever. Omit to let it run until closed."}},"description":"Open a job execution for a script running outside the platform.","title":"StartJobExecutionSchema"},"OffPlatformJobExecutionSchema":{"type":"object","properties":{"job_execution_id":{"type":"string","format":"uuid","description":"Pass this as job_execution_id to the write and upload-file tools."},"job_id":{"type":"string","format":"uuid","description":"ID of the job the execution belongs to."},"job_name":{"type":"string","description":"Name of the job the execution belongs to."},"status":{"type":["string","null"],"description":"The execution's current status."},"started_at":{"type":["string","null"],"format":"date-time","description":"When the execution started."},"completed_at":{"type":["string","null"],"format":"date-time","description":"When the execution ended, or null while it is still running."}},"required":["job_execution_id","job_id","job_name","status","started_at","completed_at"],"description":"A job execution to attribute off-platform writes and uploads to.","title":"OffPlatformJobExecutionSchema"},"UpdateJobExecutionStatusSchemaStatus":{"type":"string","enum":["completed","failed"],"description":"How the run ended. Either status is final: the execution cannot change status afterwards.","title":"UpdateJobExecutionStatusSchemaStatus"},"UpdateJobExecutionStatusSchema":{"type":"object","properties":{"status":{"$ref":"#/components/schemas/UpdateJobExecutionStatusSchemaStatus","description":"How the run ended. Either status is final: the execution cannot change status afterwards."}},"required":["status"],"description":"Close a job execution by recording how the run ended.","title":"UpdateJobExecutionStatusSchema"},"RevertResultSchema":{"type":"object","properties":{"deleted_count":{"type":"integer"},"raws_deleted_count":{"type":"integer"},"skipped_count":{"type":"integer"},"warnings":{"type":"array","items":{"type":"string"}}},"required":["deleted_count","raws_deleted_count","skipped_count","warnings"],"title":"RevertResultSchema"},"LabricWriteSchemaTargetType":{"type":"string","enum":["table","core-table"],"description":"The type of target. Currently 'table' or 'core-table'. Only some core tables are writable. Tables describing the organization, such as organizationmember, are read-only.","title":"LabricWriteSchemaTargetType"},"LabricWriteSchemaOnMatch":{"type":"string","enum":["overwrite","fill_missing"],"default":"fill_missing","description":"How a matched record takes the provided columns in create-or-update mode. 'fill_missing' only sets columns that are currently null. 'overwrite' replaces them, and a provided null clears the column. Columns absent from the record and default functions never overwrite an existing value.","title":"LabricWriteSchemaOnMatch"},"LabricWriteSchema":{"type":"object","properties":{"target_name":{"type":"string","description":"The name of the table to write to."},"target_type":{"$ref":"#/components/schemas/LabricWriteSchemaTargetType","description":"The type of target. Currently 'table' or 'core-table'. Only some core tables are writable. Tables describing the organization, such as organizationmember, are read-only."},"data":{"type":"array","items":{"type":"object","additionalProperties":{"description":"Any type"}},"description":"List of record dicts to write."},"batch_insert_ok":{"type":"boolean","default":false,"description":"If True, allow batch insert of multiple records."},"params_to_match_for_update":{"type":["array","null"],"items":{"type":"string"},"description":"Column names to match on when updating existing records."},"on_match":{"$ref":"#/components/schemas/LabricWriteSchemaOnMatch","default":"fill_missing","description":"How a matched record takes the provided columns in create-or-update mode. 'fill_missing' only sets columns that are currently null. 'overwrite' replaces them, and a provided null clears the column. Columns absent from the record and default functions never overwrite an existing value."},"defaults":{"type":["object","null"],"additionalProperties":{"type":"string"},"description":"Map of field names to default function names (e.g. 'DATETIME_NOW', 'UUID4')."},"mode":{"type":"string","description":"Write mode (e.g. 'create', 'create-or-update')."},"job_execution_id":{"type":["string","null"],"format":"uuid","description":"Existing job execution ID to associate with this write. If omitted, a new one is created."},"job_name":{"type":["string","null"],"description":"Name for the auto-created job. Defaults to 'Off-Platform Manual Job'."},"collect_output":{"type":"boolean","default":false,"description":"If True, return the written records in the response."},"dry_run":{"type":"boolean","default":false,"description":"If True, resolve references, check table and column validity, and return the execution plan without committing changes."}},"required":["target_name","target_type","data","mode"],"description":"Write records to a target table or core-table.","title":"LabricWriteSchema"},"LabricReadSchemaTargetType":{"type":"string","enum":["table","core-table"],"description":"The type of target. Either 'table' or 'core-table'.","title":"LabricReadSchemaTargetType"},"LabricReadSchemaMode":{"type":"string","enum":["single","multiple"],"default":"single","description":"'single' returns exactly one record and throws an error if more than one matching record exists, 'multiple' returns all matches.","title":"LabricReadSchemaMode"},"LabricReadSchema":{"type":"object","properties":{"target_name":{"type":"string","description":"The name of the table to read from."},"target_type":{"$ref":"#/components/schemas/LabricReadSchemaTargetType","description":"The type of target. Either 'table' or 'core-table'."},"filters":{"type":"object","additionalProperties":{"description":"Any type"},"description":"Key-value filters to apply to the query. Omit to match all records. A key may follow a foreign key onto another readable table, as in instrument_type__name; tables the read tool does not return are not traversable."},"mode":{"$ref":"#/components/schemas/LabricReadSchemaMode","default":"single","description":"'single' returns exactly one record and throws an error if more than one matching record exists, 'multiple' returns all matches."}},"required":["target_name","target_type"],"description":"Read records from a target table.","title":"LabricReadSchema"},"QueryBody":{"type":"object","properties":{"query":{"type":"string"},"params":{"type":["array","null"],"items":{"description":"Any type"}}},"required":["query"],"title":"QueryBody"},"QueryResult":{"type":"object","properties":{"columns":{"type":"array","items":{"type":"string"}},"data":{"type":"array","items":{"type":"array","items":{"description":"Any type"}}}},"required":["columns","data"],"title":"QueryResult"},"QueryableColumnSchema":{"type":"object","properties":{"id":{"type":["integer","null"]},"name":{"type":"string"},"sql_column_name":{"type":"string"},"description":{"type":["string","null"]},"data_type":{"type":"string"},"is_primary_key":{"type":"boolean"},"is_foreign_key":{"type":"boolean"},"is_nullable":{"type":"boolean"},"is_unique":{"type":"boolean"},"foreign_key_table_name":{"type":["string","null"]}},"required":["name","sql_column_name","data_type","is_primary_key","is_foreign_key","is_nullable","is_unique"],"description":"A column of a queryable table. Platform table columns have no id.","title":"QueryableColumnSchema"},"QueryableTableSchema":{"type":"object","properties":{"id":{"type":["integer","null"]},"name":{"type":"string"},"description":{"type":["string","null"]},"semantic_category":{"type":["string","null"]},"columns":{"type":"array","items":{"$ref":"#/components/schemas/QueryableColumnSchema"}}},"required":["name","columns"],"description":"A table SQL queries can target. Platform tables have no id.","title":"QueryableTableSchema"},"BatchWriteOptionsMode":{"type":"string","enum":["insert","upsert"],"default":"insert","description":"'insert' creates new records, and fails if the record already exists. 'upsert' creates or updates based on match_on columns.","title":"BatchWriteOptionsMode"},"BatchWriteOptions":{"type":"object","properties":{"mode":{"$ref":"#/components/schemas/BatchWriteOptionsMode","default":"insert","description":"'insert' creates new records, and fails if the record already exists. 'upsert' creates or updates based on match_on columns."},"match_on":{"type":["object","null"],"additionalProperties":{"type":"array","items":{"type":"string"}},"description":"For upsert: which columns to match on, per table. Example: {\"production_run\": [\"run_code\"]}"},"dry_run":{"type":"boolean","default":false,"description":"If True, validate without committing changes."},"return_records":{"type":"boolean","default":false,"description":"If True, include created/updated records in response."},"job_execution_id":{"type":["string","null"],"format":"uuid","description":"Existing job execution to attach this write to. If omitted, a new one is created and returned, so the write can be reverted as a unit."},"job_name":{"type":["string","null"],"description":"Name for the auto-created job. Defaults to 'Off-Platform Manual Job'."}},"description":"Options for controlling batch write behavior.","title":"BatchWriteOptions"},"BatchWriteRequest":{"type":"object","properties":{"tables":{"type":"object","additionalProperties":{"type":"array","items":{"type":"object","additionalProperties":{"description":"Any type"}}},"description":"Map of table_name to list of records to insert."},"options":{"oneOf":[{"$ref":"#/components/schemas/BatchWriteOptions"},{"type":"null"}],"description":"Optional write options (mode, match_on, dry_run, return_records)."}},"required":["tables"],"description":"Request body for batch write.\n\nExample:\n    {\n        \"tables\": {\n            \"production_run\": [\n                {\"_ref\": \"run1\", \"run_code\": \"RUN-001\", \"recipe\": \"croissant\"},\n            ],\n            \"baked_item\": [\n                {\"production_run\": \"@run1\", \"item_number\": 1, \"weight\": 65.2},\n            ]\n        },\n        \"options\": {\"mode\": \"upsert\", \"match_on\": {\"production_run\": [\"run_code\"]}}\n    }","title":"BatchWriteRequest"},"TableSummary":{"type":"object","properties":{"created":{"type":"integer","default":0,"description":"Number of records created."},"updated":{"type":"integer","default":0,"description":"Number of records updated."}},"description":"Summary of operations for a single table.","title":"TableSummary"},"WritePlan":{"type":"object","properties":{"insert_order":{"type":"array","items":{"type":"string"},"description":"Order in which tables will be inserted."},"operations":{"type":"array","items":{"type":"object","additionalProperties":{"description":"Any type"}},"description":"Operations that would be performed."}},"required":["insert_order","operations"],"description":"Execution plan returned by dry_run.","title":"WritePlan"},"BatchWriteResponse":{"type":"object","properties":{"success":{"type":"boolean","default":true,"description":"Whether the operation succeeded."},"job_execution_id":{"type":["string","null"],"description":"The job execution this write was recorded under. Use it to revert the write as a unit. Null for dry runs."},"summary":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/TableSummary"},"description":"Count of created/updated records per table."},"refs":{"type":"object","additionalProperties":{"type":"string"},"description":"Map of _ref labels to their created IDs."},"records":{"type":["object","null"],"additionalProperties":{"type":"array","items":{"type":"object","additionalProperties":{"description":"Any type"}}},"description":"Created/updated records (only if return_records=True)."},"plan":{"oneOf":[{"$ref":"#/components/schemas/WritePlan"},{"type":"null"}],"description":"Execution plan (only if dry_run=True)."}},"required":["summary","refs"],"description":"Response from a successful batch write.","title":"BatchWriteResponse"},"SaveAnnotationSchema":{"type":"object","properties":{"mask":{"type":"string","minLength":1,"maxLength":2000000},"width":{"type":["integer","null"]},"height":{"type":["integer","null"]},"label":{"type":"string","pattern":"^[a-zA-Z0-9_-]+$","minLength":1,"maxLength":255},"is_human_vetted":{"type":"boolean","default":false},"file_id":{"type":["string","null"],"format":"uuid"}},"required":["mask","label"],"description":"A new mask for a label on an image: the update payload plus the\nidentity fields an existing row already has.","title":"SaveAnnotationSchema"},"SaveAnnotationsSchema":{"type":"object","properties":{"annotations":{"type":"array","items":{"$ref":"#/components/schemas/SaveAnnotationSchema"}}},"required":["annotations"],"description":"A batch of masks to save on one image in a single request, so a job\nthat predicted an image's worth of masks doesn't pay a round trip per\nmask. Entries carry their own label and vetted state.","title":"SaveAnnotationsSchema"},"ActivityActorSchema":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"image_url":{"type":["string","null"]}},"required":["id","name","image_url"],"title":"ActivityActorSchema"},"AnnotationSchema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"label":{"type":"string"},"mask_url":{"type":["string","null"]},"width":{"type":["integer","null"]},"height":{"type":["integer","null"]},"is_human_vetted":{"type":"boolean","default":false},"foreground_fraction":{"type":["number","null"],"format":"double"},"user":{"oneOf":[{"$ref":"#/components/schemas/ActivityActorSchema"},{"type":"null"}]}},"required":["id","label"],"title":"AnnotationSchema"},"TableWriteMode":{"type":"string","enum":["insert","upsert","update","delete"],"default":"insert","description":"'insert' creates every row. 'upsert' updates rows that match on key and creates the rest. 'update' and 'delete' require every row to match on key.","title":"TableWriteMode"},"TableWriteOnMatch":{"type":"string","enum":["overwrite","fill_missing"],"default":"overwrite","description":"How a matched row takes the provided columns. 'overwrite' replaces them. 'fill_missing' only sets columns that are currently null. Columns absent from the row are never changed.","title":"TableWriteOnMatch"},"TableWrite":{"type":"object","properties":{"table":{"type":"string","description":"Table to write to: one of the organization's tables, or a core table such as experiment, operation, or carrier."},"rows":{"type":"array","items":{"type":"object","additionalProperties":{"description":"Any type"}},"description":"Rows keyed by column name. A row may carry '_ref': '<label>' so later rows and series can point at it with '@<label>'. A foreign key value may be an id, an '@<label>' reference to an earlier row, or a lookup object such as {'name': 'S-001'} that matches exactly one row that existed before the request. Omit a string 'id' primary key to have it generated."},"mode":{"$ref":"#/components/schemas/TableWriteMode","default":"insert","description":"'insert' creates every row. 'upsert' updates rows that match on key and creates the rest. 'update' and 'delete' require every row to match on key."},"key":{"type":["array","null"],"items":{"type":"string"},"description":"Columns that identify an existing row for upsert, update, and delete. Defaults to the primary key."},"cascade":{"type":"boolean","default":false,"description":"For delete: also delete rows of other tables that reference the deleted rows. Rows of raw tables are always deleted with the row they belong to. Without cascade, a delete that other rows reference is rejected."},"on_match":{"$ref":"#/components/schemas/TableWriteOnMatch","default":"overwrite","description":"How a matched row takes the provided columns. 'overwrite' replaces them. 'fill_missing' only sets columns that are currently null. Columns absent from the row are never changed."}},"required":["table","rows"],"description":"Rows to write to one table.","title":"TableWrite"},"SeriesWriteParent":{"oneOf":[{"type":"string"},{"type":"object","additionalProperties":{"description":"Any type"}}],"description":"Parent row that owns the series: an id, an '@<label>' reference to a row written in this request, or a lookup object such as {'name': 'M-001'}.","title":"SeriesWriteParent"},"SeriesWrite":{"type":"object","properties":{"table":{"type":"string","description":"Raw table that holds the series."},"parent":{"$ref":"#/components/schemas/SeriesWriteParent","description":"Parent row that owns the series: an id, an '@<label>' reference to a row written in this request, or a lookup object such as {'name': 'M-001'}."},"parent_column":{"type":["string","null"],"description":"Foreign key column that points at the parent. Required only when the raw table has more than one foreign key."},"columns":{"type":"object","additionalProperties":{"type":"array","items":{"description":"Any type"}},"description":"Values keyed by column name. Every list holds one value per point and all lists have the same length. An integer 'order' column is filled with each point's position unless given here."}},"required":["table","parent","columns"],"description":"A raw data series belonging to one parent row, given column by column.","title":"SeriesWrite"},"WriteDataRequest":{"type":"object","properties":{"tables":{"type":"array","items":{"$ref":"#/components/schemas/TableWrite"},"description":"Table writes, applied in order. A row may reference only rows that appear before it. At most 10,000 rows across all table writes."},"series":{"type":"array","items":{"$ref":"#/components/schemas/SeriesWrite"},"description":"Raw series, applied after the table writes. Writing a series replaces any series the parent already has in that table. At most 250,000 values across all columns of all series."},"job_execution_id":{"type":["string","null"],"format":"uuid","description":"Job execution to record this write under. When omitted, one is created and returned so the write can be reverted as a unit."},"job_name":{"type":["string","null"],"description":"Name of the job an auto-created execution belongs to. Defaults to 'Off-Platform Manual Job'."},"dry_run":{"type":"boolean","default":false,"description":"Run every validation and constraint check, then roll back instead of committing."},"return_rows":{"type":"boolean","default":false,"description":"Include the written rows of each table write in its result."}},"description":"Rows and raw series to write in a single transaction.","title":"WriteDataRequest"},"TableWriteResult":{"type":"object","properties":{"table":{"type":"string"},"created":{"type":"integer"},"updated":{"type":"integer"},"deleted":{"type":"integer"},"cascade_deleted":{"type":"object","additionalProperties":{"type":"integer"},"description":"Rows deleted because they referenced a deleted row, by table. A dry run reports them without deleting."},"ids":{"type":"array","items":{"type":"string"},"description":"Primary key of each input row, in input order."},"rows":{"type":["array","null"],"items":{"type":"object","additionalProperties":{"description":"Any type"}},"description":"Written rows in input order, when return_rows is set."}},"required":["table","created","updated","deleted","ids"],"title":"TableWriteResult"},"SeriesWriteResult":{"type":"object","properties":{"table":{"type":"string"},"parent_id":{"type":"string"},"points_written":{"type":"integer"},"points_replaced":{"type":"integer","description":"Points of the parent's previous series that were removed."}},"required":["table","parent_id","points_written","points_replaced"],"title":"SeriesWriteResult"},"WriteDataResponse":{"type":"object","properties":{"job_execution_id":{"type":["string","null"],"description":"Job execution the write was recorded under, for reverting it. Null on a dry run."},"tables":{"type":"array","items":{"$ref":"#/components/schemas/TableWriteResult"},"description":"One result per table write, in request order."},"series":{"type":"array","items":{"$ref":"#/components/schemas/SeriesWriteResult"},"description":"One result per series, in request order."},"refs":{"type":"object","additionalProperties":{"type":"string"},"description":"Primary key of every row labeled with _ref."}},"required":["job_execution_id","tables","series","refs"],"title":"WriteDataResponse"},"WriteDataProblem":{"type":"object","properties":{"path":{"type":["string","null"],"description":"Place in the request the problem concerns, such as tables[1].rows[0].sample or series[0].columns.value. Null when it concerns the request as a whole, such as a table constraint violation."},"message":{"type":"string"}},"required":["path","message"],"title":"WriteDataProblem"},"WriteDataErrorResponse":{"type":"object","properties":{"errors":{"type":"array","items":{"$ref":"#/components/schemas/WriteDataProblem"},"description":"Problems with the request. Past 100, a final problem counts the ones left out."}},"required":["errors"],"title":"WriteDataErrorResponse"},"SendNotificationSchema":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":255},"body":{"type":"string","maxLength":2000,"default":""},"action_url":{"type":"string","pattern":"^(/([^/\\\\\\x00-\\x1f\\x7f][^\\x00-\\x1f\\x7f]*)?)?$","maxLength":1024,"default":"","description":"Platform path the notification opens, such as /jobs/<id>"},"dedupe_key":{"type":"string","minLength":1,"maxLength":200,"description":"Idempotency key; a repeat send with the same key is dropped"},"data":{"type":["object","null"],"additionalProperties":{"description":"Any type"},"description":"Structured context stored with the notification. The keys sender and api_key_id are reserved for sender attribution."}},"required":["title","dedupe_key"],"title":"SendNotificationSchema"},"SentNotificationSchemaStatus":{"type":"string","enum":["delivered","deduplicated","muted"],"title":"SentNotificationSchemaStatus"},"SentNotificationSchema":{"type":"object","properties":{"id":{"type":["string","null"],"format":"uuid","description":"Inbox row id; null when the send was deduplicated or muted"},"status":{"$ref":"#/components/schemas/SentNotificationSchemaStatus"}},"required":["status"],"title":"SentNotificationSchema"},"ToolsPredictRequestSchema":{"type":"object","properties":{"pixel_threshold":{"type":"number","format":"double","minimum":0,"exclusiveMaximum":1,"default":0.5,"description":"Segmentation models only. A pixel belongs to a predicted region when the model's probability for it exceeds this. Lower values find fainter regions and grow existing ones. Higher values keep only confident pixels. Probabilities are uncalibrated, so useful values depend on the model."},"min_region_pixels":{"type":"integer","minimum":1,"default":9,"description":"Segmentation models only. Drops predicted regions with fewer pixels than this. Pixels are counted on the hole-filled mask at the model's inference resolution."},"max_hole_pixels":{"type":["integer","null"],"minimum":0,"description":"Segmentation models only. Fills enclosed holes of up to this many pixels in each predicted mask before it is split into regions. Null fills every hole. 0 keeps all holes, so ring-shaped predictions stay rings."},"min_confidence":{"type":"number","format":"double","minimum":0,"maximum":1,"default":0,"description":"Segmentation models only. Drops predicted regions whose confidence, the mean probability of their pixels, is below this."},"ml_model_id":{"type":["string","null"],"format":"uuid"},"ml_model_name":{"type":["string","null"]},"data":{"type":"array","items":{"type":"object","additionalProperties":{"description":"Any type"}}}},"required":["data"],"description":"Predict request for the SDK/MCP tools surface.\n\nThe model is identified by ml_model_id or by ml_model_name (the name of a\nnon-archived model).","title":"ToolsPredictRequestSchema"},"PredictedAnnotationSchema":{"type":"object","properties":{"file_id":{"type":"string","format":"uuid"},"label":{"type":"string"},"mask":{"type":"string"},"width":{"type":"integer"},"height":{"type":"integer"},"foreground_fraction":{"type":"number","format":"double"},"confidence":{"type":"number","format":"double"}},"required":["file_id","label","mask","width","height","foreground_fraction","confidence"],"description":"A predicted mask shaped as an annotation payload, tied back to the\ninput row's image file. Nothing is persisted by predict: to store it,\npass it to POST /v1/images/{file_id}/annotations (the images annotate\ntool), with is_human_vetted=true when a human reviewed the prediction\nand omitted (false) for automated saves.","title":"PredictedAnnotationSchema"},"PredictResponseSchema":{"type":"object","properties":{"predictions":{"type":"array","items":{"description":"Any type"}},"probabilities":{"type":["array","null"],"items":{"type":"object","additionalProperties":{"description":"Any type"}}},"model_id":{"type":"string","format":"uuid"},"model_name":{"type":"string"},"annotations":{"type":["array","null"],"items":{"$ref":"#/components/schemas/PredictedAnnotationSchema"}}},"required":["predictions","model_id","model_name"],"title":"PredictResponseSchema"},"ToolsMLModelDetailSchema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":["string","null"]},"task_type":{"type":"string"},"target_column":{"type":["string","null"]},"feature_columns":{"type":["array","null"],"items":{"type":"string"}},"image_columns":{"type":["array","null"],"items":{"type":"string"}},"problem_type":{"type":["string","null"]},"currently_active":{"type":"boolean","default":false},"status":{"type":["string","null"]},"version_number":{"type":["integer","null"]},"dataset_id":{"type":["string","null"],"format":"uuid"},"quality_preset":{"type":["string","null"]},"error_message":{"type":["string","null"]},"training_started_at":{"type":["string","null"],"format":"date-time"},"training_completed_at":{"type":["string","null"],"format":"date-time"},"evaluation_metrics":{"type":["object","null"],"additionalProperties":{"description":"Any type"}}},"required":["id","name","task_type"],"description":"Called by API tools to carry information about models.\n\nThis is called by the SDK/MCP tools surface and provides everything about\na model, including columns, dataset_id, version number, and training\ntiming details.","title":"ToolsMLModelDetailSchema"},"MLModelTaskType":{"type":"string","enum":["tabular","multimodal","segmentation"],"title":"MLModelTaskType"},"QualityPreset":{"type":"string","enum":["best_quality","high_quality","good_quality","medium_quality"],"title":"QualityPreset"},"MLProblemType":{"type":"string","enum":["binary","multiclass","regression","semantic_segmentation"],"title":"MLProblemType"},"TrainMLModelSchema":{"type":"object","properties":{"description":{"type":["string","null"]},"task_type":{"oneOf":[{"$ref":"#/components/schemas/MLModelTaskType"},{"type":"null"}]},"target_column":{"type":"string"},"quality_preset":{"$ref":"#/components/schemas/QualityPreset","default":"high_quality"},"dataset_id":{"type":"string","format":"uuid"},"feature_columns":{"type":["array","null"],"items":{"type":"string"}},"image_columns":{"type":["array","null"],"items":{"type":"string"}},"problem_type":{"oneOf":[{"$ref":"#/components/schemas/MLProblemType"},{"type":"null"}]},"ml_model_id":{"type":["string","null"],"format":"uuid"},"name":{"type":["string","null"]}},"required":["target_column","dataset_id"],"description":"Train a new model (name required) or retrain one (pass ml_model_id).\ndataset_id and target_column are always required in both modes.","title":"TrainMLModelSchema"}},"securitySchemes":{"ApiKeyAuth":{"type":"http","scheme":"bearer"}}}}